Usando a API da Web mais recente do ASP.NET , no Chrome , estou vendo o XML - como posso alterá-lo para solicitar o JSON para que eu possa visualizá-lo no navegador? Eu acredito que é apenas parte dos cabeçalhos da solicitação, estou correto nisso?
Usando a API da Web mais recente do ASP.NET , no Chrome , estou vendo o XML - como posso alterá-lo para solicitar o JSON para que eu possa visualizá-lo no navegador? Eu acredito que é apenas parte dos cabeçalhos da solicitação, estou correto nisso?
Respostas:
Acabei de adicionar o seguinte na App_Start / WebApiConfig.cs
aula no meu projeto de MVC Web API .
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html") );
Isso garante que você obtenha o JSON na maioria das consultas, mas poderá obtê- XML
lo quando enviar text/xml
.
Se você precisa ter a resposta Content-Type
como application/json
por favor, verifique a resposta de Todd abaixo .
NameSpace
está usando System.Net.Http.Headers
.
Content-Type
cabeçalho da resposta ainda estará text/html
.
Se você fizer isso no WebApiConfig
JSON, obterá JSON por padrão, mas ainda permitirá que você retorne XML se você passar text/xml
como o Accept
cabeçalho da solicitação
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
}
}
Se você não estiver usando o tipo de projeto MVC e, portanto, não tiver essa classe, consulte esta resposta para obter detalhes sobre como incorporá-la.
application/xml
com uma prioridade de 0,9 e */*
com uma prioridade de 0,8. Ao remover, application/xml
você remove a capacidade da API da Web retornar XML, se o cliente solicitar isso especificamente. por exemplo, se você enviar "Accept: application / xml", você ainda receberá JSON.
O uso do RequestHeaderMapping funciona ainda melhor, porque também define o Content-Type = application/json
cabeçalho de resposta, o que permite ao Firefox (com o complemento JSONView) formatar a resposta como JSON.
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings
.Add(new System.Net.Http.Formatting.RequestHeaderMapping("Accept",
"text/html",
StringComparison.InvariantCultureIgnoreCase,
true,
"application/json"));
Eu gosto mais da abordagem de Felipe Leusin - certifique-se de que os navegadores obtenham JSON sem comprometer a negociação de conteúdo de clientes que realmente desejam XML. A única peça que faltava para mim era que os cabeçalhos de resposta ainda continham o tipo de conteúdo: text / html. Por que isso foi um problema? Porque eu uso a extensão JSON Formatter Chrome , que inspeciona o tipo de conteúdo, e não recebo a formatação bonita com a qual estou acostumado. Corrigi isso com um formatador simples e personalizado que aceita solicitações de texto / html e retorna respostas application / json:
public class BrowserJsonFormatter : JsonMediaTypeFormatter
{
public BrowserJsonFormatter() {
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
this.SerializerSettings.Formatting = Formatting.Indented;
}
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) {
base.SetDefaultContentHeaders(type, headers, mediaType);
headers.ContentType = new MediaTypeHeaderValue("application/json");
}
}
Registre-se assim:
config.Formatters.Add(new BrowserJsonFormatter());
this.SerializerSettings.Formatting = Formatting.Indented;
se você deseja que ele seja impresso sem uma extensão do navegador.
using System.Net.Http.Formatting
eusing Newtonsoft.Json
Dica rápida do MVC4 nº 3 - Removendo o formatador XML da API da Web do ASP.Net
Em Global.asax
adicionar a linha:
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
igual a:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
BundleTable.Bundles.RegisterTemplateBundles();
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
}
No WebApiConfig.cs , adicione ao final da função Register :
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
Fonte .
No Global.asax , estou usando o código abaixo. Meu URI para obter JSON éhttp://www.digantakumar.com/api/values?json=true
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(new QueryStringMapping("json", "true", "application/json"));
}
Veja a negociação de conteúdo na WebAPI. Esses posts ( parte 1 e parte 2 ) maravilhosamente detalhados e detalhados explicam como funciona.
Em resumo, você está certo e só precisa definir os cabeçalhos Accept
ou Content-Type
solicitar. Como sua ação não está codificada para retornar um formato específico, você pode configurá-lo Accept: application/json
.
Como a pergunta é específica do Chrome, você pode obter a extensão Postman, que permite definir o tipo de conteúdo da solicitação.
network.http.accept.default
configuração para text/html,application/xhtml+xml,application/json;q=0.9,application/xml;q=0.8,*/*;q=0.7
.
text/html,application/xhtml+xml;q=1.0,*/*;q=0.7
para evitar que hosts com erros, como o Bitbucket, atendam acidentalmente o JSON do navegador em vez de HTML.
Uma opção rápida é usar a especialização MediaTypeMapping. Aqui está um exemplo do uso de QueryStringMapping no evento Application_Start:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(new QueryStringMapping("a", "b", "application/json"));
Agora, sempre que o URL contiver a string de consulta? A = b, nesse caso, a resposta Json será mostrada no navegador.
Esse código faz do json meu padrão e me permite usar o formato XML também. Vou apenas acrescentar o xml=true
.
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(new QueryStringMapping("xml", "true", "application/xml"));
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
Obrigado a todos!
Não use seu navegador para testar sua API.
Em vez disso, tente usar um cliente HTTP que permita especificar sua solicitação, como CURL ou mesmo o Fiddler.
O problema com esse problema está no cliente, não na API. A API da web se comporta corretamente, de acordo com a solicitação do navegador.
A maioria das respostas acima faz todo sentido. Como você vê dados sendo formatados no formato XML, isso significa que o formatador XML é aplicado, portanto, você pode ver o formato JSON apenas removendo o XMLFormatter do parâmetro HttpConfiguration, como
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.EnableSystemDiagnosticsTracing();
}
já que JSON é o formato padrão
Usei um filtro de ação global para remover Accept: application/xml
quando o User-Agent
cabeçalho contém "Chrome":
internal class RemoveXmlForGoogleChromeFilter : IActionFilter
{
public bool AllowMultiple
{
get { return false; }
}
public async Task<HttpResponseMessage> ExecuteActionFilterAsync(
HttpActionContext actionContext,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation)
{
var userAgent = actionContext.Request.Headers.UserAgent.ToString();
if (userAgent.Contains("Chrome"))
{
var acceptHeaders = actionContext.Request.Headers.Accept;
var header =
acceptHeaders.SingleOrDefault(
x => x.MediaType.Contains("application/xml"));
acceptHeaders.Remove(header);
}
return await continuation();
}
}
Parece funcionar.
Achei o aplicativo Chrome "Advanced REST Client" excelente para trabalhar com serviços REST. Você pode definir o Tipo de conteúdo para, application/json
entre outras coisas:
Cliente REST avançado
O retorno do formato correto é feito pelo formatador de tipo de mídia. Como outros mencionados, você pode fazer isso na WebApiConfig
classe:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...
// Configure Web API to return JSON
config.Formatters.JsonFormatter
.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/html"));
...
}
}
Para mais, verifique:
Caso suas ações estejam retornando XML (que é o caso por padrão) e você precise apenas de um método específico para retornar JSON, poderá usar um ActionFilterAttribute
e aplicá-lo a essa ação específica.
Atributo de filtro:
public class JsonOutputAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
ObjectContent content = actionExecutedContext.Response.Content as ObjectContent;
var value = content.Value;
Type targetType = actionExecutedContext.Response.Content.GetType().GetGenericArguments()[0];
var httpResponseMsg = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
RequestMessage = actionExecutedContext.Request,
Content = new ObjectContent(targetType, value, new JsonMediaTypeFormatter(), (string)null)
};
actionExecutedContext.Response = httpResponseMsg;
base.OnActionExecuted(actionExecutedContext);
}
}
Aplicando à ação:
[JsonOutput]
public IEnumerable<Person> GetPersons()
{
return _repository.AllPersons(); // the returned output will be in JSON
}
Observe que você pode omitir a palavra Attribute
na decoração da ação e usar apenas em [JsonOutput]
vez de [JsonOutputAttribute]
.
config.Formatters.Remove(config.Formatters.XmlFormatter);
Não está claro para mim por que existe toda essa complexidade na resposta. Claro, existem várias maneiras de fazer isso, com QueryStrings, cabeçalhos e opções ... mas o que eu acredito ser a melhor prática é simples. Você solicita uma URL simples (ex:) http://yourstartup.com/api/cars
e, em troca, obtém JSON. Você obtém o JSON com o cabeçalho de resposta adequado:
Content-Type: application/json
Ao procurar uma resposta para essa mesma pergunta, encontrei esse tópico e tive que continuar porque essa resposta aceita não funciona exatamente. Eu encontrei uma resposta que considero simples demais para não ser a melhor:
Defina o formatador WebAPI padrão
Vou adicionar minha dica aqui também.
WebApiConfig.cs
namespace com.yourstartup
{
using ...;
using System.Net.Http.Formatting;
...
config.Formatters.Clear(); //because there are defaults of XML..
config.Formatters.Add(new JsonMediaTypeFormatter());
}
Eu tenho uma pergunta de onde vêm os padrões (pelo menos os que estou vendo). Eles são padrões do .NET ou talvez criados em outro lugar (por outra pessoa no meu projeto). De qualquer forma, espero que isso ajude.
Aqui está uma solução semelhante à de jayson.centeno e outras respostas, mas usando a extensão interna de System.Net.Http.Formatting
.
public static void Register(HttpConfiguration config)
{
// add support for the 'format' query param
// cref: http://blogs.msdn.com/b/hongyes/archive/2012/09/02/support-format-in-asp-net-web-api.aspx
config.Formatters.JsonFormatter.AddQueryStringMapping("$format", "json", "application/json");
config.Formatters.XmlFormatter.AddQueryStringMapping("$format", "xml", "application/xml");
// ... additional configuration
}
A solução foi voltada principalmente para o suporte ao formato $ para OData nas primeiras versões do WebApi, mas também se aplica à implementação não OData e retorna o
Content-Type: application/json; charset=utf-8
cabeçalho na resposta.
Ele permite a aderência &$format=json
ou &$format=xml
o final da sua uri ao testar com um navegador. Ele não interfere com outro comportamento esperado ao usar um cliente que não é do navegador, onde você pode definir seus próprios cabeçalhos.
Você pode usar como abaixo:
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
Basta adicionar essas duas linhas de código na sua classe WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//add this two line
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
............................
}
}
Você acabou de mudar o App_Start/WebApiConfig.cs
seguinte:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
//Below formatter is used for returning the Json result.
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
//Default route
config.Routes.MapHttpRoute(
name: "ApiControllerOnly",
routeTemplate: "api/{controller}"
);
}
Do MSDN Criando um aplicativo de página única com ASP.NET e AngularJS (aproximadamente 41 minutos).
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// ... possible routing etc.
// Setup to return json and camelcase it!
var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
formatter.SerializerSettings.ContractResolver =
new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
}
Deve ser atual, eu tentei e funcionou.
Algum tempo se passou desde que essa pergunta foi feita (e respondida), mas outra opção é substituir o cabeçalho Accept no servidor durante o processamento da solicitação usando um MessageHandler, como abaixo:
public class ForceableContentTypeDelegationHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var someOtherCondition = false;
var accHeader = request.Headers.GetValues("Accept").FirstOrDefault();
if (someOtherCondition && accHeader.Contains("application/xml"))
{
request.Headers.Remove("Accept");
request.Headers.Add("Accept", "application/json");
}
return await base.SendAsync(request, cancellationToken);
}
}
Onde someOtherCondition
pode haver qualquer coisa, incluindo o tipo de navegador, etc. Isso seria para casos condicionais em que apenas às vezes queremos substituir a negociação de conteúdo padrão. Caso contrário, como em outras respostas, você simplesmente removeria um formatador desnecessário da configuração.
Você precisará registrá-lo, é claro. Você pode fazer isso globalmente:
public static void Register(HttpConfiguration config) {
config.MessageHandlers.Add(new ForceableContentTypeDelegationHandler());
}
ou em uma rota por rota:
config.Routes.MapHttpRoute(
name: "SpecialContentRoute",
routeTemplate: "api/someUrlThatNeedsSpecialTreatment/{id}",
defaults: new { controller = "SpecialTreatment" id = RouteParameter.Optional },
constraints: null,
handler: new ForceableContentTypeDelegationHandler()
);
E como esse é um manipulador de mensagens, ele será executado nas extremidades de solicitação e resposta do pipeline, como um HttpModule
. Assim, você pode reconhecer facilmente a substituição com um cabeçalho personalizado:
public class ForceableContentTypeDelegationHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var wasForced = false;
var someOtherCondition = false;
var accHeader = request.Headers.GetValues("Accept").FirstOrDefault();
if (someOtherCondition && accHeader.Contains("application/xml"))
{
request.Headers.Remove("Accept");
request.Headers.Add("Accept", "application/json");
wasForced = true;
}
var response = await base.SendAsync(request, cancellationToken);
if (wasForced){
response.Headers.Add("X-ForcedContent", "We overrode your content prefs, sorry");
}
return response;
}
}
Aqui está a maneira mais fácil que eu usei em meus aplicativos. Adicione abaixo de 3 linhas de código App_Start\\WebApiConfig.cs
em Register
função
var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
A API da web do Asp.net serializa automaticamente o objeto retornado para JSON e, conforme application/json
é adicionado no cabeçalho, para que o navegador ou o destinatário entenda que você está retornando o resultado JSON.
WebApiConfig é o local em que você pode configurar se deseja gerar em json ou xml. por padrão, é xml. na função de registro, podemos usar os Formadores de Configuração Http para formatar a saída. System.Net.Http.Headers => MediaTypeHeaderValue ("text / html") é necessário para obter a saída no formato json.
Usando a resposta de Felipe Leusin por anos, após uma recente atualização das principais bibliotecas e do Json.Net, encontrei um System.MissingMethodException
: SupportedMediaTypes. A solução no meu caso, espero que útil para outras pessoas que enfrentam a mesma exceção inesperada, é instalar System.Net.Http
. Aparentemente, o NuGet o remove em algumas circunstâncias. Após uma instalação manual, o problema foi resolvido.
Estou surpreso ao ver tantas respostas exigindo que a codificação altere um único caso de uso (GET) em uma API, em vez de usar uma ferramenta adequada, que deve ser instalada uma vez e pode ser usada para qualquer API (própria ou de terceiros) e todas casos de uso.
Portanto, a boa resposta é: