web-dev-qa-db-fra.com

Erreur WCF: méthode 405 non autorisée

Aller fou avec ce problème. J'ai une solution avec 2 projets, l'un d'eux est un ancien html simple avec un appel ajqu jquery tandis que l'autre est un service WCF. La page html émettra un appel ajax au service WCF pour obtenir une chaîne json et l'utiliser à des fins d'affichage.

Maintenant, le problème est à chaque fois que je lance en mode débogage, la page html et le WCF seront démarrés avec un port différent. Et cela a créé un problème d'origine croisée pour moi lorsque j'effectue des tests (c'est-à-dire obtenir une erreur 405 Méthode non autorisée avec le type d'appel = OPTIONS dans Firefox). Je vérifierais la méthode d'appel sur mon script ajax et le service WCF est le même (GET).

Je ferais une recherche sur Google, mais j'ai constaté que je dois installer une extension ou effectuer une configuration sur IIS, ce que j'ai trouvé fastidieux car ce que je fais est quelque chose de simple. En suivant un exemple, j'ajouterais la configuration suivante dans mon web.config mais cela n'a pas fonctionné:

    <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="crossDomain" crossDomainScriptAccessEnabled="true" />
      </webHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="MobileService.webHttpBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="MyServiceBehavior">
          <serviceMetadata httpGetEnabled="true"  />
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <services>
      <service name="MobileService.SimpleMemberInfo" behaviorConfiguration="MyServiceBehavior">
        <endpoint address="" binding="webHttpBinding" contract="MobileService.IMemberInfo" bindingConfiguration="crossDomain" behaviorConfiguration="MobileService.webHttpBehavior">
        </endpoint>
      </service>
    </services>
  </system.serviceModel>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET" />
        <add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
      </customHeaders>
    </httpProtocol>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
    </system.webServer>

Quelqu'un a une idée de se débarrasser de ce problème ennuyeux?

EDIT: Juste pour ajouter, j'exécute le débogage avec IIS Express fourni avec VS Studio 2012

Ajouter le code WCF et web.config mis à jour

[ServiceContract]
public interface IMemberInfo
{
    [WebInvoke(Method = "GET",
           BodyStyle = WebMessageBodyStyle.Wrapped,
           ResponseFormat = WebMessageFormat.Json
    )]
    [OperationContract]
    string GetMemberInfoById();
    // TODO: Add your service operations here
}

Mon script:

$(document).ready(function () {
    $.ajax("http://localhost:32972/SimpleMemberInfo.svc/GetMemberInfoById", {
        cache: false,
        beforeSend: function (xhr) {
            $.mobile.showPageLoadingMsg();
        },
        complete: function () {
            $.mobile.hidePageLoadingMsg();
        },
        contentType: 'application/json',
        dataType: 'json',
        type: 'GET',
        error: function () {
            alert('Something awful happened');
        },
        success: function (data) {
            var s = "";

            s += "<li>" + data + "</li>";
            $("#myList").html(s);

        }
    });
});
17
ipohfly

Vous devez utiliser JSONP pour un appel interdomaine pour contourner les restrictions du navigateur et mettre à jour votre web.config avec crossDomainScriptAccessEnabled défini sur true pour contourner celles du serveur. Il y a un bon exemple dans la réponse ici: comment éviter la politique inter-domaines dans jquery ajax pour consommer le service wcf?

Vous pouvez également avoir un problème avec les demandes GET. Essayez les correctifs décrits ici: Faire fonctionner un service Web WCF avec des requêtes GET

Au total, vous voulez un web.config qui ressemble à ceci:

<bindings>
  <webHttpBinding>
    <binding name="crossDomain" crossDomainScriptAccessEnabled="true" />
  </webHttpBinding>
</bindings>
<behaviors>
  <endpointBehavior>
    <behavior name="restBehavior">
      <webHttp />
    </behavior>
  </endpointBehavior>
  <serviceBehavior>         
     <behavior name="MyServiceBehavior">
        <serviceMetadata httpGetEnabled="true"  />
        <serviceDebug includeExceptionDetailInFaults="true"/>
     </behavior>
  </serviceBehavior>
</behaviors>
<services>
  <service name="..." behaviorConfiguration="MyServiceBehavior">
    <endpoint address="" binding="webHttpBinding" bindingConfiguration="crossDomain" 
              contract="..." behaviorConfigurations="restBehavior" /> 
  </service>
</services>

(Notez que le service et le point de terminaison ont des comportements attachés, autorisant respectivement les appels webHttp et httpGet, et que l'accès à crossDomain est explicitement activé pour la liaison).

... une méthode de service décorée comme ceci:

[ServiceContract]
public interface IMyService
{
    [WebGet] // Required Attribute to allow GET
    [OperationContract]
    string MyMethod(string MyParam);
}

... et un appel client utilisant JSONP:

<script type="text/javascript">
$(document).ready(function() {
    var url =  "...";
    $.getJSON(url + "?callback=?", null, function(result) { // Note crucial ?callback=?
       // Process result
    });
});
</script>
10
Jude Fisher

Cependant, c'est un vieux fil, mais j'aimerais ajouter mon commentaire sur les problèmes que j'ai rencontrés et la solution que j'ai obtenue pour travailler sur CORS. Je développe un service web dans l'environnement suivant:

  1. Service Web WCF.
  2. Framework .NET 3.5.
  3. Ajout du service Web wcf dans le site Web asp.net existant.
  4. Visual Studio 2008

La plupart des personnes ont mentionné l'ajout de l'attribut crossDomainScriptAccessEnabled dans la balise sous <webHttpBinding> dans web.config. Je ne suis pas sûr que cela fonctionne ou non mais ce n'est pas disponible en version 3.5, donc je n'avais pas le choix. J'ai également constaté que l'ajout des balises suivantes dans web.config fonctionnerait ...

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

mais pas de chance ... a continué à obtenir la méthode 405 pas autorisé les erreurs

Après avoir beaucoup lutté avec ces options, j'ai trouvé une autre solution pour ajouter dynamiquement ces en-têtes dans le fichier global.asax comme indiqué ci-dessous ...

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("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    }
}

Et supprimez le de web.config. Publiez le site Web et continuez côté client jquery/ajax ... et vous obtiendrez les données des appels api. Bonne chance!

8
RamKr

Je voulais juste ajouter quelques problèmes avec la retouche CORS en bas - Le problème est que si votre entrée ne prend pas en charge GET et POST, la demande OPTIONS ne retourne pas réellement la bonne Il ne cherche pas vraiment quelles méthodes sont réellement autorisées sur le point de terminaison WCF - il suffit de dire artificiellement "GET, POST" sont autorisés pour chaque point de terminaison unique dans l'application lorsqu'un client exécute une demande OPTIONS (qui est en fait la client demandant ce qui est pris en charge).

C'est probablement OK, si vous ne comptez pas vraiment sur les informations de la méthode OPTIONS pour vous renvoyer une liste de méthodes valide (comme c'est le cas avec certaines demandes CORS) - mais si vous l'êtes, vous devrez faire quelque chose comme la solution sur cette question: Comment gérer Ajax JQUERY POST requête avec WCF auto-Host

Fondamentalement, chaque point de terminaison doit implémenter:

Webinvoke(Method="OPTIONS", UriTemplate="")

et appeler une méthode appropriée qui charge les en-têtes appropriés dans la réponse (y compris la liste "Access-Control-Allow-Method" appropriée pour ce point d'extrémité) à l'appelant. Cela craint que les points de terminaison WCF hébergés ne le fassent pas automatiquement pour nous, mais c'est une solution de contournement qui permet un contrôle plus fin du point de terminaison. Dans cette solution, les en-têtes de réponse appropriés sont chargés lors de l'implémentation du noeud final:

public void GetOptions()
    {
        // The data loaded in these headers should match whatever it is you support on the endpoint
        // for your application. 
        // For Origin: The "*" should really be a list of valid cross site domains for better security
        // For Methods: The list should be the list of support methods for the endpoint
        // For Allowed Headers: The list should be the supported header for your application

        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
    }
2
jeremyh