Search code examples
c#autofachttpmoduleconstructor-injectiondependency-resolver

Is Injecting HttpContext by using constructor injection into HttpModule wrong?


I have a custom HttpModule where i trace http requests , part of the implementation is as below ;

    private readonly HttpContextBase _httpContext;
    private readonly ISessionContext _sessionContext;

    public ASHttpModule(HttpContextBase httpContext,
        ISessionContext sessionContext)
    {
        this._httpContext = httpContext;
        this._sessionContext = sessionContext;
    }
    public void Init(HttpApplication context)
    {
        context.BeginRequest += Context_BeginRequest;
        context.EndRequest += Context_EndRequest;
    }
    private void Context_BeginRequest(object sender, EventArgs e)
    {
       Stopwatch stopwatch = new Stopwatch();
       _httpContext.Items["Stopwatch"] = stopwatch;
       stopwatch.Start();
    }
    private void Context_EndRequest(object sender, EventArgs e)
    {
            Stopwatch stopwatch = (Stopwatch)_httpContext.Items["Stopwatch"];
            if (stopwatch == null)
                return;

            stopwatch.Stop();
            TimeSpan ts = stopwatch.Elapsed;
            //Check current httprequest variables and log if have to

    }

Here my dependency registration (using Autofac) ;

        builder.RegisterType<WebSessionContext>()
            .As<ISessionContext>().InstancePerRequest();
        builder.Register(c => (new HttpContextWrapper(HttpContext.Current) as HttpContextBase))
            .As<HttpContextBase>()
            .InstancePerRequest();
        builder.Register(c => c.Resolve<HttpContextBase>().Request)
            .As<HttpRequestBase>()
            .InstancePerRequest();
        builder.Register(c => c.Resolve<HttpContextBase>().Server)
            .As<HttpServerUtilityBase>()
            .InstancePerRequest();
        builder.Register(c => c.Resolve<HttpContextBase>().Session)
            .As<HttpSessionStateBase>()
            .InstancePerRequest();

Problem here is HttpModule is constructed only once while HttpContext needs to be injected for each request. The solution i've found is using DependencyResolver as ;

      HttpContextBase _httpContext = DependencyResolver.Current.GetService<HttpContextBase>();

However, i want to avoid this usage since ServiceLocator is considered as anti-pattern.

Is there any solution to inject HttpContext into HttpModule without using DependencyResolver?


Solution

  • You can try to use a factory to get the correct HttpContext instance:

    private readonly Func<HttpContextBase> _httpContextFactory;
    private readonly ISessionContext _sessionContext;
    
    public ASHttpModule(Func<HttpContextBase> httpContextFactory,
        ISessionContext sessionContext)
    {
        this._httpContextFactory = httpContextFactory;
        this._sessionContext = sessionContext;
    }
    private void Context_BeginRequest(object sender, EventArgs e)
    {
       var httpContext = this._httpContextFactory();
       Stopwatch stopwatch = new Stopwatch();
       httpContext.Items["Stopwatch"] = stopwatch;
       stopwatch.Start();
    }
    

    I assume Autofac can inject Func`1 instances too. If not, you might have to create a simple class which acts as a factory for your HttpContext.

    Then you can inject:

    • Normal operation → () => HttpContextWrapper(HttpContext.Current)
    • When testing/mocking → () => new HttpContextMock()