【问题标题】:Dependency Injection on Custom ActionFilter with Unity.MVC使用 Unity.MVC 对自定义 ActionFilter 进行依赖注入
【发布时间】:2016-09-02 00:57:57
【问题描述】:

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

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,是一个 接口,无法构造。您是否缺少类型映射?

【问题讨论】:

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


    【解决方案1】:

    问题在于 MVC 没有使用您在 UnityConfig.cs 中的 RegisterTypes 方法中设置的容器。在 UnityConfig.csRegisterTypes 的末尾,您将 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中设置一次。

    【讨论】:

    • 谢谢。对于回复,但它会引发空引用。 “对象引用未设置为对象的实例。”从此方法调用 PageCount.cs 上的 _visitorService.AddVisitorCount();
    • 空引用异常意味着您的依赖关系现在正在正确解决。你能调试一下看看什么是空的吗? _visitorService 是否为空? AddVisitorCount() 方法中的 _visitorRepository 是否为空?还是 _visitorRepositoryAddVisitorCount() 方法内返回一个空的 Visitor
    • @Correy Smith 嗨,我在 VisitorService.cs 中添加了断点,构造函数和其他东西运行良好,直到步骤达到 public IVisitorService _visitorService { get ;放; }_visitorService 字段为空。
    • @markoverflow 我已经设置了一个存储库on GitHub here 来反映您的代码。你能把它和你的代码库比较一下,看看有什么不同吗?根据您提供的信息,您不应再获得空引用。
    • 谢谢。我比较了 git 中的代码,问题是我在 RegisterGlobalFilters 中使用了这个代码 filters.Add(new PageCount());。它返回 null 的原因是如果我不在我将使用的控制器中使用 [PageCount]。就像我的程序不需要在登录页面控制器上有 [PageCount] ,这是我的默认页面,所以它会抛出 null,但如果我添加 [PageCount] 它将起作用。所以我只需删除 filters.Add(new PageCount()); 就可以了。非常感谢。
    【解决方案2】:

    您是否考虑过将您的属性拆分为本文中讨论的“被动”属性?

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-01-02
      • 1970-01-01
      • 2014-08-11
      • 1970-01-01
      • 1970-01-01
      • 2012-01-24
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      相关资源
      最近更新 更多