在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中的值提供一些建议吗?

谢谢!

编辑:问题解决了,感谢大家的建议!

在MVC中的线程中存储会话中的值

在处理请求期间将自定义对象放入Session。

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

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

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

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

顺便问一下,你为什么不使用任务并行库?

HttpContext会话对象的父/所有者对象不会传输到新线程,因此您的会话在主线程以外的线程中不可访问。

我建议您使用async/await从线程返回sCarmodel,并在主线程中将其设置为Session。

这并不是说该值没有存储在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"] 获取该数据

我建议您不要在线程中使用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)。

我在我的博客上详细介绍了更多细节,如果你确信要走不安全的路线,我也有一些示例代码可以在那里使用。