我们的应用程序不时因为这个错误而崩溃:https://serverfault.com/questions/675649/accessviolationexception-iis,我不想自己讨论这个错误,但对可能的原因有一些疑问:
我已经查看了带有ILSpy的system.web中的代码,我得到的结论是http运行时会丢失上下文(以及一个非托管指针),因此会崩溃。我没有关于异常的详细信息所以我检查了所有代码,除了一个api调用之外,一切都非常直接。
它或多或少看起来像这样(伪代码):
private async Task SearchAsync()
{
Func<Stream, HttpContent, TransportContext, Task> searching =
async (stream, content, transportContext) =>
{
StreamWriter writer = new StreamWriter(stream);
Action<Data> write = new Action<Data>()
{
writer.WriteData(data);
writer.WriteLine();
writer.Flush();
};
List<Task> tasks = new List<Task>();
foreach (IService service in services)
{
tasks.Add(Task.Run(() => service.CallAsync(write));
};
await Task.WhenAny(
Task.Delay(10000),
Task.WhenAll(tasks));
};
response.Content = new PushStreamContent(searching, "text/event-stream");
}
看起来有点奇怪但原因如下:
所以问题是:http上下文在这段代码中是否会以某种方式丢失?丢失意味着以下内容:在链接的问题中,您会看到system.web中的本地方法失败。可能是因为传递给此方法的IntPtr(来自http上下文)不再有效
我看不到任何潜在的问题吗?如何正确处理IIS中的并行任务?
编辑:为什么service.CallAsync Async?
该代码简化了实际情况。在我的代码中,服务是真实服务的包装器。每个服务都有多个步骤,很多类和多个级别的调解器,但结构如下:
GetFromDatabase(); // Not async yet, because of mongo driver.
await CallServiceAsync(); // Sometimes async, sometimes not, depending on service.
PrepareResults(); // Not async, but cpu intensive.
因此,在我看来,将其并行化以减少响应时间是有道理的。
答案 0 :(得分:5)
HttpContext存储在SynchronizationContext上。通过使用Task.Run卸载到ThreadPool线程,您没有使用SC,因此您无法访问HttpContext。
如果CallAsync
是异步方法,那么您不需要在这里使用Task.Run,而只需存储返回的任务:
tasks.Add(service.CallAsync(write);
如果您仍然需要Task.Run,您可以手动传递HttpContext:
var context = HttpContext.Current;
tasks.Add(Task.Run(() =>
{
HttpContext.Current = context;
service.CallAsync(write)
});