使用Unity.MVC对自定义ActionFilter进行依赖注入

时间:2016-09-01 12:57:08

标签: c# asp.net-mvc dependency-injection unity-container

我遇到自定义操作过滤器和依赖项注入问题。这是我的代码:

PageCount.cs

public class PageCount : ActionFilterAttribute
{
    [Dependency]
    public IVisitorService _visitorService { get; set; }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        _visitorService.AddVisitorCount();
        base.OnResultExecuted(filterContext);
    }
}

IVisitorService.cs

public partial interface IVisitorService
{
    int GetVisitorsCount();
    void AddVisitorCount();
}

VisitorService.cs

public partial class VisitorService : IVisitorService
{
    private readonly IRepository<Visitor> _visitorRepository;

    public VisitorService(IRepository<Visitor> visitorRepository)
    {
        _visitorRepository = visitorRepository;
    }

    public int GetVisitorsCount()
    {
        Visitor v = _visitorRepository.Get(1);

        return v.VisitCount;
    }

    public void AddVisitorCount()
    {
        Visitor v = _visitorRepository.Get(1);
        v.VisitCount += 1;
        _visitorRepository.Update(v);
    }
}

UnityConfig.cs

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

    // identity
    container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());
    container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
    container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new InjectionConstructor(new ApplicationDbContext()));
    container.RegisterType<AccountController>(new InjectionConstructor());
        container.RegisterType<IAuthenticationManager>(new InjectionFactory( o => HttpContext.Current.GetOwinContext().Authentication));

    container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
    container.RegisterType<IGameService, GameService>();
    container.RegisterType<IGenreService, GenreService>();
    container.RegisterType<IVisitorService, VisitorService>();

    DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}

UnityMvcActivator.cs

public static void Start() 
{
    var container = UnityConfig.GetConfiguredContainer();

    FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
    FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));

    DependencyResolver.SetResolver(new UnityDependencyResolver(container));

    // TODO: Uncomment if you want to use PerRequestLifetimeManager
    // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}


错误

  

目前的类型,   GameCommerce.Infrastructure.Services.Visitors.IVisitorService,是一个   界面,不能构造。你错过了类型映射吗?

2 个答案:

答案 0 :(得分:3)

问题是MVC没有使用您在 UnityConfig.cs 中的RegisterTypes方法中设置的容器。在 UnityConfig.cs RegisterTypes末尾,您将DependencyResolver.Current设置为您在方法中创建的容器,但稍后在 UnityMvcActivator中.cs DependencyResolver.CurrentUnityConfig.GetConfiguredContainer()覆盖,但不包含您的注册。

我建议您使用Unity.Mvc包提供的 UnityConfig.cs 类,而不修改RegisterTypes方法,如下所示:

<强> UnityConfig.cs

public class UnityConfig
{
    #region Unity Container
    private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    /// <summary>
    /// Gets the configured Unity container.
    /// </summary>
    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }
    #endregion

    /// <summary>Registers the type mappings with the Unity container.</summary>
    /// <param name="container">The unity container to configure.</param>
    /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
    /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
    public static void RegisterTypes(IUnityContainer container)
    {
        // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
        // container.LoadConfiguration();

        // TODO: Register your types here
        container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());
        container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
        container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new InjectionConstructor(new ApplicationDbContext()));
        container.RegisterType<AccountController>(new InjectionConstructor());
        container.RegisterType<IAuthenticationManager>(new InjectionFactory( o => HttpContext.Current.GetOwinContext().Authentication));

        container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
        container.RegisterType<IGameService, GameService>();
        container.RegisterType<IGenreService, GenreService>();
        container.RegisterType<IVisitorService, VisitorService>();
    }

这种方式DependencyResolver.Current只会在 UnityMvcActivator.cs 中设置一次。

答案 1 :(得分:1)

您是否考虑过将属性划分为&#34;被动&#34;属性如本文所述?

http://blog.ploeh.dk/2014/06/13/passive-attributes/

从您的实现开始,您正在使用属性注入,因为构造函数注入不可用,因为您只能将常量和文字传递给属性。但是你真的应该使用构造函数注入,因为你的依赖是必需的,而且在没有引用IVisitorService的情况下,win不会工作。 (属性注入通常表示可选的依赖项。)

如果您按照文章中的示例进行操作,则可以创建一个很好的关注点分离,并简化您在IoC框架中遇到的问题。