Unity.MVC 对自定义 ActionFilter 的依赖注入

Dependency Injection on Custom ActionFilter with Unity.MVC

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

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));
}


错误

The current type, GameCommerce.Infrastructure.Services.Visitors.IVisitorService, is an interface and cannot be constructed. Are you missing a type mapping?

您是否考虑过将您的属性拆分为本文中讨论的 "passive" 属性?

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

从您的实现来看,您正在使用 属性 注入,因为构造函数注入不可用,因为您只能将常量和文字传递给属性。但是您确实应该使用构造函数注入,因为您的依赖项是必需的,并且如果不引用 IVisitorService 将无法工作。 (属性 注入通常表示可选依赖项。)

如果您遵循本文中的示例,您将创建一个很好的关注点分离并缓解您在使用 IoC 框架时遇到的问题。

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

我建议您使用 Unity.Mvc 包中提供的 UnityConfig.cs class,而不要修改 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.