web-dev-qa-db-fra.com

Asp.Net WebApi2 Activer CORS ne fonctionnant pas avec AspNet.WebApi.Cors 5.2.3

J'ai essayé de suivre les étapes de http://enable-cors.org/server_aspnet.html pour que mon API RESTful (implémentée avec ASP.NET WebAPI2) fonctionne avec des requêtes d'origine croisées (CORS activé). Cela ne fonctionne que si je modifie le fichier web.config.

J'ai installé la dépendance WebApi Cors:

install-package Microsoft.AspNet.WebApi.Cors -ProjectName MyProject.Web.Api

Puis dans mon App_Start j'ai la classe WebApiConfig comme suit:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var corsAttr = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(corsAttr);

        var constraintsResolver = new DefaultInlineConstraintResolver();

        constraintsResolver.ConstraintMap.Add("apiVersionConstraint", typeof(ApiVersionConstraint));
        config.MapHttpAttributeRoutes(constraintsResolver); 
        config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
        //config.EnableSystemDiagnosticsTracing(); 
        config.Services.Replace(typeof(ITraceWriter), new SimpleTraceWriter(WebContainerManager.Get<ILogManager>())); 
        config.Services.Add(typeof(IExceptionLogger), new SimpleExceptionLogger(WebContainerManager.Get<ILogManager>()));
        config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler()); 
    }
}

mais après cela, je lance l'application, je demande une ressource avec Fiddler comme: http: // localhost: 51589/api/v1/persons et dans la réponse, je ne peux pas voir les en-têtes HTTP que je devrais voir. tel que:

  • Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS
  • Access-Control-Allow-Origin: *

Est-ce que je manque un pas? J'ai essayé avec l'annotation suivante sur le contrôleur:

[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]

Même résultat, pas de CORS activé.

Cependant, si j'ajoute ce qui suit dans mon web.config (sans même installer la dépendance AspNet.WebApi.Cors), cela fonctionne:

<system.webServer>

<httpProtocol>
  <!-- THESE HEADERS ARE IMPORTANT TO WORK WITH CORS -->
  <!--
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Methods" value="POST, PUT, DELETE, GET, OPTIONS" />
    <add name="Access-Control-Allow-Headers" value="content-Type, accept, Origin, X-Requested-With, Authorization, name" />
    <add name="Access-Control-Allow-Credentials" value="true" />
  </customHeaders>
  -->
</httpProtocol>
<handlers>
  <!-- THESE HANDLERS ARE IMPORTANT FOR WEB API TO WORK WITH  GET,HEAD,POST,PUT,DELETE and CORS-->
  <!--

  <remove name="WebDAV" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,PUT,DELETE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
-->
</handlers>

Toute aide serait très appréciée!

Je vous remercie.

69
iberodev

J'ai créé un projet de démonstration épuré pour vous.

Vous pouvez essayer le lien API ci-dessus depuis votre Fiddler local pour afficher les en-têtes. Voici une explication.

Global.ascx

Tout cela n’appelle que la WebApiConfig. Ce n'est rien mais l'organisation du code.

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        WebApiConfig.Register(GlobalConfiguration.Configuration);
    }
}

WebApiConfig.cs

La méthode clé pour votre ici est la méthode EnableCrossSiteRequests. C'est tout ce que vous devez faire . La EnableCorsAttribute est un attribut CORS à portée globale .

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        EnableCrossSiteRequests(config);
        AddRoutes(config);
    }

    private static void AddRoutes(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "Default",
            routeTemplate: "api/{controller}/"
        );
    }

    private static void EnableCrossSiteRequests(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute(
            origins: "*", 
            headers: "*", 
            methods: "*");
        config.EnableCors(cors);
    }
}

Contrôleur de valeurs

La méthode Get reçoit l'attribut EnableCors que nous avons appliqué globalement. La méthode Another remplace la méthode globale EnableCors.

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] { 
            "This is a CORS response.", 
            "It works from any Origin." 
        };
    }

    // GET api/values/another
    [HttpGet]
    [EnableCors(origins:"http://www.bigfont.ca", headers:"*", methods: "*")]
    public IEnumerable<string> Another()
    {
        return new string[] { 
            "This is a CORS response. ", 
            "It works only from two origins: ",
            "1. www.bigfont.ca ",
            "2. the same Origin." 
        };
    }
}

Web.config

Vous n'avez pas besoin d'ajouter quoi que ce soit de spécial dans web.config. En fait, voici à quoi ressemble la configuration web de la démo: vide.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
</configuration>

Démo

var url = "https://cors-webapi.azurewebsites.net/api/values"

$.get(url, function(data) {
  console.log("We expect this to succeed.");
  console.log(data);
});

var url = "https://cors-webapi.azurewebsites.net/api/values/another"

$.get(url, function(data) {
  console.log(data);
}).fail(function(xhr, status, text) {
  console.log("We expect this to fail.");
  console.log(status);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
89
Shaun Luttin

Vous avez juste besoin de changer certains fichiers. Cela fonctionne pour moi.

Global.ascx

public class WebApiApplication : System.Web.HttpApplication {
    protected void Application_Start()
    {
        WebApiConfig.Register(GlobalConfiguration.Configuration);
    } }

WebApiConfig.cs

Toutes les requêtes doivent appeler ce code.

public static class WebApiConfig {
    public static void Register(HttpConfiguration config)
    {
        EnableCrossSiteRequests(config);
        AddRoutes(config);
    }

    private static void AddRoutes(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "Default",
            routeTemplate: "api/{controller}/"
        );
    }

    private static void EnableCrossSiteRequests(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute(
            origins: "*", 
            headers: "*", 
            methods: "*");
        config.EnableCors(cors);
    } }

Certains contrôleurs

Rien à changer.

Web.config

Vous devez ajouter des gestionnaires dans votre web.config

<configuration> 
  <system.webServer>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>   
  </system.webServer> 
</configuration>
14
Jonas Ribeiro

En cas de demande CORS, tous les navigateurs modernes répondent avec un verbe OPTION, puis la demande réelle est appliquée. Ceci est censé être utilisé pour demander à l'utilisateur une confirmation en cas de demande CORS. Mais dans le cas d’une API, si vous souhaitez ignorer ce processus de vérification, ajoutez le fragment de code suivant à Global.asax.

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE");

                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
                HttpContext.Current.Response.End();
            }
        }

Nous ne faisons que passer le chèque en vérifiant le verbe OPTIONS.

12
Neeraj

Je viens d'ajouter des en-têtes personnalisés à Web.config et cela a fonctionné à merveille.

Sur la configuration - system.webServer:

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
  </customHeaders>
</httpProtocol>

J'ai l'application front-end et le backend sur la même solution. Pour que cela fonctionne, je dois définir le projet de services Web (Backend) comme paramètre par défaut pour que cela fonctionne.

J'utilisais ReST, je n'ai rien essayé d'autre.

8
Mathter

Après quelques modifications dans mon Web.config, CORS a soudainement cessé de fonctionner dans mon projet Web API 2 (au moins pour la demande OPTIONS lors du contrôle en amont). Il semble que vous ayez besoin de la section mentionnée ci-dessous dans votre configuration Web ou sinon, EnableCorsAttribute (global) ne fonctionnera pas avec les demandes OPTIONS. Notez qu'il s'agit exactement de la même section que Visual Studio ajoutera à un nouveau projet Web API 2.

<system.webServer>
  <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
    <remove name="OPTIONSVerbHandler"/>
    <remove name="TRACEVerbHandler"/>
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
  </handlers>
</system.webServer>
3
Christian Gürtler

Aucune de ces réponses ne fonctionne vraiment. Comme d'autres l'ont noté, le package Cors n'utilisera l'en-tête Access-Control-Allow-Origin que si la demande avait un en-tête Origin. Mais vous ne pouvez généralement pas simplement ajouter un en-tête Origin à la requête, car les navigateurs peuvent également essayer de la réguler.

Si vous voulez un moyen rapide et transparent d'autoriser les requêtes intersites sur une API Web, il est vraiment beaucoup plus facile d'écrire un attribut de filtre personnalisé:

public class AllowCors : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext == null)
        {
            throw new ArgumentNullException("actionExecutedContext");
        }
        else
        {
            actionExecutedContext.Response.Headers.Remove("Access-Control-Allow-Origin");
            actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        }
        base.OnActionExecuted(actionExecutedContext);
    }
}

Ensuite, utilisez-le simplement sur votre action Controller:

[AllowCors]
public IHttpActionResult Get()
{
    return Ok("value");
}

Je ne garantirai pas la sécurité de cette opération en général, mais il est probablement beaucoup plus prudent de définir les en-têtes dans le fichier web.config, car vous pouvez ainsi les appliquer aussi précisément que vous en avez besoin.

Et bien sûr, il est simple de modifier ce qui précède pour ne permettre que certaines origines, méthodes, etc.

2
Matthew

WEBAPI2: SOLUTION. global.asax.cs:

var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

IN solution explorer, cliquez-droit sur api-project. Dans la fenêtre de propriétés, définissez 'Authentification anonyme' sur activé !!!

J'espère que cela aidera quelqu'un dans le futur.

1
hannes neukermans

Je viens de vivre le même problème en essayant de activer CORS globalement . Cependant, j'ai découvert que ne fonctionnait , mais uniquement lorsque la demande contient une valeur d'en-tête Origin. Si vous omettez la valeur d'en-tête Origin, la réponse ne contiendra pas un Access-Control-Allow-Origin.

J'ai utilisé un plugin chrome appelé DHC pour tester ma requête GET. Cela m'a permis d'ajouter facilement l'en-tête Origin.

1
Rick

Aucune solution sûre ne fonctionne pour moi, alors pour être plus sûr que Neeraj et plus facile que Matthew, il suffit d'ajouter: System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

Dans la méthode de votre contrôleur. Cela fonctionne pour moi.

public IHttpActionResult Get()
{
    System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    return Ok("value");
}
0
puipuix

J'ai trouvé cette question parce que j'avais des problèmes avec la requête OPTIONS envoyée par la plupart des navigateurs. Mon application acheminait les demandes OPTIONS et utilisait mon IoC pour construire de nombreux objets. Certaines lançaient des exceptions sur ce type de demande étrange pour diverses raisons.

En gros, indiquez une route ignorée pour toutes les demandes OPTIONS si elles vous causent des problèmes:

var constraints = new { httpMethod = new HttpMethodConstraint(HttpMethod.Options) };
config.Routes.IgnoreRoute("OPTIONS", "{*pathInfo}", constraints);

Plus d'infos: arrêter les requêtes OPTIONS de traitement de l'API Web

0
BritishDeveloper

J'espère que cela aidera quelqu'un dans le futur. Mon problème était que je suivais le même tutoriel que l'OP pour activer CORS global. Cependant, j'ai également défini une règle CORS spécifique à l'action dans mon fichier AccountController.cs:

[EnableCors(origins: "", headers: "*", methods: "*")]

et obtenait des erreurs sur l'origine ne peut pas être une chaîne nulle ou vide. MAIS l'erreur se produisait dans le fichier Global.asax.cs de tous les endroits. La solution est de la changer pour:

[EnableCors(origins: "*", headers: "*", methods: "*")]

remarquez le * dans les origines? Manquer c'est ce qui causait l'erreur dans le fichier Global.asax.cs.

J'espère que ça aide quelqu'un.

0
jangooni