2012-08-17 11 views
14

Próbuję wyodrębnić niektóre dane z żądania w nowym Asp.Net Web Api. Mam konfiguracji procedury obsługi takiego:Nie można odczytać danych podstawowych z api internetowej POST

public class MyTestHandler : DelegatingHandler 
{ 
    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) 
    { 
     if (request.Content.IsFormData()) 
     { 
      request.Content.ReadAsStreamAsync().ContinueWith(x => { 
       var result = ""; 
       using (var sr = new StreamReader(x.Result)) 
       { 
        result = sr.ReadToEnd(); 
       } 
       Console.Write(result); 
      }); 
     } 

     return base.SendAsync(request, cancellationToken); 
    } 
} 

To moja prośba http:

POST http://127.0.0.1/test HTTP/1.1 
Connection: Keep-Alive 
Content-Length: 29 
Content-Type: application/x-www-form-urlencoded 
Expect: 100-continue 
Host: 127.0.0.1 

my_property=my_value 

problemem jest to, że nie ważne jak próbuję odczytać informacje z request.Content to zawsze pusty. Próbowałem

request.Content.ReadAsStreamAsync 
request.Content.ReadAsFormDataAsync 
request.Content.ReadAs<FormDataCollection> 

jak również

[HttpGet,HttpPost] 
    public string Index([FromBody]string my_property) 
    { 
     //my_property == null 
     return "Test"; 
    } 

None czy działa. Nie mogę pobrać danych z ciała. Hostuję w IIS na Windows 7 i używam Fiddlera do przesłania żądania. Co ja robię źle?

+0

Byłoby pomocne wiedzieć, czy niezależny klient podobny do wcftestclient.exe daje podobne wyniki. –

+0

Próbowałem to uruchomić, ale tak się nie stanie, ponieważ jest napisane, że mój punkt końcowy nie ma żadnych metadanych. – Micah

+0

To wygląda niesamowicie dziwnie. Czy jest jakiś powód, dla którego wybierasz tę metodę transferu danych w ramach dostarczonej metodologii [HttpGet] i [HttpPost]? –

Odpowiedz

20

Problem polega na tym, że w Web Api treść można odczytać tylko raz. Miałem uruchomiony moduł HTTP, który rejestrował wszystkie szczegóły wniosku i czytał treść.

+0

tak, robi tego rodzaju logowania nie jest możliwe, prawda? – kooldave98

+1

Jest to możliwe, najpierw musisz odczytać go w buforze, najpierw używając metody LoadIntoBufferAsync(). To sprawia, że ​​treść jest nadal dostępna dla metody bazowej. Więcej tutaj https://weblogs.asp.net/fredriknormen/log-message-request-and-response-in-asp-net-webapi – Tom

0

Miałem ten sam problem iw końcu zdecydowałem się nie pisać treści w dziennikach. Mieszkam z rejestrowaniem typu treści i długości treści.

Zawsze dobrze jest napisać całą treść w dziennikach tak daleko, jak to możliwe.

Wygląda jednak na to, że obecnie w WebApi nie możemy tego osiągnąć.

7

Jest brzydka, ale wydaje się, od początkowej majsterkowania, że ​​można w rzeczywistości zastąpić zawartość w DelegatingHandler ...

protected override Task SendAsync(
      HttpRequestMessage request, 
      CancellationToken cancellationToken) 
     {      
      Stream stream = new MemoryStream(); 

      request.Content.ReadAsStreamAsync().Result.CopyTo(stream); 
      stream.Seek(0,SeekOrigin.Begin); 

      // copy off the content "for later" 
      string query = new StreamReader(stream).ReadToEnd(); 
      stream.Seek(0,SeekOrigin.Begin); 

      // if further processing depends on content type 
      // go ahead and grab current value 
      var contentType = request.Content.Headers.ContentType; 

      request.Content = new StreamContent(stream); 
      request.Content.Headers.ContentType = contentType; 

      return base.SendAsync(request, cancellationToken); 
    } 

nie mam pojęcia, czy to jest dobre czy złe forma (podejrzany złe), ale ... wydaje się działać i podąża za modelem, który widziałem, zalecanym dla tych, którzy muszą zmodyfikować nagłówki żądań i treść "po drodze" za pomocą opcji DelegatingHandler.

Twój przebieg może się znacznie różnić.

6

Oparłem swoją odpowiedź na kodzie brmore'a;

Funkcja ta może bezpiecznie czytać zawartość w dowolnym obsługi

private string SafeReadContentFrom(HttpRequestMessage request) 
{ 
    var contentType = request.Content.Headers.ContentType; 
    var contentInString = request.Content.ReadAsStringAsync().Result; 
    request.Content = new StringContent(contentInString); 
    request.Content.Headers.ContentType = contentType; 
    return contentInString; 
} 
0

można najpierw utworzyć dostawcę. MultipartMemoryStreamProvider() następnie Request.Content.ReadAsMultipartAsync(provider); następnie przeczytaj treść

public async Task<IHttpActionResult> Post(int id, string type) 
{ 
    // Check if the request contains multipart/form-data. 
    if(!Request.Content.IsMimeMultipartContent("form-data")) 
     return BadRequest("Unsupported media type"); 

    try 
    { 
     var azureManager = new AzureManager(); 
     var imageManager = new ImageManager(); 
     var provider = new MultipartMemoryStreamProvider(); 

     await Request.Content.ReadAsMultipartAsync(provider); 

     var assets = new List<Asset>(); 
     foreach (var file in provider.Contents) 
     { 
      var stream = await file.ReadAsStreamAsync(); 
      var guid = Guid.NewGuid(); 
      string blobName = guid.ToString(); 

      await azureManager.UploadAsync(blobName, stream); 

      var asset = new Asset 
      { 
       PropertyId = id, 
       FileId = guid, 
       FileName = file.Headers.ContentDisposition.FileName.Trim('\"').ToLower(), 
       FileSize = file.Headers.ContentLength ?? 0, 
       MimeType = file.Headers.ContentType.MediaType.ToLower() 
      }; 

      if (type == "photos") 
      { 
       asset.Type = AssetType.Photo; 

       // Resize and crop copies to 16:9 
       using (MemoryStream thumb = imageManager.ResizeImage(stream, 320, 180)) 
       { 
        await azureManager.UploadAsync(blobName, thumb, BlobContainers.Thumbs); 
       } 
       using (MemoryStream photo = imageManager.ResizeImage(stream, 1024, 576)) 
       { 
        await azureManager.UploadAsync(blobName, photo, BlobContainers.Photos); 
       } 
      } 
      else 
       asset.AssumeType(); 

      assets.Add(asset); 
     } 

     db.Assets.AddRange(assets); 
     await db.SaveChangesAsync(); 

     return Ok(new { Message = "Assets uploaded ok", Assets = assets }); 
    } 
    catch (Exception ex) 
    { 
     return BadRequest(ex.GetBaseException().Message); 
    } 
} 
2

To działa dla mnie.

[HttpPost] 
public IHttpActionResult Index(HttpRequestMessage request) 
{ 
    var form = request.Content.ReadAsFormDataAsync().Result; 
    return Ok(); 
} 
Powiązane problemy