Session 如何从不同的线程访问MVC.NET4中的会话

Session 如何从不同的线程访问MVC.NET4中的会话,session,asynchronous,task,httpcontext,Session,Asynchronous,Task,Httpcontext,我有一个MVC.Net4应用程序,其中有长时间运行的回送操作,这就是我使用System.Threading.Tasks.Task类的原因 我在用户单击GUI上的某个按钮后启动任务,从该任务开始,我将使用InternAPI中的异步方法,我需要等待。这一切都在起作用 public ActionResult DoAsyncAction() { //ReturnValue that needs to be further populated by the asyn

我有一个MVC.Net4应用程序,其中有长时间运行的回送操作,这就是我使用System.Threading.Tasks.Task类的原因

我在用户单击GUI上的某个按钮后启动任务,从该任务开始,我将使用InternAPI中的异步方法,我需要等待。这一切都在起作用

public ActionResult DoAsyncAction()
        {
            //ReturnValue that needs to be further populated by the async action in productive environment
            var arv = new AsyncReturnValue
            {
                ProgressBar = new ProgressBar {Action = "SomeAction", User = "SomeUser"}
            };
            var t = new Task<AsyncReturnValue>(DoAction, arv);

            //Add a Progressbar before Task starts so i can visualize the process on the view
            HttpContext.GetSession().ProgressBars.Add(arv.ProgressBar);

            //from my understanding this is similar to an event that gets triggered when my DoAction Method finished so i need to remove 
            //the progressbar there again since the process will be finished in that case
            t.ContinueWith(DoActionkComplete);
            t.Start();

            //Returns the User to the Index Page while the Task is processing
            return View("Index");
}
部分观点:

@using AsyncProj.Models
@model List<AsyncProj.Models.ProgressBar>

@{
    ViewBag.Title = "ProgressPartial";
}
    @{
        var foo = (MySessionObject) HttpContext.Current.Session["__MySessionObject"];
        foreach (var pb in foo.ProgressBars)
         {
            <div style="border: 1px solid black">
                    <p>@pb.Action</p>
                    <div id="progressbar">This will be turned into a ProgressBar via jQuery.</div >
            </div>
         }
    }
在这个方法中,我想从会话中删除Progressbar HttpContext.GetSession.ProgressBars.RemovepbToRemove。但问题是,我仍然在另一个线程上运行,因此我没有有效的HttpContext,并且我的SessionObject在该线程上为null

这就是我的DoActionComplete方法现在的样子:

public void DoActionkComplete(Task<AsyncReturnValue> t)
        {
            //i set the user hardcode because its only a demo 
            DeleteProgress.Add(new ProgressBarDeleteObject {ProgressBar = t.Result.ProgressBar, User = "Asd123"});
        }
别误会我的意思,我的变通方法很好,但我想知道干净的方法。据我所知,从技术上讲,控制器上的静态列表可能会变得非常大,从而降低网站的速度。当ApplicationPool重新启动应用程序时,此类列表也会丢失其条目

因此,我的实际问题是,如何从我正在使用的不同线程访问HttpContext SessionObject?如果这是不可能的,什么是正确的方式来实现我想要的

您可以指定任务继续的SynchronizationContext,然后您应该能够访问进度条。尝试更改您的t.ContinueWithDoActionkComplete;召唤

t、 ContinueWithDoActionkComplete,TaskScheduler.FromCurrentSynchronizationContext

如果您使用的是.NET 4.5,则可以使用async\Wait重写您的方法

}

如果还使DoAction方法异步,则可以删除Task.Run部分,因为它会使用线程池中的线程

因此,我的实际问题是,如何从我正在使用的不同线程访问HttpContext SessionObject

那是不可能的

如果这是不可能的,什么是正确的方式来实现我想要的

首先,让我们回到原始场景。问题在于:

我有一个MVC.Net4应用程序,其中有长时间运行的回送操作,这就是我使用System.Threading.Tasks.Task类的原因

对于这种情况,这是错误的解决方案。正确的解决方案是使用一个可靠的队列Azure queue/MSMQ,由一个独立的后台进程Azure webjob/Win32服务进行处理。这是一个更可靠的解决方案,因为您在ASP.NET线程池上进行的任何工作都可能会丢失,特别是如果您不将该工作通知ASP.NET


一旦您设置了这个体系结构,那么您就可以使用signar从您的web服务器到您的客户机进行通信。如果有必要,SignalR将使用轮询,但它也可以使用更有效的方法,如WebSocket。

我是否需要以某种方式更改DoActionComplete方法?我在最初的帖子中添加了这个方法,这样你就可以看到它了。因为在我使用您的示例时根本不调用该方法。您不需要更改它,同步上下文只会影响在哪个线程上执行延续。因此,方法DoActionkComplete应该被调用,正如我所期望的那样。在DoAction方法返回后,不会发生任何事情。它只是不调用DoActionComplete。但是我也没有得到任何异常。您应该将您的方法标记为异步,并使其返回一个任务。公共异步任务DOASyncAction我刚刚尝试过。没有任何改变。它仍然只是执行DoAction,似乎完全忽略了t.ContinueWith部分。感谢您的回复。我现在真的不能尝试,因为这是一个实际的工作。我会试着在以后的项目中引入这个解决方案,因为它将是一个富有成效的项目。我现在要坚持我的解决方案,因为我的时间很短,我想会有一个更简单的方法来解决我的问题。即使没有可靠的体系结构,你仍然可以使用Signal。
     public class MySessionObject
{
    public List<ProgressBar> ProgressBars { get; set; }
    public string User { get; set; }}
 public class AsyncReturnValue
    {
        public ProgressBar ProgressBar { get; set; }
    }
public void DoActionkComplete(Task<AsyncReturnValue> t)
        {
            //i set the user hardcode because its only a demo 
            DeleteProgress.Add(new ProgressBarDeleteObject {ProgressBar = t.Result.ProgressBar, User = "Asd123"});
        }
 public class ProgressBarDeleteObject
    {
        public ProgressBar ProgressBar { get; set; }
        public string User { get; set; }
    }
    public async Task<ActionResult> DoAsyncAction()
    {
        //ReturnValue that needs to be further populated by the async action in productive environment
        var arv = new AsyncReturnValue
        {
            ProgressBar = new ProgressBar {Action = "SomeAction", User = "SomeUser"}
        };

        //Add a Progressbar before Task starts so i can visualize the process on the view
        HttpContext.GetSession().ProgressBars.Add(arv.ProgressBar);

        var result = await Task.Run(DoAction());

        //i set the user hardcode because its only a demo 
        DeleteProgress.Add(new ProgressBarDeleteObject {ProgressBar = result.ProgressBar, User = "Asd123"});

        //Returns the User to the Index Page while the Task is processing
        return View("Index");