Gibt es eine Möglichkeit, die ASP.NET-Web-API zu zwingen, einfachen Text zurückzugeben?

125

Ich muss eine Antwort von einem ASP.NET-Web-API-Controller im Klartext zurückerhalten.

Ich habe versucht, eine Anfrage mit zu machen, Accept: text/plainaber es scheint nicht den Trick zu tun. Außerdem ist die Anfrage extern und außerhalb meiner Kontrolle. Was ich erreichen würde, ist die alte ASP.NET-Methode nachzuahmen:

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

Irgendwelche Ideen?

BEARBEITEN, Lösung : Basierend auf Aliostads Antwort habe ich den WebAPIContrib- Textformatierer hinzugefügt und ihn im Application_Start initialisiert:

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

und mein Controller endete so etwas wie:

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

Antworten:

231

Hmmm ... Ich glaube nicht, dass Sie einen benutzerdefinierten Formatierer erstellen müssen, damit dies funktioniert. Geben Sie den Inhalt stattdessen folgendermaßen zurück:

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

Dies funktioniert bei mir ohne Verwendung eines benutzerdefinierten Formatierers.

Wenn Sie explizit eine Ausgabe erstellen und die Standardaushandlung von Inhalten basierend auf Accept-Headern überschreiben möchten, möchten Sie diese nicht verwenden, Request.CreateResponse()da dadurch der MIME-Typ erzwungen wird.

Erstellen Sie stattdessen explizit eine neue HttpResponseMessageund weisen Sie den Inhalt manuell zu. Im obigen Beispiel werden StringContentjedoch einige andere Inhaltsklassen verwendet, um Daten aus verschiedenen .NET-Datentypen / -strukturen zurückzugeben.

Rick Strahl
quelle
1
Dies ist in der Tat die Lösung, für die ich mich entschieden habe, da meine API JSON-Objekte an 99% aller Methoden zurückgeben würde, nur wenige (sehr wenige) Methoden einfache Zeichenfolgenantworten benötigen würden (und für viele von ihnen verwende ich einen MemoryStream, um Daten zurückzugeben direkt in der Antwort, es war also kein Problem.) Nur in 2 oder 3 Methoden habe ich eine .NET-Zeichenfolge zurückgegeben, und sie wurde als JSON-Zeichenfolge zurückgegeben. Ihre Antwort, IMHO, ist die KISS-Antwort für dieses Problem (obwohl es nicht 100% trocken ist, aber ich habe gerade eine Erweiterungsmethode für den String geschrieben, um das zu tun ... :-) Schön!) StringContent ist sehr nett. Danke dir.
Loudenvier
Es gibt eine Reihe von benutzerdefinierten XXXContent-Klassen, um bestimmte Arten von Inhalten zu erstellen, die diese Art von Dingen ziemlich einfach machen.
Rick Strahl
Ich sehe die richtige Antwort mit diesem Ansatz. HttpContext.Current ist jetzt jedoch null. Irgendwelche Ideen dazu?
Nachiket Mehta
@JavascriptEnthusiast - HttpContext.Current ist höchstwahrscheinlich null, da Sie sich selbst hosten oder den OWin-Stack ohne die System.Web-Pipeline ausführen. Unabhängig von dieser Lösung.
Rick Strahl
15

Wenn Sie nur nach einem einfachen Nur / Text-Formatierer suchen, ohne zusätzliche Abhängigkeiten hinzuzufügen, sollte dies den Trick tun.

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

Vergessen Sie nicht, es Ihrer globalen Web-API-Konfiguration hinzuzufügen.

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

Jetzt können Sie Zeichenfolgenobjekte an übergeben

this.Request.CreateResponse(HttpStatusCode.OK, "some text", "text/plain");
Despertar
quelle
12
  • Bitte achten Sie darauf, keinen Kontext in der ASP.NET-Web-API zu verwenden. Andernfalls wird es Ihnen früher oder später leid tun. Die asynchrone Natur der ASP.NET-Web-API macht die Verwendung HttpContext.Currenteiner Haftung.
  • Verwenden Sie einen Nur-Text-Formatierer und fügen Sie ihn Ihren Formatierern hinzu. Es gibt Dutzende von ihnen. Sie könnten sogar Ihre leicht schreiben. WebApiContrib hat eine.
  • Sie können es erzwingen , indem Sie den Inhaltstyp - Header Einstellung auf , httpResponseMessage.Headersum text/plainin Ihrem Controller vorausgesetzt , Sie Klartextformatierungsprogramm registriert haben.
Aliostad
quelle
Keine Sorge, ich habe weder impliziert noch beabsichtigt, das HttpContext-Objekt zu verwenden. Ich habe es nur hinzugefügt, um zu veranschaulichen, wie man es im klassischen ASP.NET machen würde
Magnus Johansson
Nun, waddayknow, ich hatte bereits WebAPIContrib referenziert, manchmal ist es einfach.
Magnus Johansson
@ Magnus Sicher. Tatsächlich habe ich den Wortlaut geändert, nachdem ich gelesen hatte, was ich geschrieben hatte. Aber als ich eine andere Antwort las, betonte ich diesen ersten Punkt.
Aliostad
Sie sagen, HttpContext.Current nicht zu verwenden. Was sind die Alternativen?
Surya
@ Spiderdevil ja, es ist absolut das, was ich sage. Sie sollten es nicht benötigen, übergeben Sie Anfrage / Antwort / Konfiguration direkt.
Aliostad
6

Wenn Accept: text / plain nicht funktioniert, gibt es keinen registrierten Formatierer für Text-Mime-Typen.

Sie können sicherstellen, dass für den angegebenen MIME-Typ keine Formatierer vorhanden sind, indem Sie eine Liste aller unterstützten Formatierer aus der Dienstkonfiguration abrufen.

Erstellen Sie einen sehr einfachen Medientyp-Formatierer, der Text-Mime-Typen unterstützt.

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

Regfor
quelle
Ich wünschte, ich könnte auch Ihre Antwort akzeptieren, die akzeptierte Antwort ersparte mir die Mühe, meinen eigenen Formatierer zu schreiben. +1 mindestens.
Magnus Johansson
0

Eine Erweiterung wie die folgende kann die Anzahl der Zeilen reduzieren und Ihren Code verschönern:

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


Jetzt können Sie die definierte Erweiterung in Ihrem Web API:

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


Durch das Weiterleiten sehen {DOMAIN}/api/Home/IndexSie den folgenden Klartext:

MyPlainTextResponse

Siyavash Hamdi
quelle
Verschwenden Sie keinen String-Namespace mit Dingen, die nichts mit String zu tun haben.
Rambalac