2012-11-05 25 views
15

Going nuts con questo problema. Ho una soluzione con 2 progetti, uno di questi è un semplice html vecchio con jquery chiamata ajax mentre l'altro è un servizio WCF. La pagina html invierà una chiamata ajax al servizio WCF per ottenere una stringa JSON e usarla a scopo di visualizzazione.Errore WCF: 405 Metodo non consentito

Ora il problema si verifica ogni volta che si esegue in modalità di debug, sia la pagina html che il WCF verranno avviati con una porta diversa. E questo ha creato per me un problema di origine incrociata quando eseguo i test (ad esempio ottenendo un errore 405 Metodo non consentito con il tipo di chiamata = OPZIONI in Firefox). Vorrei triplicare il metodo di chiamata sul mio script ajax e il servizio WCF è lo stesso (GET).

Vorrei cercare su google, ma ho scoperto che devo installare un'estensione o eseguire alcune configurazioni su IIS, che ho trovato ingombrante dal momento che quello che sto facendo è qualcosa di semplice. A seguito di un esempio, mi piacerebbe aggiungere nella seguente configurazione nel mio web.config, ma non ha funzionato:

<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> 

Ognuno ha la minima idea di sbarazzarsi di questo problema fastidioso?

EDIT: solo aggiungere, sto correndo il debug con IIS Express fornito insieme al VS Studio 2012

Aggiungere nel Codice WCF e web.config Aggiornato

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

Il mio 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); 

     } 
    }); 
}); 
+0

Questo collegamento potrebbe aiutare http://stackoverflow.com/questions/2202500/wcf-service-405-method-not-allowed-exception – Mihai

+0

Grazie. Ho provato ma non ha funzionato. – ipohfly

+0

ops ok ... ma se nessuna delle risposte ha veramente aiutato allora dovrei scegliere quella più vicina? – ipohfly

risposta

8

È necessario utilizzare JSONP per una chiamata tra domini per aggirare t le restrizioni del browser e per aggiornare il proprio web.config con crossDomainScriptAccessEnabled impostato su true per ottenere quelle del server. C'è un buon esempio nella risposta qui: how to avoid cross domain policy in jquery ajax for consuming wcf service?

Si può anche avere un problema con richieste GET. Prova il fix qui esposti: Making a WCF Web Service work with GET requests

Complessivamente, si desidera un web.config che sembra qualcosa di simile:

<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> 

(Si noti che sia il servizio e il punto finale hanno comportamenti collegati, consentendo chiamate webHttp e chiamate httpGet e il collegamento ha l'accesso crossDomain abilitato esplicitamente).

... un metodo di servizio decorato in questo modo:

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

... e una chiamata client utilizzando JSONP:

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

Grazie. Ho appena provato ma non ha funzionato, il collegamento all'esempio lato client era morto. Ho provato ad aggiungere i binding crossDomain nel mio web.config ma non ha funzionato. – ipohfly

+0

Basta fare il google o cercare qui JSONP - ci sono un sacco di esempi, come ad esempio: http://stackoverflow.com/questions/2681466/jsonp-with-jquery Il solo aggiustamento del lato server non funzionerà. – JcFx

+0

Inoltre, puoi mostrare il tuo codice WCF? Oltre a consentire WebGet in Web.Config (come nell'esempio sopra), devi decorare il tuo metodo WCF con l'attributo corretto. – JcFx

7

Tuttavia la sua un vecchio thread, ma vorrei aggiungere la mia commento sui problemi che ho affrontato e la soluzione che ho ottenuto per il lavoro di CORS. Sto sviluppando un servizio Web nel seguente ambiente:

  1. servizio Web WCF.
  2. .NET 3.5 framework.
  3. Aggiunto il servizio Web di wcf nel sito Web asp.net esistente.
  4. Visual Studio 2008

La maggior parte delle persone menzionate su come aggiungere l'attributo crossDomainScriptAccessEnabled nel tag sotto <webHttpBinding> nel web.config. Non sono sicuro che funzioni o meno, ma non è disponibile nella versione 3.5, quindi non ho avuto scelta. Ho anche scoperto che aggiungendo i seguenti tag in web.config funzionerà ...

<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>

ma senza fortuna ... continuato a ottenere 405 Metodo di errori non sono ammessi

Dopo aver lottato molto con queste opzioni ho trovato un'altra soluzione per aggiungere queste intestazioni nel file Global.asax in modo dinamico secondo la data di seguito ...

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(); 
    } 
} 

e rimuovere il da web.config. Pubblica il sito web e continua con il lato client jquery/ajax ... e otterrai i dati dalle chiamate API. In bocca al lupo!

+0

non funziona ancora ottiene 405 dalle opzioni. –

2

Volevo semplicemente aggiungere alcuni problemi con la rilavorazione di CORS in basso. Il problema è che se l'input non supporta il metodo GET e POST, la richiesta OPTIONS non restituisce effettivamente le intestazioni consentite corrette. In realtà non sta guardando quali metodi sono effettivamente consentiti sull'endpoint WCF - è solo artificialmente dicendo che "GET, POST" sono consentiti per ogni singolo endpoint nell'applicazione quando un client esegue una richiesta OPTIONS (che è in realtà il client che chiede cosa è supportato).

Questo è probabilmente OK, se non si sta realmente facendo affidamento sulle informazioni nel metodo OPTIONS per restituire un elenco valido di metodi (come nel caso di alcune richieste CORS) - ma se lo si è, è necessario fare qualcosa di simile la soluzione su questa domanda: How to handle Ajax JQUERY POST request with WCF self-host

in sostanza, ogni endpoint dovrebbe attuare:

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

e chiamare un metodo appropriato che carica le intestazioni appropriate alla risposta (incluso il proprio " Access-Control-Allow-Meth od "lista per quel punto finale) al chiamante. È una specie di succhiare che gli endpoint WCF ospitati non lo fanno automaticamente per noi, ma questa è una soluzione che consente un controllo più preciso sull'endpoint. In questa soluzione le intestazioni di risposta corretta sono caricati alla realizzazione finale:

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

tenta di utilizzare. WebInvoke(Method = "POST") invece di WebInvoke(Method = "GET")

Problemi correlati