Friday, November 6, 2009

Contract-First Web Services in practice - part 4 of 5 (.NET)

Welcome to part 4 of 5 of this article series putting contract first SOA through its paces. In the last article, I looked at how to create a php implementation of a wsdl defined in part two. In this article we look at how to create a service implementation in the .NET framework. This will be done in Visual Basic but could work for C#.NET.

Contract-first web service development is generally aspired to but often ignored in favour of code-first approaches because it is often quicker to do so. This is more so prevalent in the .NET framework where the ease of developing ".asmx" web services in Visual Studio drives people down this path. One way of creating "contract-first" web services is create a "code-first" one that closely resembles the contract you want to implement. This is may or may not work depending on the complexity of the contract and is not advised. The approach I advise is to create a binding interface using the "wsdl.exe" program that ships as part of the .NET framework or visual studio. With the path to this executable added to the %PATH% environment variable run the following command in a directory containing the wsdl file.

wsdl /language:VB /serverInterface SampleService.wsdl

If C#.NET artifacts are required replace the language with CS. This creates a single file "SampleServiceInterfaces.vb" that contains the data structures defined in the schema of the wsdl. It is heavily annotated to ensure that when the objects are serialized they are in compliance with wsdl. To complete the web service creation follow the steps below:
  1. Add the bindings interface to an existing or newly created ASP.NET web site.
  2. Now add a new "asmx" web service.
  3. Open the code behind class for the new web service. Make this class implement the binding interface instead of extending Service. Visual Studio should now create the stubs for the methods to be implemented.
  4. Implement the wsdl methods.
For our example, this should work brilliantly for our wsdl defined except for the typed exceptions. In the "infinite wisdom" of the designers of the .NET framework including thrown exceptions in the method signature is not supported. In fact, the binding interface does not create any types for the exceptions. I've created a custom class that creates the required xml for the exceptions.
  1. Imports System.Web.Services.Protocols  
  2. Imports System.Xml  
  5.       Public Class CustomSoapException  
  6.             Inherits SoapException  
  8.             Public Enum ExceptionCode  
  9.                   ServiceException  
  10.             End Enum  
  12.             Public Sub New(ByVal ExCode As ExceptionCode, ByVal Message As String)  
  13.                   Me.New(ExCode, SoapException.ClientFaultCode, Message)  
  14.             End Sub  
  16.             Public Sub New(ByVal ExCode As ExceptionCode, ByVal SoapFaultCode As XmlQualifiedName, ByVal Message As String)  
  17.                   MyBase.New(ExCode.ToString(), SoapFaultCode, Nothing, CreateXmlNode(ExCode, Message))  
  18.             End Sub  
  20.             ''' <summary>  
  21.             '''  
  22.             ''' <ServiceException>  
  23.             '''    <message>The exception message goes here.</message>  
  24.             ''' </ServiceException>  
  25.             '''  
  26.             ''' </summary>  
  27.             ''' <returns></returns>  
  28.             ''' <remarks></remarks>  
  29.             Private Shared Function CreateXmlNode(ByVal ExCode As ExceptionCode, ByVal Message As String) As XmlNode  
  30.                   Dim doc As New System.Xml.XmlDocument  
  32.                   Dim detailNode As System.Xml.XmlNode = doc.CreateNode(XmlNodeType.Element, SoapException.DetailElementName.Name, _  
  33.                               SoapException.DetailElementName.Namespace)  
  35.                   Dim excType As System.Xml.XmlNode = _  
  36.                               doc.CreateNode(XmlNodeType.Element, _  
  37.                               ExCode.ToString(), _  
  38.                               "")  
  40.                   Dim messageNode As System.Xml.XmlNode = _  
  41.                               doc.CreateNode(XmlNodeType.Element, _  
  42.                               "message", _  
  43.                               "")  
  46.                   messageNode.InnerText = Message  
  48.                   excType.AppendChild(messageNode)  
  50.                   detailNode.AppendChild(excType)  
  52.                   Return detailNode  
  53.             End Function  
  54.       End Class  
Throw an instance of this class to comply with the wsdl. That's it for the .NET implementation. In the next article I'll detail how to do the implementation in Java and wrap up my thoughts on the process.

No comments: