2009-10-22 10 views
7

Ho un servizio biblioteca WCF esposti attraverso il mio sito ASPX come segueProblema di chiamata WCF Servizio Biblioteca da jQuery

[System.ServiceModel.OperationContract] 
[System.ServiceModel.Web.WebInvoke(
Method= "POST", 
RequestFormat=System.ServiceModel.Web. WebMessageFormat .Json, 
ResponseFormat=System.ServiceModel.Web.WebMessageFormat .Json)] 
LogonResponse Logon(LogonRequest logonRequest); 


[System.Runtime.Serialization.DataContract] 
[ Serializable()] 
public class LogonRequest 
{ 
[System.Runtime.Serialization.DataMember] 
public string EMailAddress; 
[System.Runtime.Serialization.DataMember] 
public string Password; 
} 

nella mia pagina di test che posso chiamare sia attraverso MS Ajax: -

<asp:ScriptManager ID ="ScriptManager1" runat="server"> 
<Services> 
<asp:ServiceReference Path="~/testService.svc" /> 
</Services> 
</asp:ScriptManager> 
. 
. 
. 
function clsLogonRequest(eMailAddress, password) { 
this .EMailAddress = eMailAddress; 
this .Password = password; 
} 

function login(eMailAddress, password) { 
var LogonRequest = new clsLogonRequest(eMailAddress, password); 
name.API.IAPI.Logon(LogonRequest, onSuccess, onFailure); 
} 

function onSuccess(result) { 
$("#txtSessionId").val(result.SessionId); 
$("#txtUserName").val(result.Name); 
$("#txtUserId").val(result.UserId); 
} 

che funziona bene, o attraverso un jQuery $ .ajax chiamata: -

$(document).ready(function() { 
$("#Button1").click(function() { 
var LogonRequest = new clsLogonRequest('*************' , '***********'); 
$.ajax({ 
type: "POST", 
url: "testService.svc/Logon", 
data: "{'logonRequest':" + JSON.stringify(LogonRequest) + "}" , 
contentType: "application/json; charset=utf-8", 
dataType: "json", 
success: function(msg) { 
alert(msg.d); 
} 
}); 
}); 
}); 

Il che non - in FireBug posso vedere esimo E 500 Internal Server Messaggio di errore e l'eccezione inizia

{"ExceptionDetail":{"HelpLink":null,"InnerException":null,"Message":"The token '\"' was expected but found '''.","StackTrace":" at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3)\u000d\u000a at System.Xml.XmlExceptionHelper .ThrowTokenExpected(XmlDictionaryReader reader, String expected, Char found)\u000d\u000a at System.Runtime... 

perché lo fa apparire che la chiamata jQuery sta passando XML quando sono specificamente dicendogli di non (e come posso fermarlo in modo che le chiamate da tutte le fonti sono gestiti nel modo più naturale possibile)?

Grazie in anticipo.

EDIT:

Grazie per i suggerimenti, ho guardato quello che hai detto e pensare che la mia spiegazione del problema non era abbastanza chiaro.

Il problema non è che JSON non venga inviato, sia inviato ed è nel formato corretto, lo vedo da firebug. Il problema è che la libreria di servizi WCF sembra essere in attesa di XML e cade quando riceve JSON.

Giusto per essere sicuro di non aver trascurato la soluzione suggerita, ecco l'estratto web.Config - Ho provato a rimuovere dal comportamento e rimuovere l'attributo behaviorConfiguration dal tag services/service/endpoint e ciò rende l'intera faccenda fallisce senza uscire dalla pagina.

<system.serviceModel> 
<behaviors> 
<serviceBehaviors> 
<behavior name ="MyServiceTypeBehaviors "> 
<serviceDebug includeExceptionDetailInFaults="true" /> 
<serviceMetadata httpGetEnabled="true" /> 
</behavior> 
</serviceBehaviors> 
<endpointBehaviors> 
<behavior name ="AspNetAjaxBehavior"> 
<enableWebScript/> 
</behavior> 
</endpointBehaviors> 
</behaviors> 
<serviceHostingEnvironment aspNetCompatibilityEnabled= "true " /> 
<services> 
<service name ="test.API.API" behaviorConfiguration = " MyServiceTypeBehaviors"> 
<endpoint behaviorConfiguration="AspNetAjaxBehavior" binding = " webHttpBinding" contract="test.API.IAPI" /> 
<endpoint contract ="IMetadataExchange" binding= " mexHttpBinding" address="mex" /> 
</service> 
</services> 
</system.serviceModel> 

Grazie in anticipo

risposta

13

Sto indovinando aver applicato il (elemento enableWebScript in config) WebScriptEnablingBehavior? Ciò fa sì che tutte le richieste vengano racchiuse in un oggetto JSON con un singolo campo denominato "d" che quindi contiene un oggetto con i parametri specificati. Così si avrebbe bisogno di modificare i dati di jQuery per essere:

data: "{d:{logonRequest:" + JSON.stringify(LogonRequest) + "}}" 

Uno che o rimuovere il comportamento enableWebScript, ma, se lo fai, è necessario applicare il comportamento webHttp invece. Ora, sfortunatamente, la codifica predefinita è quindi XML e il comportamento non offre alcun interruttore per controllare la codifica per un intero servizio (progettazione errata di MSFT). Quindi, o devi sposarti a una codifica specifica su ogni metodo impostando le proprietà Request/ResponseFormat, o, come ho gestito questo in passato, è che ho creato un "EnhancedWebHttpElement" che applica lo stesso WebHttpBehavior, ma dà il controllo del livello di configurazione sulle sue varie proprietà. Il vantaggio dell'utilizzo di questa configurazione è che ora è possibile esporre lo stesso servizio WCF tramite endpoint diversi utilizzando la codifica AJAX di ASP.NET su uno, JSON semplice sull'altro e forse anche POX su un altro.

Ecco il codice:

public sealed class EnhancedWebHttpElement : BehaviorExtensionElement 
{ 
    #region Type specific properties 

    [ConfigurationProperty("defaultBodyStyle", DefaultValue=WebMessageBodyStyle.Bare)] 
    public WebMessageBodyStyle DefaultBodyStyle 
    { 
     get 
     { 
      return (WebMessageBodyStyle)this["defaultBodyStyle"]; 
     } 

     set 
     { 
      this["defaultBodyStyle"] = value; 
     } 
    } 

    [ConfigurationProperty("defaultOutgoingRequestFormat", DefaultValue=WebMessageFormat.Xml)] 
    public WebMessageFormat DefaultOutgoingRequestFormat 
    { 
     get 
     { 
      return (WebMessageFormat)this["defaultOutgoingRequestFormat"]; 
     } 

     set 
     { 
      this["defaultOutgoingRequestFormat"] = value; 
     } 
    } 

    [ConfigurationProperty("defaultOutgoingResponseFormat", DefaultValue=WebMessageFormat.Xml)] 
    public WebMessageFormat DefaultOutgoingResponseFormat 
    { 
     get 
     { 
      return (WebMessageFormat)this["defaultOutgoingResponseFormat"]; 
     } 

     set 
     { 
      this["defaultOutgoingResponseFormat"] = value; 
     } 
    }  

    #endregion 

    #region Base class overrides 

    protected override object CreateBehavior() 
    { 
     WebHttpBehavior result = new WebHttpBehavior(); 

     result.DefaultBodyStyle = this.DefaultBodyStyle; 
     result.DefaultOutgoingRequestFormat = this.DefaultOutgoingRequestFormat; 
     result.DefaultOutgoingResponseFormat = this.DefaultOutgoingResponseFormat; 

     return result; 
    } 

    public override Type BehaviorType 
    { 
     get 
     { 
      return typeof(WebHttpBehavior); 
     } 
    } 

    #endregion 
} 

E poi bisogna registrarlo:

<system.serviceModel> 
    <extensions> 
     <behaviorExtensions> 
      <add name="enhancedWebHttp" type="MyNamespace.EnhancedWebHttpElement, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
      </behaviorExtensions> 
    </extensions> 

E poi lo si utilizza in questo modo:

<behavior name="MyBehavior"> 
    <enhancedWebHttp defaultOutgoingRequestFormat="JSON" defaultOutgoingResponseFormat="JSON" /> 
</behavior> 

UPD ATE:

Questa risposta sopra si applica rigorosamente a .NET 3.x. Se si utilizza .NET 4.x, è ora possibile utilizzare the DefaultOutgoingResponseFormat property esposto su WebHttpElement per controllarlo. Ancora meglio, puoi esporre un singolo endpoint e impostare the new AutomaticFormatSelectionEnabled property che risponderà con il formato corretto in base al formato in cui si trovava la richiesta.

+0

grazie per il suggerimento, ho modificato il mio post originale per chiarire. – bean

+1

L'eccezione sembrerà sempre che analizzi l'XML perché è il modello utilizzato da WCF anche quando i dati non sono veramente XML. Nel caso di JSON viene utilizzato DataContractJsonSerialzer, ma anche quello ereditato da XmlObjectSerializer e quindi lo stack può far sembrare che funzioni con XML. Se potessi pubblicare la traccia completa dello stack che sarebbe utile pure. Tutto il resto della tua configurazione sembra soddisfacente, ma con enableWebScript lì DEVI superare l'oggetto wrapper come ho detto. Se si rimuove l'abilitazioneWebScript, sarà necessario impostare personalmente la codifica dei messaggi su JSON. –

+0

Ho letteralmente preso a pugni la quantità di lavoro necessaria per ottenere i servizi "WCF Ajax Enabled" in modo che diventino "Ajax Enabled". –