Existe uma maneira de forçar a API da Web do ASP.NET a retornar texto sem formatação?

125

Preciso receber uma resposta em texto sem formatação de um controlador de API da Web do ASP.NET.

Eu tentei fazer uma solicitação com, Accept: text/plainmas parece não funcionar. Além disso, o pedido é externo e está fora de meu controle. O que eu realizaria é imitar a maneira antiga do ASP.NET:

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

Alguma ideia?

EDIT, solução : com base na resposta de Aliostad, adicionei o formatador de texto WebAPIContrib e o inicializei no Application_Start:

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

e meu controlador acabou algo como:

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

Respostas:

231

Hmmm ... não acho que você precise criar um formatador personalizado para fazer isso funcionar. Em vez disso, retorne o conteúdo assim:

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

Isso funciona para mim sem usar um formatador personalizado.

Se você deseja criar explicitamente a saída e substituir a negociação de conteúdo padrão com base em Aceitar cabeçalhos, não será necessário usá- Request.CreateResponse()la porque força o tipo MIME.

Em vez disso, crie explicitamente um novo HttpResponseMessagee atribua o conteúdo manualmente. O exemplo acima usa, StringContentmas existem várias outras classes de conteúdo disponíveis para retornar dados de vários tipos / estruturas de dados .NET.

Rick Strahl
fonte
1
Essa é, de fato, a solução que eu busquei porque minha API retornaria objetos JSON para 99% de todos os métodos, apenas alguns (muito poucos) métodos precisariam de respostas simples de cadeia de caracteres (e para muitos deles eu uso um MemoryStream para retornar dados diretamente na resposta, para que não fosse um problema.) Somente em 2 ou 3 métodos retornei uma string .NET e estava sendo retornada como uma string JSON. Sua resposta, IMHO, é a resposta do KISS para esse problema (embora não seja 100% SECO, mas eu acabei de escrever um método de extensão para string para fazer isso ... :-) Bom!) StringContent é muito bom. Obrigado.
Loudenvier
Existem várias classes personalizadas de XXXContent para criar tipos específicos de conteúdo que tornam esse tipo de coisa bastante simples.
Rick Strahl
Eu vejo a resposta correta com essa abordagem. No entanto, HttpContext.Current é nulo agora. Alguma idéia sobre isso?
Nachiket Mehta
@JavascriptEnthusiast - HttpContext.Current é nulo provavelmente porque você é auto-hospedado ou está executando a pilha OWin sem o pipeline System.Web. No entanto, não está relacionado a esta solução.
Rick Strahl
15

Se você está procurando apenas um formatador simples de texto sem adição de dependências adicionais, isso deve ser suficiente.

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ão se esqueça de adicioná-lo à sua configuração de API da Web global.

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

Agora você pode passar objetos de string para

this.Request.CreateResponse(HttpStatusCode.OK, "some text", "text/plain");
Despertar
fonte
12
  • Cuidado para não usar o contexto na API da Web do ASP.NET ou, mais cedo ou mais tarde, desculpe-se. A natureza assíncrona da API da Web do ASP.NET torna o uso de HttpContext.Currentuma responsabilidade.
  • Use um formatador de texto sem formatação e adicione-o aos seus formatadores. Existem dezenas deles por aí. Você pode até escrever o seu facilmente. WebApiContrib tem um.
  • Você pode forçá-lo, definindo o cabeçalho tipo de conteúdo sobre httpResponseMessage.Headersa text/plainem seu controlador desde que você tenha registrado formatador de texto simples.
Aliostad
fonte
Não se preocupe, eu nem implícita nem a intenção de usar o objeto HttpContext, eu adicionei-lo para ilustrar como se poderia fazê-lo em ASP.NET clássico
Magnus Johansson
Bem, waddayknow, eu já tinha o WebAPIContrib referenciado, às vezes é simples.
Magnus Johansson
@Magnus Sure. Na verdade, mudei a redação depois de ler o que havia escrito. Mas ler outra resposta me fez enfatizar esse primeiro ponto.
Aliostad
Você está dizendo para não usar HttpContext.Current, quais são as alternativas?
surya
@spiderdevil sim, é absolutamente o que estou dizendo. Você não precisa, passe solicitação / resposta / configuração diretamente.
Aliostad 9/08/13
6

Quando Accept: text / plain não funciona, não há formatador registrado para tipos de mímica de texto.

Você pode garantir que não haja formatadores para o tipo MIME especificado, obtendo a lista de todos os formatadores suportados na configuração do serviço.

Crie um formatador de tipo de mídia muito simples que suporte tipos de mímica de texto.

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

Regfor
fonte
Gostaria de poder aceitar sua resposta também, a resposta aceita me salvou o trabalho de escrever meu próprio formatador. +1 pelo menos.
21412 Magnus Johansson
0

Uma extensão como a seguinte pode reduzir o número de linhas e embelezar seu código:

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


Agora você pode consumir a extensão definida no seu Web API:

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


Ao rotear, {DOMAIN}/api/Home/Indexvocê pode ver o seguinte texto sem formatação:

MyPlainTextResponse

Siyavash Hamdi
fonte
Não desperdice o espaço de nomes da string com coisas não relacionadas à string.
Rambalac