我对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 aschyncronosly。所以我尝试了这个:
[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中,稍后当我尝试检索时,会话为null
。
有人可以提供一些关于如何在线程中从类中访问值的建议吗?
谢谢!
修改 问题解决了,谢谢大家的建议!
答案 0 :(得分:3)
在处理请求期间在会话中放置自定义对象。
将对此自定义对象的引用传递给后台线程。
在后台线程中设置自定义对象的属性。
确保您进行任何必要的同步。
答案 1 :(得分:1)
您需要以某种方式将会话传递给后台线程。例如,请参阅here。
顺便问一下,你为什么不使用Task Parallel Library?
答案 2 :(得分:0)
并不是该值未存储在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"]
答案 3 :(得分:0)
HttpContext会话对象的父/所有者对象不会被传输到新线程,因此您的会话不能在主要线程以外的线程中访问。
我建议您使用async / await从线程返回sCarmodel,并将其设置为主线程中的Session。
答案 4 :(得分:0)
我建议你不要在线程中使用Session对象,因为它不是线程安全的。在ASP.NET中,每个请求都有自己的线程和自己的会话。
你从来没有描述过一个真正的问题(不幸的是)所以我真的不知道你要解决的是什么,但手动启动新线程并将数据放入Session中无论如何都不是解决方案。
如果你想异步做事以让web服务器在后台执行某些操作时为其他客户端服务,那么可以查看异步控制器: http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
再次,知道你试图建立一个合适的解决方案是什么非常有用。
答案 5 :(得分:0)
我通过在TempData中存储类的实例来解决我的问题。而且,而不是Thread,我使用的是更好的Task。这是我的解决方案:
[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");
}
}
答案 6 :(得分:0)
但是,我需要将该类放在一个单独的线程中,因为它需要一些时间来完成它并且我想要返回View aschyncronosly。
错误。这是解决此问题的完全错误方法。在ASP.NET应用程序中,除非您已将该工作保存到持久存储,否则不应该在有更多工作要做时返回。
将工作保留在内存中(即使用线程或任务)是不正确的解决方案。
正确的解决方案是使用持久存储(例如,Azure Queue,MSMQ或WebSphere MQ)来存储要完成的工作,然后使用单独的服务来读取该队列,采取适当的操作并存储结果在另一个持久数据结构中。然后,您可以让客户端轮询(例如,HTTP请求)“结果”数据结构和/或在保存结果时通知客户端(例如,SignalR)。
我会详细介绍on my blog,如果您绝对确定要采取不安全的路线,还可以使用一些示例代码。