在MVC中的Thread in Thread中存储值

时间:2013-08-03 11:38:52

标签: c# asp.net-mvc multithreading web

我对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

有人可以提供一些关于如何在线程中从类中访问值的建议吗?

谢谢!

修改 问题解决了,谢谢大家的建议!

7 个答案:

答案 0 :(得分:3)

在处理请求期间在会话中放置自定义对象。

将对此自定义对象的引用传递给后台线程。

在后台线程中设置自定义对象的属性。

确保您进行任何必要的同步。

答案 1 :(得分:1)

您需要以某种方式将会话传递给后台线程。例如,请参阅here

顺便问一下,你为什么不使用Task Parallel Library

答案 2 :(得分:0)

并不是该值未存储在Session中。它是。问题是你的代码继续与你创建的线程并行执行,当它访问Session["test"]时,你的线程还没有分配它。 你必须以某种方式重新组织你的代码。此外,不推荐在asp.net应用程序中启动线程,因为它非常耗费资源。

修改

它似乎确实没有设置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,如果您绝对确定要采取不安全的路线,还可以使用一些示例代码。