1

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?

naltun
  • 114
  • 1
  • 2
  • 12
  • The source of the problem here is that you inject [runtime data into your components](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99). – Steven Apr 05 '16 at 14:27
  • 1
    Thanks for the blog post. Helped me to see my mistake. Elegant solution. – naltun Apr 05 '16 at 17:08

1 Answers1

2

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()
knittl
  • 246,190
  • 53
  • 318
  • 364
  • Using factory is one of the solutions as Stevens blog post say. I think the solution steven offers sounded more reasonable and i will go with it. Thanks anyway. – naltun Apr 05 '16 at 17:13