Existe-t-il un moyen de forcer l'API Web ASP.NET à renvoyer du texte brut?

125

J'ai besoin de récupérer une réponse en texte brut à partir d'un contrôleur API Web ASP.NET.

J'ai essayé de faire une demande avec Accept: text/plainmais cela ne semble pas faire l'affaire. De plus, la demande est externe et hors de mon contrôle. Ce que je ferais, c'est imiter l'ancienne méthode ASP.NET:

context.Response.ContentType = "text/plain";
context.Response.Write("some text);

Des idées?

EDIT, solution : Sur la base de la réponse d'Aliostad, j'ai ajouté le formateur de texte WebAPIContrib , je l' ai initialisé dans le Application_Start:

  config.Formatters.Add(new PlainTextFormatter());

et mon contrôleur a fini par quelque chose comme:

[HttpGet, HttpPost]
public HttpResponseMessage GetPlainText()
{
  return ControllerContext.Request.CreateResponse(HttpStatusCode.OK, "Test data", "text/plain");
}
Magnus Johansson
la source

Réponses:

231

Hmmm ... Je ne pense pas que vous ayez besoin de créer un formateur personnalisé pour que cela fonctionne. Au lieu de cela, retournez le contenu comme ceci:

    [HttpGet]
    public HttpResponseMessage HelloWorld()
    {
        string result = "Hello world! Time is: " + DateTime.Now;
        var resp = new HttpResponseMessage(HttpStatusCode.OK);
        resp.Content = new StringContent(result, System.Text.Encoding.UTF8, "text/plain");
        return resp;
    }

Cela fonctionne pour moi sans utiliser de formateur personnalisé.

Si vous souhaitez explicitement créer une sortie et remplacer la négociation de contenu par défaut basée sur les en-têtes Accepter, vous ne voudrez pas utiliser Request.CreateResponse() car elle force le type mime.

Au lieu de cela, créez explicitement un nouveau HttpResponseMessageet attribuez le contenu manuellement. L'exemple ci-dessus utilise, StringContentmais il existe de nombreuses autres classes de contenu disponibles pour renvoyer des données à partir de divers types / structures de données .NET.

Rick Strahl
la source
1
C'est en fait la solution que j'ai choisie car mon API renverrait des objets JSON à 99% de toutes les méthodes, seules quelques (très peu) méthodes auraient besoin de réponses en chaîne simple (et pour beaucoup de celles que j'utilise un MemoryStream pour renvoyer des données directement dans la réponse, donc ce n'était pas un problème.) Ce n'est que dans 2 ou 3 méthodes que j'ai renvoyé une chaîne .NET, et elle était renvoyée sous forme de chaîne JSON. Votre réponse, à mon humble avis, est la réponse KISS à ce problème (bien que ce ne soit pas 100% DRY, mais je viens d'écrire une méthode d'extension de chaîne pour le faire ... :-) Nice!) StringContent est très agréable. Je vous remercie.
Loudenvier
Il existe un certain nombre de classes XXXContent personnalisées pour créer des types spécifiques de contenu qui rendent ce genre de chose assez simple.
Rick Strahl
Je vois la bonne réponse avec cette approche. Cependant, HttpContext.Current est désormais nul. Des idées à ce sujet?
Nachiket Mehta
@JavascriptEnthusiast - HttpContext.Current est très probablement nul parce que vous vous auto-hébergez ou que vous exécutez via la pile OWin sans le pipeline System.Web. Sans rapport avec cette solution cependant.
Rick Strahl
15

Si vous recherchez simplement un formateur simple / texte sans ajouter de dépendances supplémentaires, cela devrait faire l'affaire.

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

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

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

    public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext transportContext)
    {
        return Task.Factory.StartNew(() => {
            StreamWriter writer = new StreamWriter(stream);
            writer.Write(value);
            writer.Flush();
        });
    }

    public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
    {
        return Task.Factory.StartNew(() => {
            StreamReader reader = new StreamReader(stream);
            return (object)reader.ReadToEnd();
        });
    }
}

N'oubliez pas de l'ajouter à votre configuration globale de l'API Web.

config.Formatters.Add(new TextPlainFormatter());

Vous pouvez maintenant passer des objets chaîne à

this.Request.CreateResponse(HttpStatusCode.OK, "some text", "text/plain");
Despertar
la source
12
  • Veillez à ne pas utiliser de contexte dans l'API Web ASP.NET ou vous le regretterez tôt ou tard. La nature asynchrone de l'API Web ASP.NET rend l'utilisationHttpContext.Current une responsabilité.
  • Utilisez un formateur de texte brut et ajoutez à vos formateurs. Il y en a des dizaines autour. Vous pouvez même écrire le vôtre facilement. WebApiContrib a un.
  • Vous pouvez forcer en définissant l' en- tête de type de contenu sur httpResponseMessage.Headersà text/plainvotre contrôleur vous être inscrit formatter le texte brut.
Aliostad
la source
Ne vous inquiétez pas, je n'ai ni impliqué ni prévu d'utiliser l'objet HttpContext, je l'ai juste ajouté pour illustrer comment on le ferait dans ASP.NET classique
Magnus Johansson
Eh bien, waddayknow, j'ai déjà fait référence à WebAPIContrib, parfois c'est simple.
Magnus Johansson
@Magnus Bien sûr. J'ai en fait changé le libellé après avoir lu ce que j'avais écrit. Mais la lecture d'une autre réponse m'a fait souligner ce premier point.
Aliostad
Vous dites de ne pas utiliser HttpContext.Current, quelles sont les alternatives?
surya
@spiderdevil oui, c'est absolument ce que je dis. Vous ne devriez pas en avoir besoin, passez directement la demande / la réponse / la configuration.
Aliostad
6

Lorsque Accepter: text / plain ne fonctionne pas, alors il n'y a pas de formateur enregistré pour les types MIME de texte.

Vous pouvez vous assurer qu'il n'y a pas de formateurs pour le type mime spécifié en obtenant la liste de tous les formateurs pris en charge à partir de la configuration du service.

Créez un formateur de type de média très simple qui prend en charge les types de texte mime.

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

Regfor
la source
J'aurais aimé pouvoir accepter votre réponse également, la réponse acceptée m'a évité la peine d'écrire mon propre formateur. +1 au moins.
Magnus Johansson
0

Une extension comme celle-ci peut réduire le nombre de lignes et embellir votre code:

public static class CommonExtensions
{
    public static HttpResponseMessage ToHttpResponseMessage(this string str)
    {
        var resp = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(str, System.Text.Encoding.UTF8, "text/plain")
        };

        return resp;
    }
}


Vous pouvez maintenant utiliser l'extension définie dans votre Web API:

public class HomeController : ApiController
{
    [System.Web.Http.HttpGet]
    public HttpResponseMessage Index()
    {
        return "Salam".ToHttpResponseMessage();
    }
}


En acheminant, {DOMAIN}/api/Home/Indexvous pouvez voir le texte brut suivant:

MyPlainTextResponse

Siyavash Hamdi
la source
Ne gaspillez pas l'espace de noms de chaîne avec des éléments sans rapport avec la chaîne.
Rambalac