web-dev-qa-db-de.com

Kann keine Körperdaten von der Web-API lesen POST

Ich versuche, einige Daten aus einer Anfrage in der neuen Asp.Net-Web-API zu extrahieren. Ich habe ein Handler-Setup wie folgt:

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

Dies ist meine http-Anfrage:

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

das Problem ist, dass es immer leer ist, egal wie ich versuche, die Informationen von request.Content zu lesen. ich habe es versucht

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

ebenso gut wie

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

Keine, wenn es funktioniert. Ich kann die Daten nicht aus dem Körper bekommen. Ich hoste in IIS unter Windows 7 und verwende Fiddler, um die Anfrage zu senden. Was mache ich falsch?

13
Micah

Das Problem ist, dass mit der Web-API der Text nur einmal gelesen werden kann. Ich hatte ein HTTP-Modul, das alle Details der Anfrage aufzeichnete und den Text durchlas.

20
Micah

Es ist hässlich, aber Sie scheinen von Anfang an zu basteln, dass Sie tatsächlich den Inhalt in DelegatingHandler ersetzen können ...

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

Ich habe keine Ahnung, ob dies eine gute oder eine schlechte Form ist (verdächtige schlechte Form), aber ... es scheint zu funktionieren und folgt dem Modell, das ich für diejenigen empfohlen habe, die Anforderungsheader und -inhalte "auf dem Weg in" mit ändern müssen ein DelegatingHandler.

Ihr Kilometerstand kann erheblich variieren.

7
brmore

Ich habe meine Antwort auf Brmores Code gestützt.

Diese Funktion kann den Inhalt in jedem Handler sicher lesen

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;
}
6
ulmer-morozov

Das funktioniert bei mir.

[HttpPost]
public IHttpActionResult Index(HttpRequestMessage request)
{
    var form = request.Content.ReadAsFormDataAsync().Result;
    return Ok();
}
2
Barbaros Alp

Sie können zuerst einen Anbieter erstellen. MultipartMemoryStreamProvider() then Request.Content.ReadAsMultipartAsync(provider); dann lies den inhalt

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);
    }
}
0
Johnny Chu

Ich hatte das gleiche Problem und entschied mich schließlich, keinen Inhalt in die Protokolle zu schreiben. Ich lebe mit der Protokollierung von Content-Type und Content-Length.

Es ist jedoch immer eine gute Idee, den gesamten Inhalt so weit wie möglich in die Protokolle zu schreiben.

Aber wie es scheint, können wir dies mit WebApi derzeit nicht erreichen.

0
Sando