【问题标题】:How to use Ninject to inject services into MVC 3 FilterAttributes?如何使用 Ninject 将服务注入 MVC 3 FilterAttributes?
【发布时间】:2011-12-01 14:12:33
【问题描述】:

我正在为我的 MVC 项目编写自定义 ErrorHandler 属性。我想将 EventViewerLogger 的实现注入该属性。

我使用的是 Ninject 2.2,它适用于其他功能,例如注入存储库和通过控制器构造函数聚合服务。

我知道我不能通过构造函数将某个类的实现注入到属性中,因此我必须将它注入到属性的属性中。

界面如下:

namespace Foo.WebUI.Infrastructure
{
    public interface ILogger
    {        
        void Log(Exception e);
    }
}

事件查看器记录器实现

namespace Foo.WebUI.Infrastructure
{
    /// <summary>
    /// Logs exceptions into the Windows Event Viewer
    /// </summary>
    public class EventViewerLogger: ILogger
    {
        private EventViewerLogger _logger = null;        

        EventViewerLogger() 
        {
            _logger = new EventViewerLogger();
        }

        public void Log(Exception e)
        {
            _logger.Log(e);
        }
    }
}

以下是错误处理程序的代码:

namespace Foo.WebUI.Handlers
{
    /// <summary>
    /// Custom error handler with an interface to log exceptions
    /// </summary>
    public class CustomHandleErrorAttribute: HandleErrorAttribute
    {   
        [Inject]
        public ILogger Logger { get; set; }        

        // Default constructor
        public CustomHandleErrorAttribute():base() { }        

        public override void OnException(ExceptionContext filterContext)
        {           
            Logger.Log(filterContext.Exception);                        
            base.OnException(filterContext);
        }       
    }
}

在 global.asax 中,我注册了处理程序和 Ninject。

protected void Application_Start()
{
   IKernel kernel = new StandardKernel(new NinjectInfrastructureModule());
}

最后,我有一个自定义过滤器提供程序

namespace Foo.WebUI.Infrastructure
{
    public class NinjectFilterProvider: FilterAttributeFilterProvider
    {
        private readonly IKernel kernel;

        public NinjectFilterProvider(IKernel kernel)
        {
            this.kernel = kernel;
        }

        public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {            
            var filters = base.GetFilters(controllerContext, actionDescriptor);



            // Iterate through all the filters and use Ninject kernel to serve concrete implementations
            foreach (var filter in filters)
            {       
                kernel.Inject(filter.Instance);
            }

            return filters;
        }        
    }
}

当我启动应用程序时,出现以下异常:

激活路径: 2) 将依赖 ILogger 注入 CustomHandleErrorAttribute 类型的属性 Logger 1) 请求 CustomHandleErrorAttribute

建议: 1) 确保实现类型具有公共构造函数。 2) 如果你已经实现了 Singleton 模式,请改用 InSingletonScope() 的绑定。

Source Error: 


Line 27:             foreach (var filter in filters)
Line 28:             {       
Line 29:                 kernel.Inject(filter.Instance);
Line 30:             }

花了一天的时间,学到了很多关于依赖注入的知识,这很棒,但是我在这里做错了什么?

【问题讨论】:

    标签: asp.net-mvc-3 dependency-injection ninject


    【解决方案1】:

    Ninject.Web.Mvc 具有内置的称为“BindFilter”的功能,它允许您将属性(接受一些或不接受构造函数参数)映射到过滤器(其构造函数参数被注入)。此外,如果需要,您可以使用它从属性复制值并将它们作为构造函数参数注入过滤器。它还允许您将过滤器的范围更改为每个操作或每个控制器等,以便它们实际重新实例化(正常操作过滤器不会根据请求重新实例化)。

    这是一个 example 我如何使用它来执行 UoW 操作过滤器。

    【讨论】:

    • 您好,感谢您的回复。我所写的应该(理论上)有效,因为我在网上遵循了类似的教程/wiki 材料。理想情况下,我不想为项目引入另一个依赖项并使事情过于复杂:(目前,当我进行绑定时,我有一个选项 Bind().To().InRequestScope(); 应该希望在每个请求上重新实例化记录器。
    • 所以你没有使用 Ninject.Web.Mvc?您还实现了控制器工厂和 DI 出现的所有其他各个部分?当那里有一个编写良好、使用广泛且经过单元测试的库时,这似乎是很多不必要的工作......
    • 它还会阻止您在过滤器代码中包含[Inject],从而将您与ninject 耦合,而不是相反。
    • 我没有实现控制器工厂,我必须实现 IDependencyResolver 接口,它有两种获取具体实现的方法。但是,这不适用于属性。我将不得不使用 Ninject.Web.MVC,但我仍然希望找到我的问题的修复/解决方案,因为大多数代码已经到位。抱歉,我不完全理解您关于与 Ninject 分离的评论。谢谢你:)
    • 你好,布鲁克。我确实查看了 Ninject.Web.MVC - 我认为它很棒,我应该早点查看它。我发现他们的一些文档非常简短,所以这会让我在周末忙碌。谢谢你的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    相关资源
    最近更新 更多