属性 通过 Unity 将对象注入 Startup 变为空

Property injection of object via Unity into Startup turns null

注意:我最初将此页面命名为“方法 通过 Unity 将对象注入 Startup 变为空”;所有其他对 方法 注入的引用应阅读为 属性 注入。

我在 Asp.Net MVC5 项目中使用 unity,我最初是通过 Unity.Mvc5 nuget 包安装的。因为我已经将 AspNet Identity 的东西移到了它自己的项目中,所以我努力让它的自定义 ApplicationUserManager 访问 DataProtectionProvider,这可以通过 Startup.ConfigureAuth(IAppBuilder app) 中的 MVC 应用程序通过 app.GetDataProtectionProvider() 获得。 (如果 Identity 的东西还在 web 项目中,我会按照 trailmax 的建议去做:http://tech.trailmax.info/2014/09/aspnet-identity-and-ioc-container-registration/

我定义了一个 DataProtectionProviderFactory class,像这样:

public class DataProtectionProviderFactory : MVC5.Web.Identity.IDataProtectionProviderFactory
{

    private IDataProtectionProvider _dp;
    public void SetProvider(IDataProtectionProvider dp)
    {
        _dp = dp;
    }

    public IDataProtectionProvider GetProvider()
    {
        return _dp;
    }
}

然后设置 Startup class 和 ApplicationUserManager class,以便通过 Unity 进行方法注入。在身份项目中,我有:

public class ApplicationUserManager : UserManager<IdentityUser, Guid>
{

    public IDataProtectionProviderFactory DataProtectionProviderFactory { get; set; }
.
.
}

在 Web 项目中,我有

public partial class Startup
{
    public IDataProtectionProviderFactory DataProtectionProviderFactory { get; set; }

    public void ConfigureAuth(IAppBuilder app )
    { 
        DataProtectionProviderFactory.SetProvider(app.GetDataProtectionProvider());
    }

}

我的 UnityConfig.cs 文件是(基本上):

public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager(), new InjectionConstructor("Mvc5"));


        container.RegisterType<IDataProtectionProviderFactory, DataProtectionProviderFactory>();
        container.RegisterType<UserManager<IdentityUser, Guid>, ApplicationUserManager>(new HierarchicalLifetimeManager(),
            new InjectionProperty("DataProtectionProviderFactory"));
        container.RegisterType<Startup>(new HierarchicalLifetimeManager(),
            new InjectionProperty("DataProtectionProviderFactory"));

        container.RegisterType<IUserStore<IdentityUser, Guid>, UserStore>(new HierarchicalLifetimeManager());
        container.RegisterType<CustomSigninManager>(new HierarchicalLifetimeManager());                     


        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        // Startup.DataProtectionProviderFactory is non-null, after resolving in the following line
        var start = container.Resolve<Startup>();

        container.RegisterType<IAuthenticationManager>(
            new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));      

    }
}

如果我在RegisterComponents()中打断就行了:

        var start = container.Resolve<Startup>();

然后我可以看到 Startup.DataProtectionProviderFactory 是非空的。

然而,当随后Startup.ConfigureAuth(IAppBuilder app) 执行时,它的Startup.DataProtectionProviderFactory 为空。

更新

按照 mnwsmit 的建议进行初始更改后,我向 UnityConfig.RegisterComponents() 调用添加了一个参数 "new Startup()",结果如下:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        UnityConfig.RegisterComponents(new Startup());
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;      
    }

}

调用 ConfigureAuthStartup class 实例是由 OWIN 而不是 Unity 创建的。因此,在您的设置中,您最终会得到 Startup class 的两个实例,一个是依赖注入的,另一个不是。没有办法让 Unity 注入对 OWIN(您真正的启动)创建的实例的依赖。您应该对规则做一个例外,并使用容器作为服务定位器来获取 DataProtectionProviderFactory 实例,并确保 Startup class 获取并使用该实例。例如如下:

public static void RegisterComponents(Startup startup)
{
    var container = new UnityContainer();

    // registration

    startup.DataProtectionProviderFactory = container.Resolve<IDataProtectionProviderFactory>();
}