25

TransferMode.StreamedHttpSelfHostConfigurationexeでWebApiを使用してプロキシを作成しています。

fiddlerを使用してApiControllerに投稿すると、何らかの理由でRequest.Contentを読み取ることができません-データを投稿した場合でも「」が返されます

public class ApiProxyController : ApiController
{

    public Task<HttpResponseMessage> Post(string path)
    {
        return Request.Content.ReadAsStringAsync().ContinueWith(s =>
        {
            var content = new StringContent(s.Result); //s.Result is ""
                CopyHeaders(Request.Content.Headers, content.Headers);
            return Proxy(path, content);
        }).Unwrap();
    }

    private Task<HttpResponseMessage> Proxy(string path, HttpContent content)
    {
        ...
    }
}

これが私のウェブリクエストです

POST http://localhost:3001/api/values HTTP/1.1
Host: localhost:3001
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Type: application/json
Content-Length: 26

{ "text":"dfsadfsadfsadf"}

私が間違っていることは何ですか?s.Resultが生のjsonではなく空の文字列として返されるのはなぜですか?

4

10 に答える 10

35

私もこれに苦労しました。ReadAsStringAsyncタスクオブジェクトをReadAsAsync返します。プロパティを参照するとResult、コンテンツが返されます。Resultプロパティを参照していると、非同期読み取り要求がブロックされる可能性があります。

例:

string str = response.Content.ReadAsStringAsync().Result;
于 2012-09-05T15:13:05.103 に答える
20

これは古くて答えられていると思いますが、それだけの価値があるので、使用できない理由はReadAsStringAsync()、提案されているように「データを食べる」ためではなく、コンテンツがストリームとして処理されているためです。データはメッセージフォーマッタによって消費されているため、ストリームの位置はすでに終了しています。

使用するにReadAsStringAsync()は、最初にコンテンツストリームの位置を最初にリセットする必要があります。

私は次のようにします。response.RequestMessage.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin )私はHttpResponseMessageしか持っていないので、HttpRequestMessageに直接アクセスできる場合(コントローラー内で行うように)、Request.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin )機能的に同等であると思います。

後期編集

上記のように非同期ストリームを読み取るResultと、さまざまな状況でデッドロックとスレッドのブロックが発生します。非同期ストリームから同期的に読み取る必要がある場合は、次の形式を使用することをお勧めします。

 new TaskFactory( CancellationToken.None, 
                  TaskCreationOptions.None, 
                  TaskContinuationOptions.None, 
                  TaskScheduler.Default )
      .StartNew<Task<TResult>>( func )
      .Unwrap<TResult>()
      .GetAwaiter()
      .GetResult();

実行する非同期アクションはどこfuncにあるので、この場合は次のようになりasync () => { await Request.Content.ReadAsStreamAsync(); }ます…このようにして、メソッドの非同期パーツをパーツ内に配置StartNewし、同期コードにマーシャリングするときに発生する例外を適切にアンラップできます。

さらに良いことに、スタック全体を非同期にします。

于 2016-01-14T09:59:57.717 に答える
18

この投稿の署名は、投稿データを消費します。

public HttpResponseMessage Post([FromBody]string postdata)

次のように変更します。

public HttpResponseMessage Post()

次に、この呼び出しは投稿データを取得するために正常に機能します。

string str = response.Content.ReadAsStringAsync().Result;

自分でテストしました。最初の署名を使用します。strは空です。2番目のstrには投稿データがあります。

于 2014-06-27T04:20:59.997 に答える
5

あなたはApiControllerがRequest.Contentを食べていることについて正しいと思います。ApiControllerに表示される「Request」オブジェクトは、実際にはSystem.Net.Http.HttpRequestMessageタイプです。この問題を回避することはできましたが、次のようにSystem.Web.HttpRequestオブジェクトにバックアップしました。

Dim content as string
If HttpContext.Current.Request.InputStream.CanSeek Then
    HttpContext.Current.Request.InputStream.Seek(0, IO.SeekOrigin.Begin)
End If
Using reader As New System.IO.StreamReader(HttpContext.Current.Request.InputStream)
    content = reader.ReadToEnd()
End Using

シーク巻き戻しが必要かどうかはわかりませんが、念のため入れておきます。

于 2013-05-08T21:04:41.043 に答える
4

最終的には、ApiControllerの代わりにベースインターフェイスから継承することでこれを機能させました-ApiControllerは、応答を食いつぶしていたモデルバインディングだったと思います

編集:プロキシを構築するための正しいことは、ApiControllerではなくMessageHandlerです

于 2012-04-16T21:44:54.883 に答える
2
  1. Request.Content.ReadAsStreamAsync()。Result.Seek(0、System.IO.SeekOrigin.Begin)
  2. new System.IO.StreamReader(Request.Content.ReadAsStreamAsync()。Result).ReadToEnd()
于 2017-11-16T12:30:41.217 に答える
1

ここでの回答へのこの遅い追加は、WebAPIからPOSTデータを読み取る方法を示しています。

string postData;
using (var stream = await request.Content.ReadAsStreamAsync())
{
    stream.Seek(0, SeekOrigin.Begin);
    using (var sr = new StreamReader(stream))
    {
        postData = await sr.ReadToEndAsync();
    }
}
于 2019-12-31T20:07:39.800 に答える
0

引数には複合型を使用する必要があります。次に、本文で次のようなjsonを使用します。

{パス: "c:..."}

アルスは

コンテンツタイプ:application / json; charset = UTF-8

投稿リクエストのヘッダー。これにより、WebAPIはjsonが本文に含まれていることを認識します。

于 2012-11-30T10:38:43.877 に答える
0

に置き換えReadAsStringAsync()てみてくださいReadAsAsync<string>()

于 2012-04-16T20:18:19.737 に答える
0

ReadAsStringAsyncの代わりにCopyToAsyncを使用してみてください。問題が解決するようです。

var ms = new MemoryStream();
await response.Content.CopyToAsync(ms);
ms.Seek(0, SeekOrigin.Begin);

var sr = new StreamReader(ms);
responseContent = sr.ReadToEnd();
于 2021-04-27T08:55:31.893 に答える