Как использовать Ninject для внедрения сервисов в MVC 3 FilterAttributes? - PullRequest
4 голосов
/ 05 октября 2011

Я пишу собственный атрибут ErrorHandler для моего проекта MVC. Я хотел бы внедрить реализацию 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 в свойство Logger типа CustomHandleErrorAttribute 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:             }

Потратил день на это, узнал много нового о внедрении зависимости, и это здорово, но что я тут делаю не так?

1 Ответ

3 голосов
/ 05 октября 2011

Ninject.Web.Mvc имеет эту встроенную функциональность, называемую "BindFilter", которая позволяет сопоставить атрибут (который принимает несколько аргументов конструктора или нет) с фильтром (в который вставлены аргументы конструктора). Кроме того, вы можете использовать его для копирования значений из атрибута и добавления их в качестве аргументов конструктора в фильтр, если хотите. Он также позволяет вам изменять область действия ваших фильтров для каждого действия или для каждого контроллера и т. Д., Чтобы они фактически были повторно созданы (фильтры обычного действия не создаются для каждого запроса).

Вот пример того, как я использовал его для создания фильтра действий UoW.

...