Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do dependency injection inside ASP.NET MVC's RegisterGlobalFilters method

I am still a bit new to using IOC containers and I'm struggling a bit. I am using ASP.NET MVC 5.2 with Ninject.MVC3. I have an exception filter that basically hands off to a log service:

public class ExceptionLoggerFilter : IExceptionFilter
{
    private readonly ILogService _logService;

    public ExceptionLoggerFilter(ILogService logService) {
        _logService = logService;
    }

    public void OnException(ExceptionContext filterContext) {
        _logService.LogError(filterContext.Exception);
    }
}

I would like to use dependency injection to get the instance of the log service. However, the RegisterGlobalFilters method is static:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new ExceptionLoggerFilter(???));
    }
}

I could use a static constructor for FilterConfig, but this just doesn't feel like a good solution.

I tried using property injection in the ExceptionLoggerFilter class, but it just didn't work (LogService was always null):

[Inject]
public ILogService LogService { get; set; }

I have read up on using the Factory pattern, but it doesn't seem to help here as I would still need to inject the Factory class into the static constructor of the FilterConfig class. I could be wrong, but this doesn't feel like the right solution either.

For now, I'm using a just-give-me-an-instance method:

var logService = (ILogService)DependencyResolver.Current.GetService(typeof(ILogService));
filters.Add(new ExceptionLoggerFilter(logService));

This works, but is it a good solution? Is there a better way? Is my thinking about dependency injection and IOC containers all messed up?

like image 497
TallGuy Avatar asked Oct 01 '16 22:10

TallGuy


People also ask

Can we use dependency injection in asp net?

ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.

Can we inject dependency in Viewcomponent?

A view component class: Supports constructor dependency injection. Doesn't take part in the controller lifecycle, therefore filters can't be used in a view component.

What is @inject in Cshtml?

Service injection A service can be injected into a view using the @inject directive. You can think of @inject as adding a property to the view, and populating the property using DI. CSHTML Copy.


1 Answers

MVC global filters are just a list of instances. This means that any dependencies such filter has, also become singletons. This means you should be very careful with this approach, because it is really easy to accidentally cause a Captive Dependency in your application. Captive Dependencies are often hard to track and often only popup in testing or production.

Instead, you should create a proxy class that can delegate back to your container/kernel at the time the filter is used, so it can resolve the real filter on the spot. This prevents Captive Dependencies.

Such proxy can look as follows:

public class NinjectExceptionFilterProxy<TExceptionFilter> : IExceptionFilter
    where TExceptionFilter : IExceptionFilter
{
    private readonly Kernel _kernel;

    public ExceptionLoggerFilter(Kernel kernel) {
        _kernel = kernel;
    }

    public void OnException(ExceptionContext filterContext) {
        var filter = _kernel.Get<TExceptionFilter>();
        filter.OnException(filterContext);
    }
}

You can register the proxy filter as follows:

public static void RegisterGlobalFilters(GlobalFilterCollection filters, IKernel kernel)
{
    filters.Add(new NinjectExceptionFilterProxy<ExceptionLoggerFilter>(kernel));
}
like image 139
Steven Avatar answered Sep 24 '22 07:09

Steven



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!