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.cs
classe 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 XML
quando invii text/xml
.
Se avete bisogno di avere la risposta Content-Type
, come application/json
si prega di controllare la risposta di Todd di seguito .
NameSpace
sta usando System.Net.Http.Headers
.
Content-Type
intestazione della risposta sarà comunque text/html
.
Se lo fai nel WebApiConfig
otterrai JSON per impostazione predefinita, ma ti consentirà comunque di restituire XML se passi text/xml
come Accept
intestazione 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/xml
con una priorità di 0,9 e */*
con una priorità di 0,8. Rimuovendo application/xml
si 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/json
intestazione 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.Formatting
eusing Newtonsoft.Json
Suggerimento rapido MVC4 n. 3: rimozione del formatter XML dall'API Web ASP.Net
In Global.asax
aggiungi 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 Accept
o Content-Type
richiedere. 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.default
configurazione 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.7
per 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/xml
quando l' User-Agent
intestazione 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/json
tra 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 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"));
...
}
}
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 ActionFilterAttribute
e 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 Attribute
sulla 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/cars
e 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-8
intestazione nella risposta.
Ti consente di virare &$format=json
o &$format=xml
alla 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.cs
questo 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 someOtherCondition
può 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.cs
in Register
funzione
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/json
viene 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 è: