Sonntag, Juli 06, 2008

Calling WCF and SOAP based webservices from AJAX

The JavaScript proxy that is implemented for the Ajax engine to call SOAP based web services has been used on the ASP.NET platform for a long time and was ported to other platforms like Java. Some derived work can also be found for PHP and the Qooxdoo. It’s pretty stable for a while and that’s a good message.

When working with some specific Java based platforms there was a specific problem with the automatic generated WSDL descriptions, because they use an external schema for defining the structure of the passed data:

<wsdl:types> <xsd:schema targetNamespace="http://tempuri.org/Imports"> <xsd:import schemaLocation=http://localhost/AJAXEngine/S02_AJAXCoreSamples/CalcFactors.svc?xsd=xsd0

namespace="http://tempuri.org/" /> ... </xsd:schema> </wsdl:types>

The workaround was to write the JSON structure that is used by the JavaScript proxy by hand (and that is still a good idea for high trafic web sites).

When adopting the WCF .svc services this kind of using WSDL and XML schema definitions can be found too.

A solution for this is quiet simple and can now be found in the wsdl.xslt and the GetJavaScriptProxy.aspx files.

wsdl.xslt

The WSDL to JavaScript transformation now looks for import nodes under the wsdl:types and then imports the referenced schema by using the xslt document() function. Then this imported document is searched for the right element and the parameter and return value description is generated through the soapElem template. Here is the added xslt code:

<xsl:when test="/wsdl:definitions/wsdl:types/s:schema/s:import">

<!-- importing an external schema –>

<xsl:variable name="inputElementName" select="substring-after(wsdl:part/@element, ':')" />

<xsl:for-each select="/wsdl:definitions/wsdl:types/s:schema/s:import">

<xsl:variable name="doc" select="document(@schemaLocation)"/>

<xsl:for-each select="$doc/s:schema/s:element[@name=$inputElementName]//s:element">

<xsl:call-template name="soapElem">

<xsl:with-param name="name" select="@name" />

<xsl:with-param name="type" select="@type" />

</xsl:call-template>

<xsl:if test="position()!=last()">,</xsl:if>

</xsl:for-each>

</xsl:for-each>

</xsl:when>

GetJavaScriptProxy

In the .NET environment the document function will not work for security reasons without some special instructions for the xslt transform. When passing a  XmlUrlResolver when loading the xslt file the document() function can retrieve the referenced external document.

XmlUrlResolver resolver = new XmlUrlResolver();
resolver.Credentials = CredentialCache.DefaultCredentials;

XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load(Server.MapPath("~/ajaxcore/wsdl.xslt"), XsltSettings.TrustedXslt, resolver);

Implementing a WCF service for Ajax

Implementing a WCF service for Ajax is almost as simple as programming an *.asmx based service but you can also use an external C# class or interface for implementing the service.

You can find a sample source code in:

http://www.mathertel.de/AJAXEngine/S02_AJAXCoreSamples/CalcFactors.svc

The configuration

By default the WCF services use the SOAP 1.2 format but we don’t need the ws-* functionality and the soap basic profile is perfect for using webservice with AJAX solutions. This can be done by using the following configuration in web.config:

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior name="AjaxBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="false" />
      </behavior>
    </serviceBehaviors>
  </behaviors>

  <services>
    <service behaviorConfiguration="AjaxBehavior" name="CalcFactors">
      <endpoint address="" binding="basicHttpBinding" contract="CalcFactors" />
    </service>
  </services>
</system.serviceModel>

Keine Kommentare: