【问题标题】:WebApi get the post raw body inside a filterWebApi 获取过滤器内的原始正文
【发布时间】:2022-03-15 16:42:20
【问题描述】:

我创建了一个日志,我需要检索请求正文以保存在数据库中。我用 HttpActionContext 创建了一个过滤器。 我尝试通过 filterContext.Request.Content.ReadAsStringAsync().Result; 恢复 但它总是返回一个空字符串。

LogFilter.cs

public override void OnActionExecuting(HttpActionContext filterContext)
    {
        try
        {
            Task<string> content = filterContext.Request.Content.ReadAsStringAsync();
            string body = content.Result;

            logModel.RequestLog rl = new logModel.RequestLog();
            rl.IP = ((HttpContextWrapper)filterContext.Request.Properties["MS_HttpContext"]).Request.UserHostAddress;
            rl.Type = filterContext.ControllerContext.RouteData.Values["controller"].ToString().ToUpper();
            rl.URL = filterContext.Request.RequestUri.OriginalString;
            rl.Operation = filterContext.Request.Method.Method;
            rl.RequestDate = DateTime.Now;


            filterContext.ControllerContext.RouteData.Values.Add("reqID", new deviceLog.RequestLog().Add(rl).ID.ToString());
        }
        catch { }
        //return new deviceLog.RequestLog().Add(rl);
        base.OnActionExecuting(filterContext);
    }

【问题讨论】:

  • 您正在数据库中保存原始请求?听起来像是一个值得商榷的设计选择。
  • 我正在保存请求正文,以便能够跟踪一些错误。
  • 你如何使用这个过滤器?将其分配给操作方法?
  • 用作全局过滤器,用于我的应用程序的所有控制器

标签: c# asp.net-mvc asp.net-web-api


【解决方案1】:

也许请求流已经到达结束。尝试将流位置重置为开头:

public class MyAttribute:ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionContext actionContext)
    {
        string rawRequest;
        using (var stream = new StreamReader(actionContext.Request.Content.ReadAsStreamAsync().Result))
        {
            stream.BaseStream.Position = 0;
            rawRequest = stream.ReadToEnd();
        }
    }
}

【讨论】:

  • 我认为你的应用是 MVC。请参阅我更新的 WebAPI 帖子。
  • 您的答案如何与官方的 microsoft 文档相一致“此规则的原因是请求正文可能存储在只能读取一次的非缓冲流中。” docs.microsoft.com/en-us/aspnet/web-api/overview/…是否保证body会一直被读取?
  • 执行此代码时出现以下错误:“NotSupportedException:此流不支持查找操作。”
  • 这个答案是错误的。它不回答提出的问题,并产生 NotSupportedExceptions 因为 stream.BaseStream 是只读的..
【解决方案2】:

晚了将近 7 年...我的任务是为一个已有 8 年历史的遗留项目创建一个过滤器,没有任何模式或架构。

我尝试使用流/字符串异步从流中读取,但它不允许您多次读取,并且它已经在操作过滤器之前读取 - 搜索为假,位置为只读。

我尝试过反思,但收获太多,我又不喜欢它。

我尝试获取“MS_HttpContext”,但它不在字典中。

经过 8 小时的研究,我妥协于从请求中获取所有操作参数并将它们转换为 Json。

对于 4.7 框架 API:

private string requestBody = "";

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        requestBody = JsonConvert.SerializeObject(actionContext.ActionArguments);

        base.OnActionExecuting(actionContext);
    }

对于 .NET 5.0:

我在 OnResultExecuted 方法上使用它。流已被读取,因此您需要将请求正文重新定位为 0。

private static async Task<string> FormatRequestBody(HttpRequest request)
        {
            // we set the stream position to 0 to reset the pointer. If this is not done, the read stream will be incorrect and the Body will be empty
            request.Body.Position = 0;
            // We now need to read the request stream.  First, we create a new byte[] with the same length as the request stream...
            var buffer = new byte[Convert.ToInt32(request.ContentLength)];
            //...Then we copy the entire request stream into the new buffer.
            await request.Body.ReadAsync(buffer, 0, buffer.Length);
            // We convert the byte[] into a string using UTF8 encoding...
            //... and send it back...
            return Encoding.UTF8.GetString(buffer);
        }

希望这对某人有所帮助,因为我在进行研究时偶然发现了这篇文章以及其他 15 个 stackoverflow 帖子。

【讨论】:

  • .NET 4.7 的 JSON 方法在 .NET 6 中仍然有效,而且它比我遇到的任何其他解决方案都好得多,而且它是单行的。太棒了,太棒了!
猜你喜欢
  • 2016-09-23
  • 2022-07-22
  • 2015-12-17
  • 2011-03-15
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多