ASP.NET MVC,HttpContext.Current 在模拟请求时为空
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;
}
我使用 nunti 模拟一个请求。
然后我将 SessionStateItemCollection 添加到 Controller 的 ControllerContext 中。
我发现 HttpContext.Current 是 null 但 Controller 的 Session[]
不为 null,因为它来自 Controller 的 ControllerContext。
那么我应该怎么做才能在模拟请求时避免 HttpContext.Current 为空
您可以模拟 HttpContext:
public static HttpContext FakeHttpContext(HttpRequest request)
{
var stringWriter = new StringWriter();
var httpResponce = new HttpResponse(stringWriter);
var httpContext = new HttpContext(request, httpResponce);
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);
}
编辑(回答您评论中的问题):
为了获得会话,您需要调用 HttpContext.Current.Session
而不是 HttpContext.Current.Session["id"]
,因为 HttpContext.Current.Session["id"]
试图从您的会话中获取 id
密钥。
一旦将它存储在那里,就可以通过此调用使用它。你可以测试一下:
HttpContext.Current.Session["id"] = 5;
Assert.AreEqual(HttpContext.Current.Session["id"],5);
关于 httpContext.Items
声明:
(来自 MSDN)HttpContext.Items
是一个 key/value 集合,可用于在 HTTP 期间在 IHttpModule
接口和 IHttpHandler
接口之间组织和共享数据要求。
您要求的语句只是通过使用反射(因为它只有内部构造函数)创建一个新的 HttpSessionState
对象,将其与您之前创建的 HttpSessionStateContainer
相关联并存储它在 AspSession
下的 HttpContext.Items
中。有趣的是 HttpContext.Current.Session
实际上是 HttpContext.Items["AspSession"]
的捷径。因此,将 HttpSessionState 对象分配给 AspSession
键是使 HttpContext.Current.Session
起作用的前提。
好吧,在像 Alex Art 所说的那样模拟 HttpContext 之后。
调用下面的方法就可以了
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
));
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;
}
我使用 nunti 模拟一个请求。 然后我将 SessionStateItemCollection 添加到 Controller 的 ControllerContext 中。 我发现 HttpContext.Current 是 null 但 Controller 的 Session[] 不为 null,因为它来自 Controller 的 ControllerContext。 那么我应该怎么做才能在模拟请求时避免 HttpContext.Current 为空
您可以模拟 HttpContext:
public static HttpContext FakeHttpContext(HttpRequest request)
{
var stringWriter = new StringWriter();
var httpResponce = new HttpResponse(stringWriter);
var httpContext = new HttpContext(request, httpResponce);
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);
}
编辑(回答您评论中的问题):
为了获得会话,您需要调用 HttpContext.Current.Session
而不是 HttpContext.Current.Session["id"]
,因为 HttpContext.Current.Session["id"]
试图从您的会话中获取 id
密钥。
一旦将它存储在那里,就可以通过此调用使用它。你可以测试一下:
HttpContext.Current.Session["id"] = 5;
Assert.AreEqual(HttpContext.Current.Session["id"],5);
关于 httpContext.Items
声明:
(来自 MSDN)HttpContext.Items
是一个 key/value 集合,可用于在 HTTP 期间在 IHttpModule
接口和 IHttpHandler
接口之间组织和共享数据要求。
您要求的语句只是通过使用反射(因为它只有内部构造函数)创建一个新的 HttpSessionState
对象,将其与您之前创建的 HttpSessionStateContainer
相关联并存储它在 AspSession
下的 HttpContext.Items
中。有趣的是 HttpContext.Current.Session
实际上是 HttpContext.Items["AspSession"]
的捷径。因此,将 HttpSessionState 对象分配给 AspSession
键是使 HttpContext.Current.Session
起作用的前提。
好吧,在像 Alex Art 所说的那样模拟 HttpContext 之后。
调用下面的方法就可以了
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
));