how to post plain text to ASP.NET Web API endpoint?

﹥>﹥吖頭↗ 提交于 2019-11-27 19:18:31

Actually it's a shame that web API doesn't have a MediaTypeFormatter for plain text. Here is the one I implemented. It can also be used to Post content.

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

You need to "register" this formatter in your HttpConfig by something like that:

config.Formatters.Insert(0, new TextMediaTypeFormatter());
Kiran Challa

Since Web API doesn't have out of box formatter for handling text/plain, some options:

  1. Modify your action to have no parameters... reason is having parameters triggers request body de-serialization. Now you can read the request content explicitly by doing await Request.Content.ReadAsStringAsync() to get the string

  2. Write a custom MediaTypeFormatter to handle 'text/plain'... it's actually simple to write in this case and you could keep the parameters on the action.

Purified version using of gwenzek's formatter employing async/await:

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

Please note I intentionally do not dispose StreamReader/StreamWriter, as this will dispose underlying streams and break Web Api flow.

To make use of it, register while building HttpConfiguration:

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

In ASP.NET Core 2.0 you simply do the following :-

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

      // Do something else

      return Ok(plainText);
}

In some situations it might be simpler to let the JsonMediaTypeFormatter let do the work:

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" ) );
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!