我正在尝试在ASP.net 5中访问请求的原始输入正文/流.过去,我能够将输入流的位置重置为0并将其读入内存流但是当我尝试这样做时从上下文输入流为null或抛出错误(System.NotSupportedException =>“不支持指定的方法.”).
在下面的第一个例子中,如果我将控制器方法的参数对象类型声明为动态,我可以在控制器中访问原始请求.由于各种原因,这不是一个解决方案,我需要在身份验证过滤器中访问原始请求正文.
此示例有效,但不是一个合理的解决方案:
- [HttpPost("requestme")]
- public string GetRequestBody([FromBody] dynamic body)
- {
- return body.ToString();
- }
引发错误:
- [HttpPost("requestme")]
- public string GetRequestBody()
- {
- var m = new MemoryStream();
- Request.Body.CopyTo(m);
- var contentLength = m.Length;
- var b = System.Text.Encoding.UTF8.GetString(m.ToArray());
- return b;
- }
引发错误:
- [HttpPost("requestme")]
- public string GetRequestBody()
- {
- Request.Body.Position = 0;
- var input = new StreamReader(Request.Body).ReadToEnd();
- return input;
- }
引发错误:
- [HttpPost("requestme")]
- public string GetRequestBody()
- {
- Request.Body.Position = 0;
- var input = new MemoryStream();
- Request.Body.CopyTo(input);
- var inputString = System.Text.Encoding.UTF8.GetString(input.ToArray());
- return inputString;
- }
我需要访问我正在构建的API的每个请求的原始请求主体.
任何帮助或方向将不胜感激!
编辑:
这是我想要阅读请求正文的代码.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- using Microsoft.AspNet.Mvc;
- using Microsoft.AspNet.Http;
- namespace API.Filters
- {
- public class CustomAuthorizationAttribute : Attribute,IAuthorizationFilter
- {
- public CustomAuthorizationAttribute()
- { }
- public void OnAuthorization(AuthorizationContext context)
- {
- if (context == null)
- throw new ArgumentNullException("OnAuthorization AuthorizationContext context can not be null.");
- else
- {
- if (this.AuthorizeCore(context.HttpContext) == false)
- {
- // Do Other Stuff To Check Auth
- }
- else
- {
- context.Result = new HttpUnauthorizedResult();
- }
- }
- }
- protected virtual bool AuthorizeCore(HttpContext httpContext)
- {
- var result = false;
- using (System.IO.MemoryStream m = new System.IO.MemoryStream())
- {
- try
- {
- if (httpContext.Request.Body.CanSeek == true)
- httpContext.Request.Body.Position = 0;
- httpContext.Request.Body.CopyTo(m);
- var bodyString = System.Text.Encoding.UTF8.GetString(m.ToArray());
- return CheckBody(bodyString); // Initial Auth Check returns true/false <-- Not Shown In Code Here on Stack Overflow
- }
- catch (Exception ex)
- {
- Logger.WriteLine(ex.Message);
- }
- }
- return false;
- }
- }
- }
当调用标记有CustomAuthorization属性的控制器方法时,将访问此代码.
- [Filters.CustomAuthorizationAuthorization]
- [HttpPost]
- public ActionResult Post([FromBody]UserModel Profile)
- {
- // Process Profile
- }
解决方法
Request.Body的实现取决于控制器操作.
如果操作包含参数,则由Microsoft.AspNet.WebUtilities.FileBufferingReadStream实现,它支持搜索(Request.Body.CanSeek == true).此类型还支持设置Request.Body.Position.
但是,如果您的操作不包含任何参数,则由Microsoft.AspNet.Loader.IIS.FeatureModel.RequestBody实现,它不支持搜索(Request.Body.CanSeek == false).这意味着您无法调整Position属性,只需开始阅读流即可.
这种差异可能与MVC需要从请求体中提取参数值的事实有关,因此它需要读取请求.
在您的情况下,您的操作没有任何参数.因此使用Microsoft.AspNet.Loader.IIS.FeatureModel.RequestBody,如果您尝试设置Position属性,则会引发异常.
解决方案:要么不设置位置,要么检查您是否可以先设置位置:
- if (Request.Body.CanSeek)
- {
- // Reset the position to zero to read from the beginning.
- Request.Body.Position = 0;
- }
- var input = new StreamReader(Request.Body).ReadToEnd();