2013-08-27 62 views
3

我面临的情况是,我必须从ASP.NET Web API的传入请求中读取表单数据两次(从模型联编程序和筛​​选器)。我试过使用LoadIntoBufferAsync,但没有运气。调用ReadAsFormDataAsync两次

// from model binder 
Request.Content.LoadIntoBufferAsync().Wait(); 
var formData = Request.Content.ReadAsFormDataAsync().Result; 

// from filter 
var formData = Request.Content.ReadAsFormDataAsync().Result; 
+0

将有助于创建一个repro。 – Aliostad

回答

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()); 
} 
+0

感谢您回答Alex。我正在阅读模型粘合剂和过滤器。 – VJAI

+0

也许你可以直接从HttpContext中读取 - 我不认为它可以在自己托管的场景中工作。我会在我的答案中添加一些代码。 – AlexGad

+0

我在上面添加了一些代码,也许你在你的过滤器中使用它,然后阅读模型联编程序中的内容?如果上述不起作用,我认为你也可以直接寻找底层缓冲区。 – AlexGad

0

你真的不应该这样做。在一天结束时,HttpContext流指向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; 
+0

你可以发布代码吗? – VJAI

+0

@Mark我刚刚做到了。 – Aliostad

+0

今天到办公室时我会试试这个。 – VJAI

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