Есть ли способ заставить веб-API ASP.NET возвращать простой текст?

125

Мне нужно получить ответ в виде обычного текста от контроллера веб-API ASP.NET.

Я попытался сделать запрос, Accept: text/plainно, похоже, это не помогло. Кроме того, запрос внешний и неподвластный мне. Я хотел бы имитировать старый способ ASP.NET:

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

Любые идеи?

РЕДАКТИРОВАТЬ, решение : на основе ответа Aliostad я добавил средство форматирования текста WebAPIContrib , инициализировало его в Application_Start:

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

и мой контроллер закончился примерно так:

[HttpGet, HttpPost]
public HttpResponseMessage GetPlainText()
{
  return ControllerContext.Request.CreateResponse(HttpStatusCode.OK, "Test data", "text/plain");
}
Магнус Йоханссон
источник

Ответы:

231

Хммм ... Я не думаю, что вам нужно создавать специальный модуль форматирования, чтобы это работало. Вместо этого верните такой контент:

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

У меня это работает без использования специального форматера.

Если вы явно хотите создать вывод и переопределить согласование содержимого по умолчанию на основе заголовков Accept, вы не захотите использовать, Request.CreateResponse()потому что это принудительно устанавливает тип mime.

Вместо этого явно создайте новый HttpResponseMessageи назначьте содержимое вручную. В приведенном выше примере используется, StringContentно существует довольно много других классов содержимого, которые могут возвращать данные из различных типов / структур данных .NET.

Рик Страл
источник
1
Фактически это решение, к которому я пошел, потому что мой API будет возвращать объекты JSON в 99% всех методов, только несколько (очень немногих) методов потребуют простых строковых ответов (и для многих из них я использую MemoryStream для возврата данных непосредственно в ответе, поэтому это не было проблемой.) Только в 2 или 3 методах я возвращал строку .NET, и она возвращалась как строка JSON. Ваш ответ, IMHO, является ответом KISS на эту проблему (хотя он не на 100% DRY, но я просто написал для этого метод расширения для строки ... :-) Приятно!) StringContent очень хорош. Спасибо.
Loudenvier
Существует ряд настраиваемых классов XXXContent для создания определенных типов контента, которые делают подобные вещи довольно простыми.
Rick Strahl
Я вижу правильный ответ при таком подходе. Однако теперь HttpContext.Current имеет значение null. Есть идеи по этому поводу?
Начикет Мехта
@JavascriptEnthusiast - HttpContext.Current, скорее всего, имеет значение NULL, потому что вы используете собственный хостинг или используете стек OWin без конвейера System.Web. Однако не имеет отношения к этому решению.
Rick Strahl
15

Если вы просто ищете простой текстовый форматировщик без добавления дополнительных зависимостей, это должно помочь.

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

Не забудьте добавить его в конфигурацию глобального веб-API.

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

Теперь вы можете передавать строковые объекты в

this.Request.CreateResponse(HttpStatusCode.OK, "some text", "text/plain");
Деспертар
источник
12
  • Будьте осторожны, чтобы не использовать контекст в веб-API ASP.NET, иначе вы рано или поздно пожалеете. Асинхронный характер веб-API ASP.NET делает использованиеHttpContext.Current .
  • Используйте средство форматирования обычного текста и добавьте его в средства форматирования. Их вокруг десятки. Вы даже можете легко написать свой. WebApiContrib есть.
  • Вы можете заставить его установку заголовка типа контента на , httpResponseMessage.Headersчтобы text/plainв вашем контроллере при условии , что вы зарегистрированы простой форматирования текста.
Aliostad
источник
Не волнуйтесь, я не подразумевал и не намеревался использовать объект HttpContext, я просто добавил его, чтобы проиллюстрировать, как это можно сделать в классическом ASP.NET
Магнус Йоханссон
Ну, waddayknow, я уже упоминал WebAPIContrib, иногда это просто.
Magnus Johansson
@ Магнус Конечно. Фактически я изменил формулировку после того, как прочитал то, что написал. Но чтение другого ответа заставило меня подчеркнуть этот первый момент.
Aliostad
Вы говорите не использовать HttpContext.Current, каковы альтернативы?
Surya 09
@spiderdevil: да, это именно то, что я говорю. Вам это не нужно, передайте запрос / ответ / конфигурацию напрямую.
Aliostad
6

Если Accept: text / plain не работает, значит, для текстовых mime-типов не зарегистрировано средство форматирования.

Вы можете убедиться, что для указанного типа MIME нет средств форматирования, получив список всех поддерживаемых средств форматирования из конфигурации службы.

Создайте очень простой форматировщик типов мультимедиа, поддерживающий типы mime текста.

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

Regfor
источник
Жаль, что я тоже не могу принять ваш ответ, принятый ответ избавил меня от необходимости писать собственный форматер. +1 минимум.
Magnus Johansson
0

Расширение, подобное следующему, может уменьшить количество строк и украсить ваш код:

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


Теперь вы можете использовать определенное расширение в своем Web API:

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


При маршрутизации {DOMAIN}/api/Home/Indexвы можете увидеть следующий простой текст:

MyPlainTextResponse

Сияваш Хамди
источник
Не тратьте зря пространство имен строк на вещи, не связанные со строкой.
Rambalac