Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在异步任务中使用HttpContext_C#_Asp.net Mvc_Asp.net Mvc 3_Asynchronous_Async Await - Fatal编程技术网

C# 在异步任务中使用HttpContext

C# 在异步任务中使用HttpContext,c#,asp.net-mvc,asp.net-mvc-3,asynchronous,async-await,C#,Asp.net Mvc,Asp.net Mvc 3,Asynchronous,Async Await,我有以下mvc操作 public async Task<JsonResult> DoSomeLongRunningOperation() { return await Task.Run(() => { //Do a lot of long running stuff //The underlying framework uses the HttpContext.Current.User.Identity.Name so the u

我有以下mvc操作

public async Task<JsonResult> DoSomeLongRunningOperation()
{
    return await Task.Run(() =>
    {
        //Do a lot of long running stuff
        //The underlying framework uses the HttpContext.Current.User.Identity.Name so the user is passed on the messagebus.
    }
}
在持久化到数据库之前,会在很多地方调用此代码

我们需要另一种方法来获取发起webrequest的用户的用户名,或者修复HttpContext为null的问题

因为对数据库的持久化发生在任务中,所以在进入任务之前,我无法访问HttpContext


我也想不出一种安全的方法来临时保存用户名,以便实现另一个ICredentials服务对象。

在启动新线程之前,您应该从当前上下文中获得所需的任何信息。在本例中,添加如下内容:

string username = HttpContext.Current.User.Username;
任务之前。运行
,然后在另一个线程中使用该线程

另一方面,目前来看,没有理由等待任务。您可以直接返回任务,而不将方法标记为
Async


如果您需要访问
响应
对象,该对象可能会利用长时间运行操作的结果,因此不能在
任务之前运行。运行
您应该在
任务之后执行。运行
(但确保任务已等待)。如果你最终这样做了,那么你就不能按照我在上一段中的建议去做。

你几乎不想使用
任务。在ASP.NET方法中运行

我认为最干净的解决方案(但工作最多)是在其他层实现
异步
兼容接口:

public async Task<JsonResult> DoSomeLongRunningOperation()
{
  //Do a lot of long running stuff
  var intermediateResult = await DoLongRunningStuff();
  return await DetermineFinalResult(intermediateResult);
}
公共异步任务DoSomeLongRunningOperation()
{
//做很多长时间跑步的事情
var intermediateResult=wait DoLongRunningStuff();
返回等待确定最终结果(中间结果);
}

我会尝试将对HttpContext的引用作为状态对象传入,因为这会在堆栈上为执行工作的线程创建该对象的新实例。不要使用Task.Run,而是使用

return await Task.Factory.StartNew((ctx) => 
{
    var context = (HttpContext)ctx;
   //Do stuff
}, httpContextObject);

Task.Run和Task.Factory.StartNew立即返回,因此asp.net在处理请求的工作线程的事件生命周期中继续运行,而您的线程正在对已处理的对象进行操作。

我更新了我的问题。。。在将内容保存到数据库之前,需要访问任务中的上下文,或者需要另一个安全的解决方案来获取我的用户名。@MarcoFranssen您将无法从后台线程访问当前上下文,这是不可能的。正如我已经说过的,在启动后台线程之前,您需要从当前上下文中获取信息。另一个问题可能是,在后台任务中,您所做的工作比您应该做的更多。也许这个方法的部分应该被完全重构以在其他地方运行,或者只有一个较小的部分应该被设置为在后台任务中运行,该部分实际上与数据库交互或进行一些处理。这里的问题是混合了业务和UI代码。@Servy您实际上可以关闭HttpContext对象作为新任务的状态对象。这将在堆栈上为新线程创建该对象的新副本。请参阅下面的答案。@hotsoup.Open我已经在您的帖子的评论中列出了与此相关的几个问题;除此之外,您实际上并没有在代码中结束它,您只是将它作为一个形式参数传入。这…不同。首先,你不是在创建对象的副本,你只是在复制对象的引用
HttpContext
不是一个
struct
。其次,它不能从后台线程访问的原因是,它不是设计用来从其他上下文访问的。从设计上看,它不是线程安全的对象,您只能在适当的同步上下文中依赖对象的当前状态,等等。您根本不应该从另一个线程访问
HttpContext
,就像在winform应用程序中,您不能从非UI线程访问控件一样。@Servy根据,您可以关闭HttpContext。如果每个线程都有自己的堆栈,并且HttpContext作为参数传递给该线程,那么应该在堆上为新线程创建该对象的副本。确保可以关闭它。我从没说过你不能我说过你不应该。是的,每个线程都有自己的堆栈,我对此没有异议。我争论的是,你所做的任何事情都是在复制上下文;不是。虽然堆栈不同(必要时),但堆是共享的。由于
HttpContext
是引用类型,因此实际对象位于堆上。您只是在闭包中复制对该对象的引用。好的,这可能不是上述问题的答案,但它对我很有用,谢谢!)当然,也可以看到代码位于体系结构的不同层,但这不是问题所在。如果我在不同的课堂上定义它,我仍然会有同样的问题。真的很糟糕的答案。有许多API需要执行任务。@TheSharpNinja:我会坚持我的答案。如果需要
任务
,则使用
异步
/
等待
,而不是
任务。运行
。如果被调用的函数必须返回void,则无法执行此操作。使用async void会导致异常处理问题。在这种情况下,使用Task.Run是正确的技术。现在,我已经对此进行了很多思考,使用一个自定义的调度程序将线程与上下文对象相关联,这将解决这个问题。@TheSharpNinja:也许你可以详细阐述一下你的场景,并提出你自己的问题<代码>任务。运行
对于这种情况听起来不是一个好的解决方案。
return await Task.Factory.StartNew((ctx) => 
{
    var context = (HttpContext)ctx;
   //Do stuff
}, httpContextObject);