Подтвердить что ты не робот

Как отправить обычный текст в конечную точку веб-API ASP.NET?

У меня есть конечная точка веб-API ASP.NET с действием контроллера, определенным следующим образом:

[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'.
4b9b3361

Ответ 1

На самом деле стыдно, что веб-API не имеет MediaTypeFormatter для обычного текста. Вот тот, который я реализовал. Он также может использоваться для публикации содержимого.

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

Ответ 2

Поскольку Web API не имеет готового форматера для обработки текста/простого текста, некоторые параметры:

  1. Измените ваше действие, чтобы оно не имело параметров... причина в том, что параметры запускают десериализацию тела запроса. Теперь вы можете явно прочитать содержимое запроса, выполнив await Request.Content.ReadAsStringAsync() чтобы получить строку

  2. Напишите собственный MediaTypeFormatter для обработки 'text/plain'... на самом деле это просто написать в этом случае, и вы можете сохранить параметры в действии.

Ответ 3

Очищенная версия с использованием форматирования gwenzek с использованием async/wait:

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

Обратите внимание, что я намеренно не размещаю StreamReader/StreamWriter, так как это будет уничтожать базовые потоки и прерывать поток Web Api.

Чтобы использовать его, зарегистрируйтесь при построении HttpConfiguration:

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

Ответ 4

В ASP.NET Core 2.0 вы просто делаете следующее:

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

      // Do something else

      return Ok(plainText);
}

Ответ 5

В некоторых ситуациях было бы проще позволить 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" ) );