Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

Friday, September 24, 2010

WSDL-First development with Visual Studio

This is how I implemented the WSDL-First approach when creating a WCF service with Visual Studio.

An example of a simple WSDL:

<?xml version="1.0" encoding="utf-8"?>
<definitions
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://www.myweb.com/ws/"
  xmlns:s="http://www.w3.org/2001/XMLSchema"
  xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
  targetNamespace="http://www.myweb.com/ws/"
  xmlns="http://schemas.xmlsoap.org/wsdl/">
  <types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://www.myweb.com/ws/">
      <s:element name="DoSomething">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="param1" type="s:string" />
            <s:element minOccurs="0" maxOccurs="1" name="param2" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="DoSomethingResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="DoSomethingResult" type="tns:TheDTO" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:complexType name="TheDTO">
        <s:complexContent mixed="false">
          <s:extension base="tns:BaseDTO">
            <s:sequence>
              <s:element minOccurs="0" maxOccurs="1" name="Att1" type="s:string" />
            </s:sequence>
          </s:extension>
        </s:complexContent>
      </s:complexType>
      <s:complexType name="BaseDTO" abstract="true">
        <s:sequence>
          <s:element minOccurs="0" maxOccurs="1" name="BaseAtt1" type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" name="BaseAtt2" type="s:string" />
        </s:sequence>
      </s:complexType>
    </s:schema>
  </types>
  <message name="DoSomethingSoapIn">
    <part name="parameters" element="tns:DoSomething" />
  </message>
  <message name="DoSomethingSoapOut">
    <part name="parameters" element="tns:DoSomethingResponse" />
  </message>
  <portType name="IService">
    <operation name="DoSomething">
      <documentation xmlns="http://schemas.xmlsoap.org/wsdl/">Do something.</documentation>
      <input message="tns:DoSomethingSoapIn" />
      <output message="tns:DoSomethingSoapOut" />
    </operation>
  </portType>
  <binding name="TheServiceSoap" type="tns:IService">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <operation name="DoSomething">
      <input>
        <soap:body use="literal" />
      </input>
      <output>
        <soap:body use="literal" />
      </output>
    </operation>
  </binding>
  <service name="TheService">
    <port binding="tns:TheServiceSoap" name="TheServicePort"/>
  </service>
</definitions>

Tip: It can be useful to download a WSDL-template to start with, instead of writing it from scratch.
Use the svcutil utility to save the WSDL-file exported from a service:

> svcutil /t:metadata http://localhost:8731/TheService/Service/

I added a Pre-Build command that reads my WSDL-file and creates an interface file in preferred language, in my case C#:

svcutil /language:C# /n:*,TheService /out:$(ProjectDir)IService.cs $(ProjectDir)\TheService.wsdl

The IService.cs will be regenerated each time I initiates a build so I adds the implementation of the interface in a separate file, Service.cs.

using System;
namespace TheService
{
    using System.ServiceModel;

    [ServiceBehavior(Namespace = "http://www.myweb.com/ws/")]
    public class Service : IService
    {
        public TheDTO DoSomething(string param1, string param2)
        {
            throw new NotImplementedException();
        }
    }
}

It is preferable to store the WSDL file separately in the VCS, then you can redesign both server and clients without affecting the functionality, as long as they use the same version of the WSDL file.

 

The WSDL can now be used to create service clients.
For example, to create a .NET client, use the svcutil utility to create the service proxy code:

> svcutil TheService.wsdl

The svcutil utility creates a Service.cs that you include in the client project, and then the service can be invoked as if it were a local object.

var myService = new ServiceClient();

TheDTO result = myService.DoSomething("A", "B");

Tuesday, July 7, 2009

Register WCF COM proxies with WIX

This is how I get the registration of WCF COM Proxies to work in WIX installation packets.

The CLSID and APPID are regenerated by the framework each time the version of the assembly is changed by. Avoid that by adding a Guid attribute to the COM proxy interface file (that’s the one generated with svcutil.exe).
I have still not managed to define all guid’s in the WCF Service interface file which I would prefer, as the proxy interface file changes are destroyed each time its regenerated.

namespace MyComProxy
{
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(Namespace="http://myservices.com", ConfigurationName="MyService.IMyInterface")]
    [Guid("E055A238-F196-3EF1-ADE2-AB124C197A1F")]
    public interface IMyInterface
    {
        [System.ServiceModel.OperationContractAttribute(Action="http://myservices.com/IMyInterface/DoSomething", ReplyAction="http://myservices.com/IMyInterface/DoSomethingResponse")]
        string DoSomething(string newValue);
    }
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    [Guid("D1902FA8-A2DC-39BD-8009-6047F340E1CC")]
    public interface IMyInterfaceChannel : MyService.IMyInterface, System.ServiceModel.IClientChannel
    {
    }
    
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    [Guid("3BAA7AE8-70C7-3D37-92B9-39971872567D")]
    public partial class MyInterface : System.ServiceModel.ClientBase&lt;MyService.IMyInterface&gt;, MyService.IMyInterface
    {
...
Remember to add the Guid attributes again if the file has to be regenerated with svcutil.

Now its time to use heat.exe to generate the Registry keys that makes the proxy visible to COM clients.

Verify that the “Register for COM interop” is checked for the COM Proxy project. Visual Studio then creates a type library file during compilation.

comreg

First generate the keys for the type library (it’s not recommended to use the WIX Typelib element, that’s why I specify –scom to get the actual Registry keys):

heat file -scom MyService.tlb -out tlbtags.wxs

Copy the Registry tags from the output file and add them to the tlb-component in the wxs-file.

Then generate Registry keys for the assembly:

heat file MyService.dll -out dlltags.wxs

Copy those keys to the dll-component in the wxs-file (ignore the <Class> tags). The Codebase keys can be removed.

Thursday, May 28, 2009

Empty Actions when mocking Java Web Service

I get the
“System.InvalidOperationException: The operations methodX and methodY have the same action ().  Every operation must have a unique action value”, when trying to mock a Java Web Service with Rhino Mocks in CSharp.

The WSDL-file that was downloaded from the Java Web Service declared an empty soap action for each exported operation.
For example:

<operation name="aMethod">
  <soap:operation soapAction="" /> 
  <input>
   <soap:body use="literal" /> 
  </input>
  <output>
   <soap:body use="literal" /> 
  </output>
  <fault name="MyWebServiceException">
   <soap:fault name="MyWebServiceException" use="literal" /> 
  </fault>
</operation>

WCF uses the action to dispatch an incoming message to the correct method, see Action Property. Each method must have a unique action value.

I solved it by downloading the WSDL-file and remove all soap action declarations:

<soap:operation soapAction="" />

I ran the svcutil.exe on the changed WSDL-file.
WCF then creates unique action values in the service interface file, and the service can be mocked (as I described in Mocking WCF service).

Saturday, February 7, 2009

Mocking WCF service

We are using continuous integration (with help of CruiseControl.NET) in My current project. Some of the components connects to WCF-services. The continuous integration includes automated unit tests with NUnit.
We needed to mock the services as we don't want to install and run any services on the build server.
I have used Rhino Mocks in previous projects so I decided to give it a try. As always, I started to google for any experience out there, and found this blog which describes exactly what I wanted to do! http://kashfarooq.wordpress.com/2008/11/29/mocking-wcf-services-with-rhinomocks/
Use the WCF self hosting to host a dummy class that expose the service interface. The methods does not need to be implemented as they are mocked with Rhino Mocks.

Thursday, February 5, 2009

Consuming WCF Service From Classic ASP

Consuming WCF services from classic ASP is described on several places, for instance http://msdn.microsoft.com/en-us/library/bb735856.aspx#_Toc156817372.

I ran into the "The maximum string content length quota (8192) has been exceeded"-exception, i.e. the message I try to send is larger than 8192 bytes.

Ok, just to add a binding configuration to allow larger messages. But I consume the WCF service from VB Script with a moniker, so where to define the binding configuration?

It took a while before I realised that, as classic ASP does not have a web.config, the binding configuration has to be in the machine.config.

Not so dynamic but an acceptable solution.