Utilizzando la più recente API Web ASP.NET , in Chrome visualizzo XML: come posso modificarlo per richiedere JSON in modo da poterlo visualizzare nel browser? Credo che sia solo una parte delle intestazioni della richiesta, ho ragione?
Utilizzando la più recente API Web ASP.NET , in Chrome visualizzo XML: come posso modificarlo per richiedere JSON in modo da poterlo visualizzare nel browser? Credo che sia solo una parte delle intestazioni della richiesta, ho ragione?
Risposte:
Ho appena aggiunto quanto segue in App_Start / WebApiConfig.csclasse nel mio progetto API Web MVC .
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html") );
Questo ti assicura di ricevere JSON sulla maggior parte delle query, ma puoi ottenerlo XMLquando invii text/xml.
Se avete bisogno di avere la risposta Content-Type, come application/jsonsi prega di controllare la risposta di Todd di seguito .
NameSpacesta usando System.Net.Http.Headers.
Content-Typeintestazione della risposta sarà comunque text/html.
Se lo fai nel WebApiConfigotterrai JSON per impostazione predefinita, ma ti consentirà comunque di restituire XML se passi text/xmlcome Acceptintestazione della richiesta
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 non stai usando il tipo di progetto MVC e quindi non hai avuto questa classe per cominciare, vedi questa risposta per i dettagli su come incorporarlo.
application/xmlcon una priorità di 0,9 e */*con una priorità di 0,8. Rimuovendo application/xmlsi rimuove la possibilità per l'API Web di restituire XML se il client lo richiede in modo specifico. ad es. se invii "Accetta: application / xml" riceverai comunque JSON.
L'uso di RequestHeaderMapping funziona ancora meglio, perché imposta anche l' Content-Type = application/jsonintestazione della risposta, che consente a Firefox (con il componente aggiuntivo JSONView) di formattare la risposta come JSON.
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings
.Add(new System.Net.Http.Formatting.RequestHeaderMapping("Accept",
"text/html",
StringComparison.InvariantCultureIgnoreCase,
true,
"application/json"));
Mi piace molto l'approccio di Felipe Leusin : assicurarsi che i browser ottengano JSON senza compromettere la negoziazione dei contenuti da parte dei clienti che desiderano effettivamente XML. L'unico pezzo mancante per me era che le intestazioni di risposta contenevano ancora tipo di contenuto: testo / html. Perché è stato un problema? Perché utilizzo l' estensione JSON Formatter per Chrome , che controlla il tipo di contenuto e non ottengo la formattazione graziosa a cui sono abituato. Ho risolto questo problema con un semplice formatter personalizzato che accetta richieste text / html e restituisce risposte 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");
}
}
Registrati in questo modo:
config.Formatters.Add(new BrowserJsonFormatter());
this.SerializerSettings.Formatting = Formatting.Indented;se lo si desidera piuttosto stampato senza un'estensione del browser.
using System.Net.Http.Formattingeusing Newtonsoft.Json
Suggerimento rapido MVC4 n. 3: rimozione del formatter XML dall'API Web ASP.Net
In Global.asaxaggiungi la riga:
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
così:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
BundleTable.Bundles.RegisterTemplateBundles();
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
}
In WebApiConfig.cs , aggiungi alla fine della funzione Register :
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
Fonte .
Nel Global.asax sto usando il codice qui sotto. Il mio URI per ottenere 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"));
}
Dai un'occhiata alla negoziazione dei contenuti nella WebAPI. Questi post di blog ( Parte 1 e Parte 2 ) meravigliosamente dettagliati e completi spiegano come funziona.
In breve, hai ragione e devi solo impostare le intestazioni Accepto Content-Typerichiedere. Dato che la tua azione non è codificata per restituire un formato specifico, puoi impostare Accept: application/json.
Poiché la domanda è specifica di Chrome, puoi ottenere l' estensione Postman che ti consente di impostare il tipo di contenuto della richiesta.

network.http.accept.defaultconfigurazione in 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.7per evitare che host buggy come Bitbucket servano accidentalmente il tuo browser JSON al posto di HTML.
Un'opzione rapida è utilizzare la specializzazione MediaTypeMapping. Ecco un esempio dell'uso di QueryStringMapping nell'evento Application_Start:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(new QueryStringMapping("a", "b", "application/json"));
Ora, ogni volta che l'URL contiene la stringa di query? A = b in questo caso, la risposta Json verrà mostrata nel browser.
Questo codice rende json il mio valore predefinito e mi consente di utilizzare anche il formato XML. Aggiungerò semplicemente il xml=true.
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(new QueryStringMapping("xml", "true", "application/xml"));
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
Grazie a tutti!
Non utilizzare il browser per testare l'API.
Invece, prova a utilizzare un client HTTP che ti consente di specificare la tua richiesta, come CURL o persino Fiddler.
Il problema con questo problema è nel client, non nell'API. L'API Web si comporta correttamente, in base alla richiesta del browser.
La maggior parte delle risposte sopra ha perfettamente senso. Dato che stai vedendo che i dati sono formattati in formato XML, ciò significa che viene applicato il formattatore XML, quindi puoi vedere il formato JSON semplicemente rimuovendo XMLFormatter dal parametro HttpConfiguration come
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();
}
poiché JSON è il formato predefinito
Ho usato un filtro di azione globale per rimuovere Accept: application/xmlquando l' User-Agentintestazione contiene "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();
}
}
Sembra funzionare.
Ho trovato l'app Chrome "Advanced REST Client" eccellente per lavorare con i servizi REST. È possibile impostare Content-Type su application/jsontra le altre cose:
client REST avanzato
La restituzione del formato corretto viene eseguita dal formattatore del tipo di supporto. Come altri hanno già detto, puoi farlo in WebApiConfigclasse:
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"));
...
}
}
Per di più, controlla:
Nel caso in cui le tue azioni restituiscano XML (che è il caso per impostazione predefinita) e hai bisogno solo di un metodo specifico per restituire JSON, puoi quindi utilizzare un ActionFilterAttributee applicarlo a quell'azione specifica.
Attributo 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);
}
}
Applicando all'azione:
[JsonOutput]
public IEnumerable<Person> GetPersons()
{
return _repository.AllPersons(); // the returned output will be in JSON
}
Nota che puoi omettere la parola Attributesulla decorazione dell'azione e usare solo [JsonOutput]invece di [JsonOutputAttribute].
config.Formatters.Remove(config.Formatters.XmlFormatter);
Non mi è chiaro perché ci sia tutta questa complessità nella risposta. Sicuramente ci sono molti modi in cui puoi farlo, con QueryStrings, header e opzioni ... ma quello che credo sia la migliore pratica è semplice. Richiedi un semplice URL (es:) http://yourstartup.com/api/carse in cambio ottieni JSON. Ottieni JSON con l'intestazione della risposta corretta:
Content-Type: application/json
Nel cercare una risposta a questa stessa domanda, ho trovato questa discussione e ho dovuto continuare perché questa risposta accettata non funziona esattamente. Ho trovato una risposta che ritengo troppo semplice per non essere la migliore:
Imposta il formattatore WebAPI predefinito
Aggiungerò il mio consiglio anche qui.
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());
}
Ho una domanda su da dove provengano i valori predefiniti (almeno quelli che sto vedendo). Sono impostazioni predefinite .NET o forse create altrove (da qualcun altro nel mio progetto). Comunque, spero che questo aiuti.
Ecco una soluzione simile a quella di jayson.centeno e di altre risposte, ma utilizzando l'estensione integrata di 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
}
La soluzione era principalmente orientata al supporto del formato $ per OData nelle prime versioni di WebApi, ma si applica anche all'implementazione non OData e restituisce l'
Content-Type: application/json; charset=utf-8intestazione nella risposta.
Ti consente di virare &$format=jsono &$format=xmlalla fine del tuo uri durante i test con un browser. Non interferisce con altri comportamenti previsti quando si utilizza un client non browser in cui è possibile impostare le proprie intestazioni.
Puoi usare come di seguito:
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
Basta aggiungere quelle due righe di codice sulla classe WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//add this two line
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
............................
}
}
Basta cambiare in App_Start/WebApiConfig.csquesto modo:
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}"
);
}
Da MSDN Creazione di un'applicazione a pagina singola con ASP.NET e AngularJS (circa 41 minuti).
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();
}
Dovrebbe essere attuale, l'ho provato e ha funzionato.
È trascorso del tempo da quando questa domanda è stata posta (e ha risposto) ma un'altra opzione è quella di sovrascrivere l'intestazione Accept sul server durante l'elaborazione della richiesta utilizzando un MessageHandler come di seguito:
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);
}
}
Dove someOtherConditionpuò essere qualsiasi cosa, incluso il tipo di browser, ecc. Questo sarebbe per i casi condizionali in cui solo a volte vogliamo sovrascrivere la negoziazione dei contenuti predefinita. Altrimenti, come per altre risposte, rimuoveresti semplicemente un formattatore non necessario dalla configurazione.
Dovrai registrarlo ovviamente. Puoi farlo sia a livello globale:
public static void Register(HttpConfiguration config) {
config.MessageHandlers.Add(new ForceableContentTypeDelegationHandler());
}
o percorso per percorso:
config.Routes.MapHttpRoute(
name: "SpecialContentRoute",
routeTemplate: "api/someUrlThatNeedsSpecialTreatment/{id}",
defaults: new { controller = "SpecialTreatment" id = RouteParameter.Optional },
constraints: null,
handler: new ForceableContentTypeDelegationHandler()
);
E poiché si tratta di un gestore di messaggi, verrà eseguito sia a livello di richieste che di risposte della pipeline in modo molto simile a un HttpModule. Quindi potresti facilmente riconoscere l'override con un'intestazione personalizzata:
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;
}
}
Ecco il modo più semplice che ho usato nelle mie applicazioni. Aggiungi sotto 3 righe di codice App_Start\\WebApiConfig.csin Registerfunzione
var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
L'API Web Asp.net serializzerà automaticamente l'oggetto di ritorno su JSON e come application/jsonviene aggiunto nell'intestazione in modo che il browser o il destinatario capisca che stai restituendo il risultato JSON.
WebApiConfig è il luogo in cui è possibile configurare se si desidera eseguire l'output in json o xml. per impostazione predefinita è xml. nella funzione di registro possiamo usare HttpConfiguration Formatters per formattare l'output. System.Net.Http.Headers => MediaTypeHeaderValue ("text / html") è necessario per ottenere l'output nel formato json.

Usando la risposta di Felipe Leusin per anni, dopo un recente aggiornamento delle librerie di base e di Json.Net, mi sono imbattuto in System.MissingMethodException: SupportedMediaTypes. La soluzione nel mio caso, si spera utile per gli altri che sperimentano la stessa inaspettata eccezione, è installare System.Net.Http. Apparentemente NuGet lo rimuove in alcune circostanze. Dopo un'installazione manuale, il problema è stato risolto.
Sono stupito di vedere così tante risposte che richiedono la codifica di cambiare un caso d'uso singola (GET) in un'API invece di usare uno strumento adeguato ciò che deve essere installato una sola volta e può essere utilizzato per qualsiasi API (parte propria o 3 °) e tutti casi d'uso.
Quindi la buona risposta è: