C# 如何使用.NET4API端点从request.Content对象获取原始请求正文

C# 如何使用.NET4API端点从request.Content对象获取原始请求正文,c#,asp.net-web-api,C#,Asp.net Web Api,我试图捕获原始请求数据以实现责任,并希望从请求对象中提取请求正文内容 我看到一些建议正在执行Request.InputStream,但是这个方法在Request对象上不可用 知道如何获取Request.Content主体的字符串表示形式吗 您可以通过调用Request.Content属性上的readasstringasync来获取原始数据 string result = await Request.Content.ReadAsStringAsync(); 如果您希望在字节或流中使用它,则有各种

我试图捕获原始请求数据以实现责任,并希望从请求对象中提取请求正文内容

我看到一些建议正在执行Request.InputStream,但是这个方法在Request对象上不可用

知道如何获取Request.Content主体的字符串表示形式吗


您可以通过调用
Request.Content
属性上的
readasstringasync
来获取原始数据

string result = await Request.Content.ReadAsStringAsync();
如果您希望在字节或流中使用它,则有各种重载。由于这些是异步方法,您需要确保控制器是异步的:

public async Task<IHttpActionResult> GetSomething()
{
    var rawMessage = await Request.Content.ReadAsStringAsync();
    // ...
    return Ok();
}

在这种情况下,您的端点不需要是异步的(除非您有其他异步方法)

在您对@Kenneth答案的评论中,您是说
ReadAsStringAsync()
返回的是空字符串

这是因为您(或类似model binder的东西)已经阅读了内容,所以Request.content中内部流的位置在末尾

你能做的是:

public static string GetRequestBody()
{
    var bodyStream = new StreamReader(HttpContext.Current.Request.InputStream);
    bodyStream.BaseStream.Seek(0, SeekOrigin.Begin);
    var bodyText = bodyStream.ReadToEnd();
    return bodyText;
}

对于其他不想使其控制器异步、无法访问HttpContext或正在使用dotnet core的未来用户(这是我在Google上首次找到的尝试实现此目的的答案),以下内容适用于我:

[HttpPut("{pathId}/{subPathId}"),
public IActionResult Put(int pathId, int subPathId, [FromBody] myViewModel viewModel)
{

    var body = new StreamReader(Request.Body);
    //The modelbinder has already read the stream and need to reset the stream index
    body.BaseStream.Seek(0, SeekOrigin.Begin); 
    var requestBody = body.ReadToEnd();
    //etc, we use this for an audit trail
}

如果您既需要从请求中获取原始内容,又需要在控制器中使用它的绑定模型版本,则可能会出现此异常

NotSupportedException: Specified method is not supported. 
例如,您的控制器可能是这样的,这让您想知道为什么上面的解决方案不适合您:

public async Task<IActionResult> Index(WebhookRequest request)
{
    using var reader = new StreamReader(HttpContext.Request.Body);

    // this won't fix your string empty problems
    // because exception will be thrown
    reader.BaseStream.Seek(0, SeekOrigin.Begin); 
    var body = await reader.ReadToEndAsync();

    // Do stuff
}
公共异步任务索引(WebhookRequest)
{
使用var reader=newstreamreader(HttpContext.Request.Body);
//这不会解决字符串空的问题
//因为异常将被抛出
reader.BaseStream.Seek(0,SeekOrigin.Begin);
var body=wait reader.ReadToEndAsync();
//做事
}
您需要将模型绑定从方法参数中取出,然后手动绑定自己:

public async Task<IActionResult> Index()
{
    using var reader = new StreamReader(HttpContext.Request.Body);

    // You shouldn't need this line anymore.
    // reader.BaseStream.Seek(0, SeekOrigin.Begin);

    // You now have the body string raw
    var body = await reader.ReadToEndAsync();

    // As well as a bound model
    var request = JsonConvert.DeserializeObject<WebhookRequest>(body);
}
公共异步任务索引()
{
使用var reader=newstreamreader(HttpContext.Request.Body);
//你不应该再需要这条线了。
//reader.BaseStream.Seek(0,SeekOrigin.Begin);
//现在,主体字符串已处于原始状态
var body=wait reader.ReadToEndAsync();
//以及一个约束模型
var request=JsonConvert.DeserializeObject(主体);
}

很容易忘记这一点,我以前解决过这个问题,但现在不得不重新学习解决方案。希望我在这里的回答能给我自己一个很好的提醒…

谢谢Kenneth,但是原始消息返回一个空字符串,我做对了吗?我可以看到内容包含数据,为什么ReadAsStringAsync()返回空字符串?与@MarkKadlec的问题相同,此解决方案不起作用检查您是否在
ReadAsStringAsync
之前已经阅读过它。此方法将读取到该流的末尾,并将指针保留在该流中。如果正在调试并希望在“监视”窗口中以字符串形式查看内容,则无法在Request.Body流中进行搜索。使用此:
Request.Content.ReadAsStringAsync().Result
此代码在HTTP中运行良好,但当我使用HTTPS连接时,它在bodytext中给出了空字符串,你能帮我吗?奇怪的是,对我来说,它甚至在HTTPS连接上工作。从HTTPS调用时得到空字符串,我是否需要在web配置中添加任何内容?如果您想知道.Current”-属性在HttpContext中不可用,它已被删除,原因是架构不好。此处可以找到解释:重要提示:如果您的方法没有参数,则不要使用
Seek
,否则您将得到“NotSupportedException:指定的方法不受支持。Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.Seek”
public async Task<IActionResult> Index()
{
    using var reader = new StreamReader(HttpContext.Request.Body);

    // You shouldn't need this line anymore.
    // reader.BaseStream.Seek(0, SeekOrigin.Begin);

    // You now have the body string raw
    var body = await reader.ReadToEndAsync();

    // As well as a bound model
    var request = JsonConvert.DeserializeObject<WebhookRequest>(body);
}