两次调用ReadAsFormDataAsync

时间:2013-08-27 07:27:47

标签: c# asp.net-web-api

我面临的情况是我要在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;

3 个答案:

答案 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;
}