web-dev-qa-db-fra.com

comment publier du texte brut sur le point de terminaison de l'API Web ASP.NET?

J'ai un point de terminaison d'API Web ASP.NET avec l'action du contrôleur définie comme suit:

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

Si mon corps de demande de publication contient du texte brut (c'est-à-dire ne doit pas être interprété comme json, xml ou tout autre format spécial), j'ai pensé que je pourrais simplement inclure l'en-tête suivant à ma demande:

Content-Type: text/plain

Cependant, je reçois une erreur:

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

Si je change la signature de ma méthode d'action de contrôleur en:

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

Je reçois un message d'erreur légèrement différent:

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

En fait, c'est dommage que l'API Web n'ait pas de MediaTypeFormatter pour le texte brut. Voici celui que j'ai implémenté. Il peut également être utilisé pour publier du contenu.

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

Vous devez "enregistrer" ce formateur dans votre HttpConfig par quelque chose comme ça:

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

Étant donné que l'API Web ne dispose pas d'un formateur prêt à l'emploi pour la gestion de texte/brut, certaines options:

  1. Modifiez votre action pour ne pas avoir de paramètres ... la raison est que les déclencheurs de paramètres demandent la désérialisation du corps. Vous pouvez maintenant lire le contenu de la requête de manière explicite en faisant await Request.Content.ReadAsStringAsync() pour obtenir la chaîne

  2. Écrivez un MediaTypeFormatter personnalisé pour gérer 'text/plain' ... c'est en fait simple à écrire dans ce cas et vous pouvez conserver les paramètres de l'action.

11
Kiran Challa

Version purifiée utilisant le formateur de gwenzek utilisant 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);
    }
}

Veuillez noter que je ne pas disposer intentionnellement StreamReader/StreamWriter, car cela supprimera les flux sous-jacents et interrompra le flux Web Api.

Pour en faire usage, inscrivez-vous lors de la construction de HttpConfiguration:

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

Dans ASP.NET Core 2.0, vous procédez simplement comme suit: -

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

      // Do something else

      return Ok(plainText);
}
4
Derek

Dans certaines situations, il peut être plus simple de laisser le JsonMediaTypeFormatter faire le travail:

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