2009-10-22 19 views
7

Mam WCF usługi Biblioteka wystawiony przez mojej stronie ASPX następującoProblem Wywołanie usługi WCF Biblioteka z 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; 
} 

Na stronie testowej można wywołać za pośrednictwem 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); 
} 

który działa dobrze, lub za pośrednictwem jQuery $ .ajax rozmowy: -

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

Co nie - pod FireBug widzę th e Komunikat o błędzie 500 Internal Server i wyjątek zaczyna

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

Dlaczego wydaje się, że wezwanie jQuery przechodzi XML kiedy jestem specjalnie informując go nie (i jak mogę zatrzymać go tak, że wywołuje ze wszystkich źródeł są obsługiwane tak naturalnie, jak to możliwe)?

Z góry dziękuję.

EDIT:

Dzięki za sugestie, szukałem na to, co powiedział i myślę, że moje wyjaśnienie problemu nie było wystarczająco jasne.

Problem nie polega na tym, że JSON nie jest wysyłany, jest wysyłany i ma poprawny format, widzę to z firebug. Problem polega na tym, że biblioteka usług WCF wydaje się oczekiwać XML i przewraca się po otrzymaniu JSON.

Dla pewności nie przeoczyłem sugerowanego rozwiązania, oto wyciąg Web.Config - próbowałem usunąć z zachowania i usunąć atrybut behaviorConfiguration z tagu services/service/endpoint, a to sprawia, że wszystko kończy się niepowodzeniem, nie wydostając się ze strony.

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

Dzięki z góry

Odpowiedz

13

Zgaduję masz zastosował (elementu enableWebScript w pliku .config) WebScriptEnablingBehavior? Powoduje to, że wszystkie żądania będą zawijane w obiekcie JSON z pojedynczym polem o nazwie "d", które następnie zawiera obiekt o nazwanych parametrach. Więc trzeba by zmienić dane jQuery być:

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

Albo to, albo usunąć zachowanie enableWebScript, ale jeśli to zrobisz, musisz zastosować zachowanie webHttp zamiast. Teraz niestety domyślnym kodowaniem jest XML, a zachowanie nie oferuje żadnych przełączników kontrolujących kodowanie całej usługi (zły projekt za pomocą MSFT). Tak więc, albo musisz poślubić siebie, aby sepcific kodowanie dla każdej metody, ustawiając właściwości Request/ResponseFormat, lub, jak sobie z tym poradziłem w przeszłości, jest to, że utworzyłem "EnhancedWebHttpElement", która stosuje to samo WebHttpBehavior, ale daje kontrolę poziomu konfiguracji nad jego różnymi właściwościami. Zaletą korzystania z tej konfiguracji jest to, że można teraz udostępnić tę samą usługę WCF za pośrednictwem różnych punktów końcowych za pomocą kodowania AJAX ASP.NET na jednym, zwykłym JSON na drugim, a może nawet na innym POX.

Oto kod:

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 
} 

A potem trzeba zarejestrować go:

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

A potem go używać tak:

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

UPD ATE:

Powyższa odpowiedź dotyczy wyłącznie .NET 3.x. Jeśli korzystasz z .NET 4.x, możesz teraz użyć the DefaultOutgoingResponseFormat property, który jest dostępny pod adresem WebHttpElement, aby to kontrolować. Co więcej, możesz odsłonić pojedynczy punkt końcowy i ustawić the new AutomaticFormatSelectionEnabled property, który będzie odpowiadał prawidłowym formatem w zależności od formatu oryginalnego żądania.

+0

dzięki za sugestię, zredagowałem mój pierwotny wpis, aby wyjaśnić. – bean

+1

Wyjątek będzie zawsze wyglądał tak, jakby analizował XML, ponieważ jest to model używany przez WCF, nawet jeśli dane nie są prawdziwie XML. W przypadku JSON używany jest DataContractJsonSerialzer, ale nawet ten dziedziczy po XmlObjectSerializer, więc stos może sprawić, że będzie wyglądał, jakby działał z XML. Jeśli mógłbyś opublikować pełny ślad stosu, który również byłby przydatny. Cała reszta konfiguracji wygląda dobrze, ale z włączonym opcją enableWebScript MUSISZ przekazać ten obiekt opakowania, tak jak powiedziałem. Jeśli usuniesz enableWebScript, będziesz musiał sam ustawić kodowanie wiadomości na JSON. –

+0

Dosłownie sprzeciwiłem się ilości pracy związanej z uzyskaniem usług "włączonego WCF Ajax", aby uzyskać efekt "Ajax włączony". –

Powiązane problemy