2013-08-27 4 views
3

ASP.NET 웹 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

재현을 만드는 데 도움이 되겠습니까? – Aliostad

답변

1

문제는 컨텐츠에 대한 기본 버퍼 번만 판독 할 수 순방향 전용 스트림이다.

왜 두 번 읽어야합니까? 조금 더 많은 컨텍스트가 도움이 될 것입니다. 두 개의 개별 필터에서 읽는 것이 맞습니까?

EDIT : 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 스트림은 웹 API에서 읽는 동일한 스트림을 가리 킵니다.

LoadIntoBufferAsync은 부작용이 없으므로 다른 곳으로 트리거 할 수 있고 이미 버퍼에 있었으므로 두 위치에 모두 넣을 수 있습니다.

지내는 API의 개발 기간 동안
// 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

@ 마크 방금했습니다. – Aliostad

+0

오늘 내가 사무실에 도착하면 이것을 시험해 보겠습니다. – VJAI

0

, 우리는 응답이 컨트롤러 내에서 처리 할 수 ​​있도록하기 전에 요청을 인증 할 필요가 있고, 그래서 이것은뿐만 아니라 헤더를 읽을 수 할 필요를 생성 요청 헤더가 아닌 양식 본문 내의 요청에 자격 증명이 전달되었는지 확인하기위한 양식 (있는 경우). 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; 
} 
관련 문제