web-dev-qa-db-ja.com

ASP.NET Web APIエンドポイントにプレーンテキストを投稿する方法は?

次のように定義されたコントローラーアクションを持つASP.NET Web APIエンドポイントがあります。

[HttpPost]
public HttpResponseMessage Post([FromBody] object text)

リクエスト後の本文にプレーンテキストが含まれている場合(つまり、json、xml、またはその他の特別な形式として解釈されるべきではない)、次のヘッダーをリクエストに含めることができると考えました:

Content-Type: text/plain

しかし、私はエラーを受け取ります:

No MediaTypeFormatter is available to read an object of type 'Object' from content with media type 'text/plain'.

コントローラーアクションメソッドのシグネチャを次のように変更した場合:

[HttpPost]
public HttpResponseMessage Post([FromBody] string text)

私はわずかに異なるエラーメッセージが表示されます:

No MediaTypeFormatter is available to read an object of type 'String' from content with media type 'text/plain'.
35
BaltoStar

実際、プレーンテキスト用のMediaTypeFormatterがWeb APIにないのは残念です。これが私が実装したものです。コンテンツの投稿にも使用できます。

public class TextMediaTypeFormatter : MediaTypeFormatter
{
    public TextMediaTypeFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
    }

    public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
    {
        var taskCompletionSource = new TaskCompletionSource<object>();
        try
        {
            var memoryStream = new MemoryStream();
            readStream.CopyTo(memoryStream);
            var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
            taskCompletionSource.SetResult(s);
        }
        catch (Exception e)
        {
            taskCompletionSource.SetException(e);
        }
        return taskCompletionSource.Task;
    }

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, System.Net.TransportContext transportContext, System.Threading.CancellationToken cancellationToken)
    {
        var buff = System.Text.Encoding.UTF8.GetBytes(value.ToString());
        return writeStream.WriteAsync(buff, 0, buff.Length, cancellationToken);
    }

    public override bool CanReadType(Type type)
    {
        return type == typeof(string);
    }

    public override bool CanWriteType(Type type)
    {
        return type == typeof(string);
    }
}

次のような方法で、HttpConfigでこのフォーマッターを「登録」する必要があります。

config.Formatters.Insert(0, new TextMediaTypeFormatter());
58
gwenzek

Web APIにはtext/plainを処理するためのすぐに使えるフォーマッターがないため、いくつかのオプションがあります。

  1. パラメーターを持たないようにアクションを変更してください...理由は、パラメータートリガーが本体の逆シリアル化を要求しているためです。これで、await Request.Content.ReadAsStringAsync()を実行して文字列を取得することで、リクエストの内容を明示的に読み取ることができます

  2. 'text/plain'を処理するカスタムMediaTypeFormatterを作成します。この場合、実際に記述するのは簡単で、アクションのパラメーターを保持できます。

11
Kiran Challa

Async/awaitを使用するgwenzekのフォーマッタを使用した精製バージョン:

public class PlainTextFormatter : MediaTypeFormatter
{
    public PlainTextFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
    }

    public override bool CanReadType(Type type) =>
        type == typeof(string);

    public override bool CanWriteType(Type type) =>
        type == typeof(string);

    public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
    {
        var streamReader = new StreamReader(readStream);
        return await streamReader.ReadToEndAsync();
    }

    public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
    {
        var streamReader = new StreamWriter(writeStream);
        await streamReader.WriteAsync((string) value);
    }
}

I 意図的に破棄しない StreamReader/StreamWriterに注意してください。これにより、基になるストリームが破棄され、Web Apiフローが中断されます。

それを利用するには、HttpConfigurationの構築中に登録します。

protected HttpConfiguration CreateHttpConfiguration()
{
    HttpConfiguration httpConfiguration = new HttpConfiguration();
    ...
    httpConfiguration.Formatters.Add(new PlainTextFormatter());
    ...
    return httpConfiguration;
}
9

ASP.NET Core 2.0では、次のことを行うだけです。

using (var reader = new StreamReader(Request.Body))
{
      string plainText= reader.ReadToEnd();

      // Do something else

      return Ok(plainText);
}
4
Derek

状況によっては、JsonMediaTypeFormatterに作業を任せる方が簡単な場合があります。

var formatter = GlobalConfiguration.Configuration.Formatters.Where(f=>f is System.Net.Http.Formatting.JsonMediaTypeFormatter).FirstOrDefault();
if (!formatter.SupportedMediaTypes.Any( mt => mt.MediaType == "text/plain" ))
    formatter.SupportedMediaTypes.Add( new MediaTypeHeaderValue( "text/plain" ) );
3
mmyta