簡體   English   中英

如何將屬性注入到我無法控制其創建的類中

[英]How to inject a property into a class that I don't control the creation of

如何使用autofac將IServiceManager屬性注入此類? 這是一個自定義資源提供程序工廠類,當您調用HttpContext.GetGlobalResourceObject("", "MyResource")以獲取資源字符串時,將調用該類。

public class SqlResourceProviderFactory : ResourceProviderFactory
{
    // needs autofac property injection
    public IServiceManager ServiceManager { get; set; }

    public override IResourceProvider CreateGlobalResourceProvider(string classKey)
    {
        ...
    }

    public override IResourceProvider CreateLocalResourceProvider(string virtualPath)
    {
        ...
    }

    public static string GetAppRelativePath(string logicalPath)
    {
        ...
    }
}

我曾經遇到過與ASP.NET ResourceProviderFactory完全相同的問題,不幸的是,答案是必須使用service location

您可以在其中注入任何內容或更改內置ASP.NET行為的任何地方都沒有“鈎子”進入管道。 因此,如果需要將某些內容放入屬性,則必須在構造函數中進行設置。

public class SqlResourceProviderFactory : ResourceProviderFactory
{
  public IServiceManager ServiceManager { get; set; }

  public SqlResourceProviderFactory()
  {
    this.ServiceManager =
      DependencyResolver.Current.GetService<IServiceManager>();
  }
}

是的,這真的很丑。

在此要考慮的非常重要的事情,尤其是對於Autofac而言,是IServiceManager注冊的生存期范圍。

ResourceProviderFactory僅創建一次並緩存。 與Create *方法中的全局/本地資源提供程序相同。 我們花了很長時間,因為這意味着在創建工廠時不一定有HttpContext ,即使存在,如果下游依賴項已注冊InstancePerHttpRequest它們也會被處理掉,而您重新軟管。

  • 您的ResourceProviderFactory或生成的資源提供者使用的所有內容(從堆棧一直到堆棧)都應注冊SingleInstanceInstancePerDependency
  • 如果可能,不要直接使用DependencyResolver.Current (對於Autofac,它需要一個活動的HttpContext ),請直接引用該應用程序容器。 這意味着您需要將對它的引用存儲在其他地方(全局靜態變量?)並使用它。

這是更完整的解決方案可能涉及的內容:

// Create some "holder" for the app container.
public static class ApplicationContainerProvider
{
  public static ILifetimeScope Container { get; set; }
}


// In Global.asax, build your container and set it in both
// the DependencyResolver AND in the holder class.
var builder = new ContainerBuilder();
builder.RegisterType<Something>().As<ISomething>();
var container = builder.Build();
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
ApplicationContainerProvider.Container = container;


// In your service location, reference the container instead of
// DependencyResolver.
public class SqlResourceProviderFactory : ResourceProviderFactory
{
  public IServiceManager ServiceManager { get; set; }

  public SqlResourceProviderFactory()
  {
    this.ServiceManager =
      ApplicationContainerProvider.Container.Resolve<IServiceManager>();
  }
}

請注意,由於您要從根容器中解決該問題,因此它將在應用程序的整個生命周期內始終存在。 即使您將其注冊為InstancePerDependency ,由於.NET進行了內部緩存,它也只會被創建一次。

如果您不喜歡這樣創建自己的靜態持有Autofac.Extras.CommonServiceLocator ,則可以使用Autofac.Extras.CommonServiceLocatorAutofac.Extras.CommonServiceLocatorCommonServiceLocatorAutofac.Extras.CommonServiceLocator

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM