Web API Request Content多次读取

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web API Request Content多次读取相关的知识,希望对你有一定的参考价值。

使用OWIN 

项目中要做日志过滤器 

新建类ApiLogAttribute

继承ActionFilterAttribute

ApiLogAttribute :  ActionFilterAttribute

public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            string result = null;
            Stream stream = actionContext?.Request?.Content?.ReadAsStreamAsync().Result;

            stream.Position = 0L;
            Encoding encoding = Encoding.UTF8;
            /*
                这个StreamReader不能关闭,也不能dispose, 关了就傻逼了
                因为你关掉后,后面的管道  或拦截器就没办法读取了
            */
            var reader = new StreamReader(stream, encoding);
            result = reader.ReadToEnd();
            /*
            这里也要注意:   stream.Position = 0;
            当你读取完之后必须把stream的位置设为开始
            因为request和response读取完以后Position到最后一个位置,交给下一个方法处理的时候就会读不到内容了。
            */
            stream.Position = 0L;
            Console.WriteLine(result);
            return base.OnActionExecutingAsync(actionContext, cancellationToken);
        }

结果发现stream Position 无法设置,CanSeek为false

用 流复制也不管用

MemoryStream stream = new MemoryStream();
Stream.CopyToAsync(stream);
始终读取不到内容

最后读取文档得知 OWIN 中 Request 的content 只能读取一次,已经被解析,无法再次读取

 

百度 谷歌了一番

https://stackoverflow.com/questions/31389781/read-request-body-twice/31395692#31395692

解决办法如下

在Startup中添加添加中间件

这里的流还没有被读取过,直接复制一份CanSeek为false的stream 流 ,进行替换 

//Request stream重用
            app.Use(async (context, next) =>
            {
                // Keep the original stream in a separate
                // variable to restore it later if necessary.
                var stream = context.Request.Body;

                // Optimization: don‘t buffer the request if
                // there was no stream or if it is rewindable.
                if (stream == Stream.Null || stream.CanSeek)
                {

                    await next.Invoke();

                    return;
                }

                try
                {
                    using (var buffer = new MemoryStream())
                    {
                        // Copy the request stream to the memory stream.
                        await stream.CopyToAsync(buffer);

                        // Rewind the memory stream.
                        buffer.Position = 0L;

                        // Replace the request stream by the memory stream.
                        context.Request.Body = buffer;

                        // Invoke the rest of the pipeline.
                        await next.Invoke();
                    }
                }

                finally
                {
                    // Restore the original stream.
                    context.Request.Body = stream;
                }
            });

或者 在过滤器中 通过如下放法 直接 取出已经被解析的参数

/// <summary>
        /// 读取request 的提交内容
        /// </summary>
        /// <param name="actionContext"></param>
        /// <returns></returns>
        public string GetRequestValues(HttpActionContext actionContext)
        {
            string result = null;
            foreach (var arg in actionContext.ActionArguments)
            {
                if (arg.Value == null)
                    continue;
                var type = arg.Value.GetType();
                if (type == typeof(HttpRequestMessage))
                {
                    result += $"key={arg.Key};";
                    var bytes = ((HttpRequestMessage)arg.Value).Content.ReadAsByteArrayAsync().Result;
                    var decode = HttpUtility.UrlDecode(bytes, 0, bytes.Length, Encoding.GetEncoding("GBK"));
                    result += $"value={decode};{Environment.NewLine}";
                }
                else
                {
                    result += $"key={arg.Key};";
                    result += $"value={JsonConvert.SerializeObject(arg.Value)};{Environment.NewLine}";
                }
            }

            return result;
        }

 



以上是关于Web API Request Content多次读取的主要内容,如果未能解决你的问题,请参考以下文章

如何获取httpservletrequest

Method not found: then send request web api controller

asp.net core 3.0 web api request.body和[frombody]冲突[关闭]

使用HttpContext.Current.Request.Form Web API后的404 POST状态

C# EF6 使用 Unity 对一个上下文进行多次异步调用 - Asp.Net Web Api

ASP.NET Web Api HttpResponseException 400 (Bad Request) 被 IIS 劫持