Zeurso
Zeurso

Reputation: 75

ASP.NET MVC, HttpContext.Current is null while mocking a request

public async Task <ActionResult>Select(DWorkingTimeSelection dto) { 
    var session = HttpUtils.GetSeesion<User>("USER"); 
} 

public static T GetSeesion<T>(string key) where T : class
{ 
    if (HttpContext.Current == null) 
    { 
        return default(T);
    }
     return HttpContext.Current.Session[key] as T; 
}

public async Task <ActionResult>Select(DWorkingTimeSelection dto) { 
    var session = HttpUtils.GetSeesion<User>("USER"); 
} 

public static T GetSeesion<T>(string key) where T : class
{ 
    if (HttpContext.Current == null) 
    { 
        return default(T);
    } 
    return HttpContext.Current.Session[key] as T; 
}

I use nunti to mock a request. And I add the SessionStateItemCollection to the Controller 's ControllerContext . I found that the HttpContext.Current is null but the Controller 's Session[] is not null because it get from the Controller 's ControllerContext . So what should I do to avoid the HttpContext.Current is null while mocking a request

Upvotes: 1

Views: 1391

Answers (2)

Alex Art.
Alex Art.

Reputation: 8781

You can mock the HttpContext:

    public static HttpContext FakeHttpContext(HttpRequest request)
    {
        var stringWriter = new StringWriter();
        var httpResponse = new HttpResponse(stringWriter);
        var httpContext = new HttpContext(request, httpResponse);

        var sessionContainer = new HttpSessionStateContainer(
            "id", 
            new SessionStateItemCollection(), 
            new HttpStaticObjectsCollection(), 
            10, 
            true, 
            HttpCookieMode.AutoDetect, 
            SessionStateMode.InProc, 
            false);

        httpContext.Items["AspSession"] =
            typeof(HttpSessionState).GetConstructor(
                BindingFlags.NonPublic | BindingFlags.Instance, 
                null, 
                CallingConventions.Standard, 
                new[] { typeof(HttpSessionStateContainer) }, 
                null).Invoke(new object[] { sessionContainer });

        return httpContext;
    }

    [TestMethod]
    public void ActionTest()
    {
        var request = new HttpRequest(string.Empty, "url to the action that you are testing", string.Empty)
        {
            RequestType = "GET"
        };
        HttpContext.Current = FakeHttpContext(request);

        var controller = new YourController();
        //You need the get a Result property since it is an async action
        var result = controller.ActionToTest(//the parameters that your action expects).Result;
        Assert.IsNotNull(result);
    }

EDIT (answering the questions in your comment):

In order to get a session you need to call HttpContext.Current.Session and not the HttpContext.Current.Session["id"] because HttpContext.Current.Session["id"] tries to get an id key from your session. Once you store it there it will be available through this call. You can test it:

HttpContext.Current.Session["id"] = 5;
Assert.AreEqual(HttpContext.Current.Session["id"],5);

Regarding the httpContext.Items statement:

(From MSDN)HttpContext.Items is a key/value collection that can be used to organize and share data between an IHttpModule interface and an IHttpHandler interface during an HTTP request.

For the statement that you are asking for, simply create a new HttpSessionState object by using reflection (because it has only internal constructors) associates it with the HttpSessionStateContainer that you created earlier, and store it in HttpContext.Items under AspSession. And an interesting thing is that HttpContext.Current.Session actually is a shortcut to HttpContext.Items["AspSession"]. So the assignment of HttpSessionState object to the AspSession key is the one that makes HttpContext.Current.Session work.

Upvotes: 2

Zeurso
Zeurso

Reputation: 75

Well,after mocking the HttpContext as Alex Art said .

Calling the following method will be fine.

var sessionItems = new SessionStateItemCollection();
        sessionItems["SessionKey"] = new MyCustomObject();
        SessionStateUtility.AddHttpSessionStateToContext(fakeHttpContext,
            new HttpSessionStateContainer(SessionNameStorage.Suser,
                          sessionItems,
                          new HttpStaticObjectsCollection(),
                          20000,
                          true,
                          HttpCookieMode.AutoDetect,
                          SessionStateMode.InProc,
                          false
                      ));

Upvotes: 2

Related Questions