C# HttpContent.ReadAsStringAsync导致请求挂起
在ASP.NET WebAPi 2代码中,我有一个委托处理程序C# HttpContent.ReadAsStringAsync导致请求挂起,c#,asp.net,asp.net-web-api,asp.net-web-api2,C#,Asp.net,Asp.net Web Api,Asp.net Web Api2,在ASP.NET WebAPi 2代码中,我有一个委托处理程序 public class RequestHandler1 : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var formData2 = a
public class RequestHandler1 : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var formData2 = await ReadContent(request);
return await base.SendAsync(request, cancellationToken);
}
private static async Task<string> ReadContent(HttpRequestMessage request)
{
using (var ms = new MemoryStream())
{
await request.Content.CopyToAsync(ms);
ms.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(ms, Encoding.UTF8, true, 100, true))
{
return sr.ReadToEnd();
}
}
}
private static async Task<string> ReadContent3(HttpRequestMessage request)
{
var text = await request.Content.ReadAsStringAsync();
return text;
}
}
public类RequestHandler1:DelegatingHandler
{
受保护的覆盖异步任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
var formData2=等待读取内容(请求);
返回wait base.sendaync(请求、取消令牌);
}
专用静态异步任务ReadContent(HttpRequestMessage请求)
{
使用(var ms=new MemoryStream())
{
等待请求.Content.CopyToAsync(ms);
Seek女士(0,SeekOrigin.Begin);
使用(var sr=新的StreamReader(ms,Encoding.UTF8,true,100,true))
{
返回sr.ReadToEnd();
}
}
}
专用静态异步任务ReadContent3(HttpRequestMessage请求)
{
var text=wait request.Content.ReadAsStringAsync();
返回文本;
}
}
这个问题是与相关的,但从未在该线程中得到正确的回答
当我调用return wait base.SendAsync(请求,取消令牌)时代码>它只是挂起。无论我是调用ReadContent
还是ReadContent3
还有什么建议吗?试试这段代码
public class CustomLogHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var logMetadata = await BuildRequestMetadata(request);
var response = await base.SendAsync(request, cancellationToken);
logMetadata = await BuildResponseMetadata(logMetadata, response);
await SendToLog(logMetadata);
return response;
}
private async Task<LogMetadata> BuildRequestMetadata(HttpRequestMessage request)
{
LogMetadata log = new LogMetadata
{
RequestMethod = request.Method.Method,
RequestTimestamp = DateTime.Now,
RequestUri = request.RequestUri.ToString(),
RequestContent = await request.Content.ReadAsStringAsync(),
};
return log;
}
private async Task<LogMetadata> BuildResponseMetadata(LogMetadata logMetadata, HttpResponseMessage response)
{
logMetadata.ResponseStatusCode = response.StatusCode;
logMetadata.ResponseTimestamp = DateTime.Now;
logMetadata.ResponseContentType = response.Content == null ? string.Empty : response.Content.Headers.ContentType.MediaType;
logMetadata.Response = await response.Content.ReadAsStringAsync();
return logMetadata;
}
private async Task<bool> SendToLog(LogMetadata logMetadata)
{
try
{
//write your code
}
catch
{
return false;
}
return true;
}
}
公共类CustomLogHandler:DelegatingHandler
{
受保护的覆盖异步任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
var logMetadata=await BuildRequestMetadata(请求);
var response=await base.sendaync(请求、取消令牌);
logMetadata=等待BuildResponseMetadata(logMetadata,响应);
等待发送日志(日志元数据);
返回响应;
}
专用异步任务BuildRequestMetadata(HttpRequestMessage请求)
{
LogMetadata log=新的LogMetadata
{
RequestMethod=request.Method.Method,
RequestTimestamp=DateTime。现在,
RequestUri=request.RequestUri.ToString(),
RequestContent=Wait request.Content.ReadAsStringAsync(),
};
返回日志;
}
专用异步任务BuildResponseMetadata(LogMetadata LogMetadata、HttpResponseMessage响应)
{
logMetadata.ResponseStatusCode=response.StatusCode;
logMetadata.ResponseTimestamp=DateTime.Now;
logMetadata.ResponseContentType=response.Content==null?string.Empty:response.Content.Headers.ContentType.MediaType;
logMetadata.Response=wait Response.Content.ReadAsStringAsync();
返回日志元数据;
}
专用异步任务SendToLog(日志元数据日志元数据)
{
尝试
{
//编写代码
}
抓住
{
返回false;
}
返回true;
}
}
在代码中进行全局搜索,查看是否有.Result或.Wait()调用。如果有可能出现死锁问题,则可能与此答案存在类似的问题:。调用SendAsync,它在等待ReadContent时阻止请求上下文。但在ReadContent内部,CopyToAsync()、ReadToEnd()或ReadAsTringAsync()正在等待上下文自由获取内容。因此,由于您的内容读取器正在等待请求上下文由等待它们返回值的同一方法释放,因此出现了死锁。@Steve您是对的,在其他类的其他地方还有一些其他的.Result。一旦我把它们修好了,它就可以工作了。这有什么用呢?首先,ReadAsStringAsync
没有挂起。其次,在读取内容时甚至不使用此处理程序。它只用于记录请求和响应。如果ReadAsStringAsync
被阻止(它没有),则等待响应。Content.ReadAsStringAsync()BuildResponseMetadata
中的code>也会阻止此代码的功能,但会引入bug。没有任何东西表明响应是字符串,但是BuildResponseMetadata
尝试将其全部读取为字符串。如果响应很大,这将阻塞,直到所有内容都被读取。它会将整个响应字符串缓存在内存中,浪费RAM,消除HttpClient最重要的优点之一。最糟糕的是,它将在调用方进行更改之前消耗整个响应流。这将中断任何预期从流中读取的调用程序