2009-10-22 10 views
7

J'ai une bibliothèque service WCF exposée à travers mon site ASPX comme suitProblème appel bibliothèque service WCF de 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; 
} 

Dans Ma page de test, je peux appeler soit par 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); 
} 

qui fonctionne très bien, ou par un appel jQuery $ .ajax: -

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

qui n'a pas - sous Firebug je peux voir e e 500 Message d'erreur interne du serveur et l'exception commence

{"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... 

Pourquoi apparaît-il que l'appel jQuery passe XML quand je suis spécifiquement dit-il pas (et comment puis-je l'arrêter afin que les appels de toutes les sources sont traitées aussi naturellement que possible)?

Merci d'avance.

EDIT:

Merci pour les suggestions, j'ai regardé ce que vous avez dit et je pense que mon explication du problème n'a pas été assez clair.

Le problème n'est pas que JSON n'est pas envoyé, il est envoyé et est dans le bon format, je peux le voir depuis firebug. Le problème est que la bibliothèque de service WCF semble attendre le code XML et tombe quand elle reçoit JSON. Pour être sûr que je n'ai pas oublié la solution suggérée, voici l'extrait web.Config - J'ai essayé de supprimer le comportement et de supprimer l'attribut behaviorConfiguration de la balise services/service/endpoint et cela fait juste le tout échoue sans sortir de la page.

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

Merci à l'avance

Répondre

13

Je devine que vous avez appliqué le (élément enableWebScript dans .config) WebScriptEnablingBehavior? Cela provoque toutes les demandes à être enveloppées dans un objet JSON avec un seul champ nommé "d" qui contient alors un objet avec vos paramètres nommés. Donc, vous devez modifier les données jQuery être:

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

Qu'ou supprimer le comportement enableWebScript, mais si vous faites cela, vous devez appliquer le comportement webHttp à la place. Maintenant, malheureusement, le codage par défaut est alors XML et le comportement n'offre aucun commutateur pour contrôler l'encodage pour un service entier (mauvaise conception par MSFT). Donc, soit vous devez vous marier à un encodage spécifique sur chaque méthode en définissant les propriétés Request/ResponseFormat, ou, comment j'ai géré cela dans le passé, c'est que j'ai créé un "EnhancedWebHttpElement" qui applique le même WebHttpBehavior, mais donne le contrôle du niveau de configuration sur ses différentes propriétés. L'avantage de l'utilisation de cette configuration est que vous pouvez maintenant exposer votre même service WCF via différents points de terminaison en utilisant l'encodage ASP.NET AJAX sur un seul, JSON simple sur l'autre et peut-être même POX sur un autre.

Voici le code:

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 
} 

Et alors vous devez l'enregistrer:

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

Et vous l'utilisez comme ceci:

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

UPD ATE:

Cette réponse s'applique uniquement à .NET 3.x. Si vous utilisez .NET 4.x alors vous pouvez maintenant utiliser the DefaultOutgoingResponseFormat property qui est exposé sur WebHttpElement pour contrôler cela. Encore mieux, vous pouvez exposer un seul point de terminaison et définir the new AutomaticFormatSelectionEnabled property qui répondra avec le format correct en fonction du format de la demande d'origine.

+0

merci pour la suggestion, j'ai édité mon message original pour clarifier. – bean

+1

L'exception ressemblera toujours à l'analyse XML car c'est le modèle utilisé par WCF même lorsque les données ne sont pas vraiment XML. Dans le cas de JSON, le DataContractJsonSerialzer est utilisé, mais même celui-ci hérite de XmlObjectSerializer et la pile peut donc donner l'impression qu'elle fonctionne avec XML. Si vous pouviez poster la trace complète de la pile, cela serait également utile. Tout le reste de votre config semble bien, mais avec enableWebScript là-bas, vous devez passer cet objet wrapper comme je l'ai dit. Si vous supprimez l'enableWebScript, vous devrez définir vous-même l'encodage des messages dans JSON. –

+0

J'ai littéralement lolé à la quantité de travail impliqué pour obtenir des services "WCF Ajax Enabled" pour devenir effing "Ajax Enabled". –

Questions connexes