Web API Request Content多次读取问题

如题:

.net webapi 采用了Owin的验证机制,另外在Action层之外设置了两次验证

第一次是重写了AuthorizeAttribute,用来验证身份的类,类名为ProtalApiAuth【这个是直接作用于action的,如下图】

 

 

第二次是重写了ActionFilterAttribute, 在OnActionExecuting和OnActionExecuted的时候分别记录webapi请求和返回的内容 ,类名为:AppRequestActionFilter 【这个是注册到全局的,见图3】

 

 

 

前两层具体读取body的代码

//读取请求的内容流
var task = context.Request.Content.ReadAsStreamAsync();
string content = "";
using (System.IO.Stream sm = task.Result)
                {
                    if (sm != null)
                    {
                        sm.Seek(0, SeekOrigin.Begin);
                        int len = (int)sm.Length;
                        byte[] inputByts = new byte[len];
                        sm.Read(inputByts, 0, len);
                        sm.Close();
                        content = Encoding.UTF8.GetString(inputByts);
                    }
                }
View Code

 

以上这两步操作完之后,才到了action这里,背景交代完毕。

遇到的问题是:

  第一层和第二层都需要解析body值,做一些操作,但是在解析完之后,走到ActionFilterAttribute的时候就拿不到body了,提示为null,百度了很久前辈很多都说是因为引用了owin导致流只能读取一次。而且我发现个问题,如果不写AuthorizeAttribute,把逻辑都放到ActionFilterAttribute里面实现的话,ActionFilterAttribute和Action里都还是可以拿到body的。只要加入了AuthorizeAttribute,那么在ActionFilterAttribute和Action里都是空的。这个原因现在还没弄明白

 

解决方法:

  1、采用以下方式读取post,至少写法简单一些了。但是只能传递到ActionFilterAttribute,Action也是拿不到

//获取Post请求的内容
  context.Request.Content.ReadAsStreamAsync().Result.Seek(0, System.IO.SeekOrigin.Begin);
  dynamic content = await actionContext.Request.Content.ReadAsStringAsync().Result;

  2、 在ActionFilterAttribute类当中,可以用context.ActionArguments来获取body内容

var task = context.ActionArguments;
                foreach (var b in task)
                {
                    var post = context.ActionArguments[b.Key];

                    if (null != post)
                    {
                        Type t = post.GetType();
                        var typeArr = t.GetProperties();
                        var str = "";
                        foreach (var a in typeArr.OrderBy(x => x.Name))
                        {
                            var n = a.Name;
                            var v = a.GetValue(post, null);
                            if (null != v && v.ToString() != "")
                            {
                                str += @"""" + n + @""":" + @"""" + v + @""",";
                            }
                        }
                        str = str.TrimEnd(',');
                        str = @"{" + str + "}";
                        content += str + ",";
                    }
                }
                content = content.TrimEnd(',');
View Code

 

        3、终极方案:用这种方式避免读流,ActionFilterAttribute和Action都能拿到body值  【注意异步读取时await】

dynamic content = await context.Request.Content.ReadAsStringAsync();

 

附Asp.net Core碰到此类问题的解决方法     https://blog.csdn.net/weixin_34126215/article/details/93605418

微软官网对ReadAsStringAsync的解释:https://docs.microsoft.com/zh-cn/dotnet/api/system.net.http.httpcontent.readasstringasync?view=netframework-4.6.2

posted @ 2020-09-15 10:43  狼窝窝  阅读(1412)  评论(0编辑  收藏  举报