How to use Ninject to implement services in MVC 3 FilterAttributes?

I am writing my own ErrorHandler attribute for my MVC project. I would like to add an implementation of EventViewerLogger to this attribute.

I use Ninject 2.2, and it works great for other functions, such as repository repositories and aggregated services through controller constructors.

I understand that I cannot embed an implementation of any class in an attribute through a constructor, so I have to enter it in the attribute property.

The interface is below:

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

Implementing Event Viewer Log

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

Below is the code for the error handler:

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

In global.asax I register the handler and Ninject.

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

Finally, I have a custom filter provider

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

When I run the application, I get the following exception:

Activation path: 2) Injection of the ILogger dependency into the Logger property of type CustomHandleErrorAttribute 1) Request for CustomHandleErrorAttribute

Suggestions: 1) Make sure that the implementation type has an open constructor. 2) If you have implemented the Singleton template, use the binding with InSingletonScope ().

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

Spent a day on this, learned a lot about dependecy injections, which is great, but what am I doing wrong here?

+4
source share
1 answer

Ninject.Web.Mvc has this functionality, built under the name "BindFilter", which allows you to map an attribute (which takes some or no design arguments) to a filter (which has a nested args constructor). Alternatively, you can use it to copy values ​​from an attribute and inject them as the args constructor for the filter, if you want. It also allows you to change the scope of your filters to each action or to the controller, etc., so that they actually receive a re-creation of the instance (normal action filters cannot be re-created for each request).

Here is an example of how I used it to create a UoW action filter.

+3
source

Source: https://habr.com/ru/post/899042/


All Articles