Home > Enterprise >  How to get instance of class in Application_BeginRequest?
How to get instance of class in Application_BeginRequest?

Time:08-30

I just started using Castle.Windsor for a couple of reasons, one of which is to get away from using both static classes and the singleton pattern.

I'm not new to the general concepts of DI, but am a little new to implementation details. The one I'm dealing with now: how do I get the instance of my class that I registered from within the Application_BeginRequest() method in the Global.asax file? I obviously can't add parameters to this method, and I setup the container in the Application_Start() method of this class so it's not like I can create a constructor to inject it.

Is this an edge case where I would have to use the Service Locator pattern or what is the proper way to do this?

CodePudding user response:

Application_BeginRequest is a legacy ASP.NET classic method that runs outside of the context of MVC. The only way to provide an instance there is to keep an instance of the container around after the Application_Start method runs.

However, MVC has better alternatives. If you have a crosscutting concern that you need to run in each request, you should make a global filter to run that logic.

public class MyFilter : IActionFilter
{
    private readonly ISomeDependency someDependency;

    public MyFilter(ISomeDependency someDependency)
    {
        this.someDependency = someDependency 
            ?? throw new ArgumentNullException(nameof(someDependency));
    }

    // Runs after action method
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
    }

    // Runs before action method
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        someDependency.DoSomething();
    }
}

Usage

If you can get away with registering the filter as a singleton, you just need to register it at application startup in the static GlobalFilterCollection.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters, IWindsorContainer container)
    {
        filters.Add(new MyFilter(container.Resolve<ISomeDependency>()));
        filters.Add(new HandleErrorAttribute());
    }
}

If you have dependencies that would be captive (such as DbContext) if you registered as singleton, you can either inject a factory into your filter, or use a custom filter provider to resolve your global filter from the Castle Windsor container.

You can read more details about filter providers here.

NOTE: This is really just the tip of the iceberg. You could control which actions your filter will run on by making a custom attribute to decorate your actions with and using Reflection to scan for it in your filter (see this example). While MVC sort of does this with its ActionFilterAttribute extension, it is not DI-friendly to use it. Instead, make DI-friendly filters and make the attributes passive.

CodePudding user response:

Usually you initialize the container in Application_Start(). Just make a static variable with reference of the initialized container and use it in Application_BeginRequest().

  • Related