سؤال

How can I create an instance of HttContext and register it in StructureMap config?

I have an MVC3 web project using StructureMap with, I think, a typical setup where the controllers call repository class and the repo classes are responsible for business logic and database manipulation.

StructureMap is used to inject the controllers with the proper repositories.

But recently, I had a requirement for some repos to log certain actions along with the IP address of the user.

To get the IP address, I am using

requestContext.HttpContext.Request.UserHostAddress

Now, I thought it would be smart to pass the HttpContext into the repo classes and then register the HTTContext dependancy in StructureMap like this:

For<RequestContext>().Use(ctx => HttpContext.Current.Request.RequestContext);

That is working so far, but I also have a mini-project that will use the same repo functions but run as a console application (or maybe win service). The problem here is there is no HttpContext without the ASP.Net runtime. I get a runtime error saying that httpContext is null.

How can I get an HttpContext in there?

EDIT Suggested solution by Alexei and Plymouth

Thanks, if I understand Alexei's suggestion, I should make an interface like:

interface ILoggingConext
{
    public string IPAddress { get; set; }
}

And then have 2 concrete classes, one of which (A) accepts an HTTPContext and the other (B) can have a default value for IPAddress

Then in StructureMap, configure it so that it will use concrete class a if HttpContext is not null. Otherwise , it will use B.

Am I close?

SOLUTION

Taking Alexei's advice, here is the solution I am currently using:

First declare the Interface and 2 concrete classes

public interface ILoggingContext
{
    string IPAddress { get; set; }
    string HostAddress { get; set; }
}

public class HttpLoggingContext : ILoggingContext
{
    public string IPAddress { get; set; }
    public string HostAddress { get; set; }

    //This is the concrete class to use if context is available, so provide a constructor to accept a context and set properties appropriately
    public HttpLoggingContext(RequestContext rContext)
    {
        if (rContext != null && rContext.HttpContext != null && rContext.HttpContext.Request != null)
        {
            this.IPAddress = rContext.HttpContext.Request.UserHostAddress;
            this.HostAddress = rContext.HttpContext.Request.UserHostName;
        }
    }
}

//No http context, so just set the properties to something that signifies this, using "local" here
public class ConsoleLoggingContext : ILoggingContext
{
    public string IPAddress { get; set; }
    public string HostAddress { get; set; }


    public ConsoleLoggingContext()
    {
        this.IPAddress = "local";
        this.HostAddress = "local";
    }
}

Then here is the configuration in the StructureMap registry class:

        For<ILoggingContext>().ConditionallyUse(o =>
            {
                o.If(c => HttpContext.Current!=null && HttpContext.Current.Request!=null && HttpContext.Current.Request.RequestContext!=null).ThenIt.Is.ConstructedBy(a=> new HttpLoggingContext(HttpContext.Current.Request.RequestContext));
                o.TheDefault.IsThis(new ConsoleLoggingContext());

            }
        ).Named("ConditionalILoggingContext");

If the HttpContext.Current.Request.RequestContext is not null, we use the HttpLoggingContext. Otherwise we use the ConsoleLoggingContext.

I am marking this as the solution. Thanks for the help

هل كانت مفيدة؟

المحلول 2

The solution I ran with was what Alexei suggested. Use different wrappers to contain the required properties that I needed from the context object and use Structure map to decide which wrapper to use depending on the existence of the HttpContext. See original question for sample code under "Solution".

نصائح أخرى

To do as you suggest:

For<RequestContext>().Use(ctx =>
{
    //TODO: Create unittest.html as required.
    SimpleWorkerRequest request = new SimpleWorkerRequest("/unittest", @"c:\inetpub\wwwroot\unittest", "unittest.html", null, new StringWriter());
    HttpContext context = new HttpContext(request);
    return HttpContext.Current = context;
});

As was recommended though, abstracting the dependency upon the context would be a better long way to go.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top