我面临的情况是我要在ASP.NET Web API中从传入请求中读取表单数据两次(来自模型绑定器和过滤器)。我尝试使用LoadIntoBufferAsync
,但没有运气。
// from model binder
Request.Content.LoadIntoBufferAsync().Wait();
var formData = Request.Content.ReadAsFormDataAsync().Result;
// from filter
var formData = Request.Content.ReadAsFormDataAsync().Result;
答案 0 :(得分:1)
问题是内容的底层缓冲区是只能读取一次的仅向前流。
为什么需要阅读两次?更多的背景会有所帮助。是你正在阅读两个独立的过滤器吗?
编辑:可能会尝试直接从MS_HttpContext中读取并将其用作您的内容流(不要认为这在自托管环境中有效)。
using (var s = new System.IO.MemoryStream()) {
var ctx = (HttpContextBase)actionContext.Request.Properties["MS_HttpContext"];
ctx.Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
ctx.Request.InputStream.CopyTo(s); var body =
System.Text.Encoding.UTF8.GetString(s.ToArray());
}
答案 1 :(得分:0)
你真的不应该这样做。在一天结束时,HttpContext
Stream指向Web API读取的相同流。
你可以尝试将LoadIntoBufferAsync
放在两个地方,因为一个人可以在另一个地方之前触发它已经在缓冲区中,调用LoadIntoBufferAsync
没有副作用。
// from model binder
Request.Content.LoadIntoBufferAsync().Wait();
var formData = Request.Content.ReadAsFormDataAsync().Result;
// from filter
Request.Content.LoadIntoBufferAsync().Wait();
var formData = Request.Content.ReadAsFormDataAsync().Result;
答案 2 :(得分:0)
在开发REST API期间,我们需要在允许在控制器内处理响应之前对请求进行身份验证,因此这需要能够读取标头和表单(如果有的话)确定是否将凭证传递到表单正文中的请求而不是通过请求标头。
几行代码将流指针重置为流的开头,以便MVC能够读取表单并在控制器中填充视图模型
public class WebServiceAuthenticationAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
var authenticationHeaderValue = actionContext.Request.Headers.Authorization;
try
{
if (authenticationHeaderValue != null)
{
var webRequestInfo = new WebRequestInfo(actionContext.Request.Method, actionContext.Request.RequestUri);
this.AuthenticationHeaderService.LogOnUsingAuthenticationHeader(authenticationHeaderValue, webRequestInfo);
}
else if (actionContext.Request.Content.IsFormData())
{
Task<NameValueCollection> formVals = actionContext.Request.Content.ReadAsFormDataAsync();
this.AuthenticationFormService.LogOnUsingFormsAuthentication(formVals.Result);
// reset the underlying stream to the beginning so that others may use it in the future...
using (var s = new System.IO.MemoryStream())
{
var ctx = (HttpContextBase) actionContext.Request.Properties["MS_HttpContext"];
ctx.Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
}
}
catch (Exception)
{
throw;
}
}
}
最初,MVC没有创建数据模型,并且将null传递给控制器方法。重置流后,MVC能够读取表单,创建并填充数据模型,并将其传递给控制器方法。
[WebServiceAuthentication]
public HttpResponseMessage Get(DocumentRequestModel requestForm)
{
var response = CreateResponse(HttpStatusCode.OK);
response.Content = new ByteArrayContent(this.documentService.GetDocument(requestForm.DocumentId.ToString()));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
}