Como forçar o ASP.NET Web API a sempre retornar JSON?

103

ASP.NET Web API faz negociação de conteúdo por padrão - retornará XML ou JSON ou outro tipo com base no Acceptcabeçalho. Eu não preciso / quero isso, há uma maneira (como um atributo ou algo assim) para dizer à API Web para sempre retornar JSON?

Borek Bernard
fonte
Você pode fazer isso removendo todos os formatadores, exceto json deGlobalConfiguration.Configuration.Formatters
Claudio Redi

Respostas:

75

Compatível apenas com JSON na API da Web ASP.NET - A MANEIRA CORRETA

Substitua IContentNegotiator por JsonContentNegotiator:

var jsonFormatter = new JsonMediaTypeFormatter();
//optional: set serializer settings here
config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter));

Implementação JsonContentNegotiator:

public class JsonContentNegotiator : IContentNegotiator
{
    private readonly JsonMediaTypeFormatter _jsonFormatter;

    public JsonContentNegotiator(JsonMediaTypeFormatter formatter) 
    {
        _jsonFormatter = formatter;    
    }

    public ContentNegotiationResult Negotiate(
            Type type, 
            HttpRequestMessage request, 
            IEnumerable<MediaTypeFormatter> formatters)
    {
        return new ContentNegotiationResult(
            _jsonFormatter, 
            new MediaTypeHeaderValue("application/json"));
    }
}
Dmitry Pavlov
fonte
4
onde a primeira parte do código é cortada e colada também? Não vejo um objeto "config" em meu Global.asax. De onde vem essa variável? o artigo também não explica.
BuddyJoe
3
Verifique o método public static void Register (HttpConfiguration config) {...} no arquivo WebApiConfig.cs que foi gerado por VS2012 na criação do projeto
Dmitry Pavlov
Isso forçará o JSON no sentido de que um cliente AcceptXML obterá JSON e não 406 ?
Luke Puplett
1
Posso responder ao meu próprio comentário / pergunta: retorna XML independentemente do Acceptcabeçalho.
Luke Puplett
2
Isso quebra minha integração com o swashbuckle e parece que está relacionado a esse problema no github ( github.com/domaindrivendev/Swashbuckle/issues/219 ). Eu gostaria de usar este método, mas o que está abaixo GlobalConfiguration...Clear()realmente funciona.
seangwright
167

Limpe todos os formatadores e adicione o formatador Json de volta.

GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());

EDITAR

Eu adicionei para Global.asaxdentro Application_Start().

Filip W
fonte
e em qual arquivo .. ?? global.ascx .. ??
shashwat de
Em seu método Application_Start ()
Jafin
6
Filip W acabou de melhorar agora :), veja aqui strathweb.com/2013/06/…
Tien Do
7
@TienDo - com link para o blog do próprio Filip?
Phill
10

Philip W teve a resposta certa, mas para maior clareza e uma solução de trabalho completa, edite seu arquivo Global.asax.cs para ficar assim: (Observe que tive que adicionar a referência System.Net.Http.Formatting ao arquivo gerado no estoque)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Formatting;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace BoomInteractive.TrainerCentral.Server {
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class WebApiApplication : System.Web.HttpApplication {
        protected void Application_Start() {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            //Force JSON responses on all requests
            GlobalConfiguration.Configuration.Formatters.Clear();
            GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
        }
    }
}
JJ_Coder4Hire
fonte
9
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

Isso limpa o formatador XML e, portanto, padroniza para o formato JSON.

Bat_Programmer
fonte
Perfeito tudo o que é necessário
tfa
4

Inspirado pela excelente resposta de Dmitry Pavlov, eu alterei um pouco para que pudesse inserir qualquer formatador que desejasse aplicar.

Crédito para Dmitry.

/// <summary>
/// A ContentNegotiator implementation that does not negotiate. Inspired by the film Taken.
/// </summary>
internal sealed class LiamNeesonContentNegotiator : IContentNegotiator
{
    private readonly MediaTypeFormatter _formatter;
    private readonly string _mimeTypeId;

    public LiamNeesonContentNegotiator(MediaTypeFormatter formatter, string mimeTypeId)
    {
        if (formatter == null)
            throw new ArgumentNullException("formatter");

        if (String.IsNullOrWhiteSpace(mimeTypeId))
            throw new ArgumentException("Mime type identifier string is null or whitespace.");

        _formatter = formatter;
        _mimeTypeId = mimeTypeId.Trim();
    }

    public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
    {
        return new ContentNegotiationResult(_formatter, new MediaTypeHeaderValue(_mimeTypeId));
    }
}
Luke Puplett
fonte
2

Se você quiser fazer isso apenas para um método, declare seu método como retornando em HttpResponseMessagevez de IEnumerable<Whatever>e faça:

    public HttpResponseMessage GetAllWhatever()
    {
        return Request.CreateResponse(HttpStatusCode.OK, new List<Whatever>(), Configuration.Formatters.JsonFormatter);
    }

este código é uma dor para o teste de unidade, mas também é possível assim:

    sut = new WhateverController() { Configuration = new HttpConfiguration() };
    sut.Configuration.Formatters.Add(new Mock<JsonMediaTypeFormatter>().Object);
    sut.Request = new HttpRequestMessage();
Durilka
fonte
Se você quiser algo para um método, crie apenas um msdn.microsoft.com/en-us/library/…
Elisabeth
2

Este tem cabeçalhos corretos definidos. Parece um pouco mais elegante.

public JsonResult<string> TestMethod() 
{
return Json("your string or object");
}
Netferret
fonte
1
Quais são os nomes totalmente qualificados para as classes JsonResult e Json?
Josh Withee
0

Você pode usar em WebApiConfig.cs:

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
Antonio
fonte
0

para aqueles que usam OWIN

GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());

torna-se (em Startup.cs):

   public void Configuration(IAppBuilder app)
        {
            OwinConfiguration = new HttpConfiguration();
            ConfigureOAuth(app);

            OwinConfiguration.Formatters.Clear();
            OwinConfiguration.Formatters.Add(new DynamicJsonMediaTypeFormatter());

            [...]
        }
Carlo Saccone
fonte