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); } }
以上这两步操作完之后,才到了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(',');
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