How to fake an HttpContext and its HttpRequest to inject them in a service constructor

In a console application, I would like to use a service that would normally need the current http context to be passed to its constructor. I am using Ninject, and I think I can simply fake an http context and define the proper binding, but I have been struggling with this for a few hours without success.

The details:

The service is actually a mailing service that comes from an ASP.Net MVC project. I am also using Ninject for IoC. The mail service needs the current http context to be passed to its constructor. I do the binding as follows:

kernel.Bind<IMyEmailService>().To<MyEmailService>()
    .WithConstructorArgument("httpContext", ninjectContext => new HttpContextWrapper(HttpContext.Current));

However, I would like now to use this mailing service in a console application that will be used to run automated tasks at night. In order to do this, I think I can simply fake an http context, but I have been struggling for a few hours with this.

All the mailing service needs from the context are these two properties:

I thought I could do something like this, but:

Define my own fake request class:

public class AutomatedTaskHttpRequest : SimpleWorkerRequest
{
    public string UserHostAddress;
    public string RawUrl;

    public AutomatedTaskHttpRequest(string appVirtualDir, string appPhysicalDir, string page, string query, TextWriter output)
        : base(appVirtualDir, appPhysicalDir, page, query, output)
    {
        this.UserHostAddress = "127.0.0.1";
        this.RawUrl = null;
    }
}

Define my own context class:

public class AutomatedTasksHttpContext
{
    public AutomatedTaskHttpRequest Request;

    public AutomatedTasksHttpContext()
    {
        this.Request = new AutomatedTaskHttpRequest("", "", "", null, new StringWriter());
    }
}

and bind it as follows in my console application:

   kernel.Bind<IUpDirEmailService>().To<UpDirEmailService>()
        .WithConstructorArgument("httpContext", ninjectContext => new AutomatedTasksHttpContext());

Unfortunately, this is not working out. I tried various variants, but none was working. Please bear with me. All that IoC stuff is quite new to me.

Upvotes: 1

Views: 1220

Answers (1)

dove
dove

Reputation: 20692

I'd answered recently about using a HttpContextFactory for testing, which takes a different approach equally to a console application.

public static class HttpContextFactory
    {
        [ThreadStatic]
        private static HttpContextBase _serviceHttpContext;

        public static void SetHttpContext(HttpContextBase httpContextBase)
        {
            _serviceHttpContext = httpContextBase;
        }

        public static HttpContextBase GetHttpContext()
        {
            if (_serviceHttpContext!= null)
            {
                return _serviceHttpContext;
            }

            if (HttpContext.Current != null)
            {
                return new HttpContextWrapper(HttpContext.Current);
            }
            return null;
        }
    }

then in your code to this:

var rawUrl = HttpContextFactory.GetHttpContext().Request.RawUrl;

then in your tests use the property as a seam

HttpContextFactory.SetHttpContext(HttpMocks.HttpContext());

where HttpMocks has the following and would be adjusted for your tests:

public static HttpContextBase HttpContext()
      {
          var context = MockRepository.GenerateMock<HttpContextBase>();
          context.Stub(r => r.Request).Return(HttpRequest());
          // and stub out whatever else you need to, like session etc
          return context;
      }


      public static HttpRequestBase HttpRequest()
      {
          var httpRequest = MockRepository.GenerateMock<HttpRequestBase>();
          httpRequest.Stub(r => r.UserHostAddress).Return("127.0.0.1"); 
          httpRequest.Stub(r => r.RawUrl).Return(null); 
          return httpRequest;
      }

Upvotes: 3

Related Questions