在MVC中的线程中存储会话中的值
本文关键字:会话 存储 线程 MVC | 更新日期: 2023-09-27 18:26:20
我对MVC很陌生,所以如果我遗漏了什么,请原谅我。
在我的一个控制器中,我启动了一个类,该类进行一些处理并输出如下字符串:
[HttpPost]
public ActionResult Check(string reg)
{
string sCarmodel;
GetRegInfo gri = new GetRegInfo(reg, out sCarmodel);
Session["test"] = sCarmodel;
return View("Check");
}
到目前为止还不错,sCarmodel的输出正确地存储在Session中,稍后可以在View中访问它。但是,我需要把这个类放在一个单独的线程中,因为完成它需要一些时间,而且我想越来越多地返回View。所以我尝试了这个:
[HttpPost]
public ActionResult Check(string reg)
{
var getreginfoThread = new Thread(
() =>
{
string sCarmodel;
GetRegInfo gri = new GetRegInfo(reg, out sCarmodel);
Session["test"] = sCarmodel;
}
);
getreginfoThread.Start();
return View("Check");
}
我知道我可以从类本身将"sCarmodel"的值存储在数据库中,但我一直在寻找一种跳过使用数据库的方法。使用线程时,sCarmodel的值不会存储在Session中,稍后当我尝试检索它时,Session是null
有人能就如何在线程中访问Class中的值提供一些建议吗?
谢谢!
编辑:问题解决了,感谢大家的建议!
在处理请求期间将自定义对象放入Session。
将对此自定义对象的引用传递到后台线程。
在后台线程中设置自定义对象的属性。
确保进行任何必要的同步。
您需要以某种方式将会话传递给后台线程。例如,请参见此处。
顺便问一下,你为什么不使用任务并行库?
HttpContext会话对象的父/所有者对象不会传输到新线程,因此您的会话在主线程以外的线程中不可访问。
我建议您使用async/await从线程返回sCarmodel,并在主线程中将其设置为Session。
这并不是说该值没有存储在Session中。是的。问题是你的代码继续与你创建的线程并行执行,当它访问你必须以某种方式重新组织你的代码。此外,不建议在asp.net应用程序中启动线程,因为这非常耗费资源。Session["test"]
时,它还没有被你的线程分配
编辑
它似乎真的没有设置Session变量。如果你真的想这样做,你可以使用CallContext
:
CallContext.LogicalSetData("CurrentSession", Session);
var getreginfoThread = new Thread(
() =>
{
string sCarmodel;
GetRegInfo gri = new GetRegInfo(reg, out sCarmodel);
var session = (HttpSessionState)CallContext.LogicalGetData("CurrentSession");
session["test"] = sCarmodel;
}
);
getreginfoThread.Start();
return View("Check");
您必须以某种方式等待该数据不为空,然后使用Session["test"]
获取该数据
我建议您不要在线程中使用Session对象,因为它不是线程安全的。在ASP.NET中,每个请求都有自己的线程和会话。
你从未描述过真正的问题(不幸的是),所以我真的不知道你想解决什么,但手动启动一个新线程并将数据放入Session并不是一个解决方案。
如果你想异步地做一些事情,让web服务器在后台做一些事情的同时为其他客户端提供服务,那么也许可以看看异步控制器:http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
同样,了解你试图实现的目标,提出一个合适的解决方案,这将非常有用。
我通过在TempData中存储该类的实例解决了问题。此外,我使用Task而不是Thread,后者要好得多。这是我的解决方案:
[HttpPost]
public ActionResult GetRegInfo(string reg)
{
var gri = new GetRegInfo(reg);
TempData["GetRegInfo"] = gri;
Action<object> action = (object obj) => gri.Start();
var t1 = new Task(action, "GetRegInfo");
t1.Start();
return View("bilforsakring");
}
稍后,我在Ajax中使用JavaScript计时器,并获得如下值:
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult GetRegInfoAjax()
{
if (TempData["GetRegInfo"] != null)
{
var g = (GetRegInfo)TempData["GetRegInfo"];
return Content(g.sCarmodel);
}
else
{
return Content("null");
}
}
但是,我需要把这个类放在一个单独的线程中,因为完成它需要一些时间,而且我想越来越多地返回View。
错了。这是解决这个问题的完全错误的方法。在ASP.NET应用程序中,当有更多的工作要做时,您永远不应该返回,除非您已经将这些工作保存到永久存储中。
将工作保存在内存中(即使用线程或任务)是不正确的解决方案。
正确的解决方案是使用持久存储(例如,Azure队列、MSMQ或WebSphere MQ)来存储要完成的工作,然后有一个单独的服务来读取该队列,采取适当的操作,并将结果存储在另一个持久数据结构中。然后,您可以让客户端轮询(例如HTTP请求)"结果"数据结构和/或在保存结果时通知客户端(例如SignalR)。
我在我的博客上详细介绍了更多细节,如果你确信要走不安全的路线,我也有一些示例代码可以在那里使用。