En utilisant la nouvelle API Web ASP.NET , dans Chrome, je vois XML - comment puis-je le changer pour demander JSON afin que je puisse le voir dans le navigateur? Je crois que cela ne fait partie que des en-têtes de demande, ai-je raison?
En utilisant la nouvelle API Web ASP.NET , dans Chrome, je vois XML - comment puis-je le changer pour demander JSON afin que je puisse le voir dans le navigateur? Je crois que cela ne fait partie que des en-têtes de demande, ai-je raison?
Réponses:
Je viens d'ajouter les éléments suivants en App_Start / WebApiConfig.cs
classe dans mon projet d' API Web MVC .
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html") );
Cela garantit que vous obtenez JSON sur la plupart des requêtes, mais vous pouvez l'obtenir XML
lorsque vous envoyez text/xml
.
Si vous avez besoin de la réponse Content-Type
, application/json
veuillez vérifier la réponse de Todd ci-dessous .
NameSpace
utilise System.Net.Http.Headers
.
Content-Type
tête de la réponse sera toujours text/html
.
Si vous faites cela dans le, WebApiConfig
vous obtiendrez JSON par défaut, mais cela vous permettra toujours de renvoyer XML si vous passez text/xml
comme en- Accept
tête de demande
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);
}
}
Si vous n'utilisez pas le type de projet MVC et que vous n'aviez donc pas cette classe pour commencer, consultez cette réponse pour plus de détails sur la façon de l'incorporer.
application/xml
avec une priorité de 0,9 et */*
avec une priorité de 0,8. En supprimant, application/xml
vous supprimez la possibilité pour l'API Web de renvoyer XML si le client le demande spécifiquement. Par exemple, si vous envoyez "Accepter: application / xml", vous recevrez toujours JSON.
L'utilisation de RequestHeaderMapping fonctionne encore mieux, car elle définit également l' Content-Type = application/json
en-tête de réponse, ce qui permet à Firefox (avec le module complémentaire JSONView) de formater la réponse en JSON.
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings
.Add(new System.Net.Http.Formatting.RequestHeaderMapping("Accept",
"text/html",
StringComparison.InvariantCultureIgnoreCase,
true,
"application/json"));
J'aime l'approche de Felipe Leusin - assurez-vous que les navigateurs obtiennent JSON sans compromettre la négociation de contenu des clients qui souhaitent réellement XML. Le seul élément manquant pour moi était que les en-têtes de réponse contenaient toujours le type de contenu: texte / html. Pourquoi était-ce un problème? Parce que j'utilise l' extension JSON Formatter Chrome , qui inspecte le type de contenu, et je n'obtiens pas le joli formatage auquel je suis habitué. J'ai corrigé cela avec un simple formateur personnalisé qui accepte les requêtes text / html et renvoie les réponses 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");
}
}
Inscrivez-vous comme ceci:
config.Formatters.Add(new BrowserJsonFormatter());
this.SerializerSettings.Formatting = Formatting.Indented;
si vous le souhaitez joli-imprimé sans extension de navigateur.
using System.Net.Http.Formatting
etusing Newtonsoft.Json
Astuce MVC4 # 3 - Suppression du formateur XML de l'API Web ASP.Net
En Global.asax
ajouter la ligne:
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
ainsi:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
BundleTable.Bundles.RegisterTemplateBundles();
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
}
Dans WebApiConfig.cs , ajoutez à la fin de la fonction Register :
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
Source .
dans le Global.asax, j'utilise le code ci-dessous. Mon URI pour obtenir JSON esthttp://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"));
}
Jetez un œil à la négociation de contenu dans WebAPI. Ces articles ( partie 1 et partie 2 ) merveilleusement détaillés et approfondis expliquent comment cela fonctionne.
En bref, vous avez raison et il suffit de définir les en Accept
- Content-Type
têtes ou de demander. Étant donné que votre action n'est pas codée pour renvoyer un format spécifique, vous pouvez définir Accept: application/json
.
Comme la question est spécifique à Chrome, vous pouvez obtenir l' extension Postman qui vous permet de définir le type de contenu de la demande.
network.http.accept.default
configuration en 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
pour éviter que des hôtes bogués tels que Bitbucket ne servent accidentellement votre JSON de navigateur au lieu de HTML.
Une option rapide consiste à utiliser la spécialisation MediaTypeMapping. Voici un exemple d'utilisation de QueryStringMapping dans l'événement Application_Start:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(new QueryStringMapping("a", "b", "application/json"));
Maintenant, chaque fois que l'url contient la chaîne de requête? A = b dans ce cas, la réponse Json sera affichée dans le navigateur.
Ce code fait de json ma valeur par défaut et me permet également d'utiliser le format XML. Je vais juste annexer le xml=true
.
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(new QueryStringMapping("xml", "true", "application/xml"));
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
Merci tout le monde!
N'utilisez pas votre navigateur pour tester votre API.
Au lieu de cela, essayez d'utiliser un client HTTP qui vous permet de spécifier votre demande, comme CURL, ou même Fiddler.
Le problème avec ce problème est dans le client, pas dans l'API. L'API Web se comporte correctement, selon la demande du navigateur.
La plupart des réponses ci-dessus sont parfaitement logiques. Étant donné que vous voyez des données formatées au format XML, cela signifie que le formateur XML est appliqué, vous pouvez donc voir le format JSON simplement en supprimant XMLFormatter du paramètre HttpConfiguration comme
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();
}
puisque JSON est le format par défaut
J'ai utilisé un filtre d'action global pour supprimer Accept: application/xml
lorsque l'en- User-Agent
tête contient "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();
}
}
Semble fonctionner.
J'ai trouvé l'application Chrome "Advanced REST Client" excellente pour travailler avec les services REST. Vous pouvez définir le Content-Type application/json
entre autres:
Client REST avancé
Le retour du format correct se fait par le formateur de type média. Comme d'autres l'ont mentionné, vous pouvez le faire en 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"));
...
}
}
Pour en savoir plus, consultez:
Dans le cas où vos actions retournent du XML (ce qui est le cas par défaut) et que vous avez juste besoin d'une méthode spécifique pour retourner JSON, vous pouvez alors utiliser un ActionFilterAttribute
et l'appliquer à cette action spécifique.
Attribut de filtre:
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);
}
}
S'appliquer à l'action:
[JsonOutput]
public IEnumerable<Person> GetPersons()
{
return _repository.AllPersons(); // the returned output will be in JSON
}
Notez que vous pouvez omettre le mot Attribute
sur la décoration d'action et utiliser juste à la [JsonOutput]
place de [JsonOutputAttribute]
.
config.Formatters.Remove(config.Formatters.XmlFormatter);
Je ne comprends pas pourquoi il y a toute cette complexité dans la réponse. Bien sûr, il existe de nombreuses façons de le faire, avec QueryStrings, des en-têtes et des options ... mais ce que je pense être la meilleure pratique est simple. Vous demandez une URL simple (ex:) http://yourstartup.com/api/cars
et en retour vous obtenez JSON. Vous obtenez JSON avec l'en-tête de réponse approprié:
Content-Type: application/json
En cherchant une réponse à cette même question, j'ai trouvé ce fil, et j'ai dû continuer car cette réponse acceptée ne fonctionne pas exactement. J'ai trouvé une réponse que je trouve trop simple pour ne pas être la meilleure:
Définir le formateur WebAPI par défaut
J'ajouterai également mon conseil ici.
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());
}
J'ai une question d'où viennent les défauts (du moins ceux que je vois). S'agit-il de valeurs par défaut .NET, ou peut-être créées ailleurs (par quelqu'un d'autre sur mon projet). En tout cas, j'espère que cela vous aidera.
Voici une solution similaire à jayson.centeno et à d'autres réponses, mais en utilisant l'extension intégrée 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
}
La solution était principalement destinée à prendre en charge le format $ pour OData dans les premières versions de WebApi, mais elle s'applique également à l'implémentation non-OData et renvoie l'en-
Content-Type: application/json; charset=utf-8
tête dans la réponse.
Il vous permet de virer de bord &$format=json
ou &$format=xml
jusqu'à la fin de votre uri lors d'un test avec un navigateur. Il n'interfère pas avec les autres comportements attendus lors de l'utilisation d'un client non navigateur où vous pouvez définir vos propres en-têtes.
Vous pouvez utiliser comme ci-dessous:
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
Ajoutez simplement ces deux lignes de code sur votre classe WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//add this two line
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
............................
}
}
Vous changez juste App_Start/WebApiConfig.cs
comme ceci:
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}"
);
}
À partir de MSDN Création d'une application à page unique avec ASP.NET et AngularJS (environ 41 minutes).
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();
}
Il devrait être à jour, je l'ai essayé et cela a fonctionné.
Un certain temps s'est écoulé depuis que cette question a été posée (et répondue), mais une autre option consiste à remplacer l'en-tête Accept sur le serveur pendant le traitement de la demande à l'aide d'un MessageHandler comme ci-dessous:
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);
}
}
Où someOtherCondition
peut être n'importe quoi, y compris le type de navigateur, etc. Ce serait pour les cas conditionnels où nous voulons seulement parfois remplacer la négociation de contenu par défaut. Sinon, selon les autres réponses, vous supprimeriez simplement un formateur inutile de la configuration.
Vous devrez bien sûr l'enregistrer. Vous pouvez soit le faire globalement:
public static void Register(HttpConfiguration config) {
config.MessageHandlers.Add(new ForceableContentTypeDelegationHandler());
}
ou itinéraire par itinéraire:
config.Routes.MapHttpRoute(
name: "SpecialContentRoute",
routeTemplate: "api/someUrlThatNeedsSpecialTreatment/{id}",
defaults: new { controller = "SpecialTreatment" id = RouteParameter.Optional },
constraints: null,
handler: new ForceableContentTypeDelegationHandler()
);
Et comme il s'agit d'un gestionnaire de messages, il s'exécutera à la fois sur les extrémités de demande et de réponse du pipeline, tout comme un HttpModule
. Ainsi, vous pouvez facilement reconnaître le remplacement avec un en-tête personnalisé:
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;
}
}
Voici le moyen le plus simple que j'ai utilisé dans mes applications. Ajouter ci-dessous 3 lignes de code App_Start\\WebApiConfig.cs
dans la Register
fonction
var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
L'API Web Asp.net sérialisera automatiquement votre objet de retour en JSON et au fur et à mesure de l' application/json
ajout dans l'en-tête, le navigateur ou le destinataire comprendra que vous retournez le résultat JSON.
WebApiConfig est l'endroit où vous pouvez configurer si vous voulez sortir en json ou xml. par défaut, c'est xml. dans la fonction de registre, nous pouvons utiliser les formats HttpConfiguration pour formater la sortie. System.Net.Http.Headers => MediaTypeHeaderValue ("text / html") est requis pour obtenir la sortie au format json.
En utilisant la réponse de Felipe Leusin pendant des années, après une récente mise à jour des bibliothèques de base et de Json.Net, je suis tombé sur un System.MissingMethodException
: SupportedMediaTypes. La solution dans mon cas, si tout va bien utile à d'autres rencontrant la même exception inattendue, est d'installer System.Net.Http
. NuGet le supprime apparemment dans certaines circonstances. Après une installation manuelle, le problème a été résolu.
Je suis étonné de voir autant de réponses nécessitant un codage pour changer un cas d'utilisation unique (GET) dans une API au lieu d'utiliser un outil approprié qui doit être installé une fois et peut être utilisé pour n'importe quelle API (propre ou tierce partie) et tout cas d'utilisation.
La bonne réponse est donc: