C# ASP.NET Web API异步控制器方法和死锁
请帮助我理解为什么这段代码会导致死锁? 我有一个asp.NETWebAPI应用程序,我试图使一些控制器方法异步C# ASP.NET Web API异步控制器方法和死锁,c#,asp.net,.net,async-await,deadlock,C#,Asp.net,.net,Async Await,Deadlock,请帮助我理解为什么这段代码会导致死锁? 我有一个asp.NETWebAPI应用程序,我试图使一些控制器方法异步 [HttpPost] [Authentication] public async Task<SomeDTO> PostSomething([FromBody] SomeDTO someDTO) { return await _service.DoSomething(someDTO); } [HttpPost]
[HttpPost]
[Authentication]
public async Task<SomeDTO> PostSomething([FromBody] SomeDTO someDTO)
{
return await _service.DoSomething(someDTO);
}
[HttpPost]
[认证]
公共异步任务PostSomething([FromBody]SomeDTO-SomeDTO)
{
返回等待服务。完成一些事情(sometto);
}
以下是被调用的服务方法的外观:
public async Task<SomeDTO> DoSomething(SomeDTO someDTO)
{
...
var someTask = Task.Run(() =>
{
var entity = new SomeEntity(someDTO);
return _repository.Create(entity);
});
...
var result = await someTask;
...
}
公共异步任务DoSomething(SomeDTO SomeDTO)
{
...
var someTask=Task.Run(()=>
{
var实体=新的SomeEntity(someDTO);
返回_repository.Create(实体);
});
...
var result=等待某项任务;
...
}
还有一些globalhandler,它向控制台打印响应
public class AppGlobalHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var resp = base.SendAsync(request, cancellationToken);
Debug.WriteLine($"Response:{request.RequestUri}{Environment.NewLine}{resp?.ConfigureAwait(false).GetAwaiter().GetResult()?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult()}");
return resp;
}
}
公共类AppGlobalHandler:DelegatingHandler
{
受保护的覆盖任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
var resp=base.sendaync(请求、取消令牌);
Debug.WriteLine($”响应:{request.RequestUri}{Environment.NewLine}{resp?.ConfigureAwait(false).GetAwaiter().GetResult()?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult());
返回响应;
}
}
看起来像ConfigureAwait(false).GetAwaiter().GetResult()
阻止调用线程,但我认为ConfigureWait(false)应该可以避免这种情况,不是吗?我认为您忽略了Task.Run()方法中的async关键字
公共异步任务DoSomething(SomeDTO SomeDTO)
{
var someTask=Task.Run(async()=>//只需为异步运行添加这个
{
var实体=新的SomeEntity(someDTO);
返回_repository.Create(实体);
});
var result=等待某项任务;
}
configurewait(false)在这里对您没有帮助,因为它必须一直在调用堆栈中(请参阅更多)而不是在同步等待的位置,也就是说,它取决于base.SendAsync的实现。如果它在当前线程上获得了一个锁,那么就太晚了。在ASP.net管道中也不建议继续在其他线程上响应(请参阅讨论和帖子)
最后,在异步上下文中同步等待总是一个高风险的想法。
如果您需要阅读内容,为什么不这样做:
public class AppGlobalHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var resp = await base.SendAsync(request, cancellationToken);
var content = resp?.Content != null
? (await resp.Content.ReadAsStringAsync())
: string.Empty;
Debug.WriteLine($"Response:{request.RequestUri}{Environment.NewLine}{content}");
return resp;
}
}
公共类AppGlobalHandler:DelegatingHandler
{
受保护的覆盖异步任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
var resp=await base.sendaync(请求、取消令牌);
var content=resp?.content!=null
?(等待响应内容ReadAsStringAsync())
:string.Empty;
Debug.WriteLine($“响应:{request.RequestUri}{Environment.NewLine}{content}”);
返回响应;
}
}
为什么要将代码包装到Task.Run()中?强制同步代码异步运行毫无意义,它只会使用更多线程。如果你不能一直异步,那就坚持同步。这是代码的一部分,我需要并行运行一些操作@MarcusHöglundI没有看到在你的代码中任何东西会并行运行。记住:异步!=parallel“这是代码的一部分”的意思是:我们发现死锁的可能性很小。哦,如果没有(和类似的)Debug.WriteLine()行,它会死锁吗?
public class AppGlobalHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var resp = await base.SendAsync(request, cancellationToken);
var content = resp?.Content != null
? (await resp.Content.ReadAsStringAsync())
: string.Empty;
Debug.WriteLine($"Response:{request.RequestUri}{Environment.NewLine}{content}");
return resp;
}
}