WCF and IsWrapped MessageContracts

The IsWrapped property on a messagecontract is keeping me busy. When working with WSSF it’s forcing you to set the IsWrapped property to true when you have more than one element in your message contract. This is because this required by the WS-I Basic profile1.1 standard. So you set the property to true and don’t have any idea what this will do to the proxy which is generated for you. In this post i will describe four possible scenarios and there effect on the proxy which is influenced by the choice you make. The possible scenarios are summarized in the table below:

  Request IsWrapped  Response IsWrapped 
Scenario 1 True  False 
Scenario 2  False True 
Scenario 3 False False
Scenario 4 True True

 

Well I desgined a simple service called CaseService. This service implements the ICaseService interface. This interface contains one operation RetrieveCase which accepts a casenumber (string) as input paramter and returns a Case object.

The messagecontract I used are: RetrieveCaseRequest and RetrieveCaseResponse.

Scenario 1

In this scenario I set the property IsWrapped of the RetrieveCaseRequest to true and the IsWrapped property of the RetrieveCaseResponse to false. When I build this service and generate a proxy for this service this will give me the following code (I stripped code which is irrelevant for this post):

public WCFService.Client.Proxy.Case RetrieveCase(WCFService.Client.Proxy.RetrieveCaseRequest RetrieveCaseRequest)
        {
            WCFService.Client.Proxy.RetrieveCaseRequest1 inValue = new WCFService.Client.Proxy.RetrieveCaseRequest1();
            inValue.RetrieveCaseRequest = RetrieveCaseRequest;
            WCFService.Client.Proxy.RetrieveCaseResponse retVal = ((WCFService.Client.Proxy.CaseService)(this)).RetrieveCase(inValue);
            return retVal.Case;
        }

The extra generated messagcontract

[System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
    public partial class RetrieveCaseRequest1
    {

There are two Request MessageContracts generated: RetrieveCaseRequest and RetrieveCaseRequest1. The RetrieveCaseRequest1 is a wrapper for the RetrieveCaseRequest. It looks like that the proxy will balance the request and response to the same IsWrapped setting. They are both send over the line with IsWrapped set to false.

The proxy will send the RetrieveCaseRequest1 (IsWrapped=false) and will receive RetrieveCaseResponse (IsWrapped=false). The RetrieveCaseRequest method in the proxy will accept a request messagecontract as input.

Scenario 2

In this scenario we will switch the IsWrapped settings. For the Request it will be set to false and for the response it will be set to true. Scenario 2 will give us the situation which is vica versa of scenario 1. There is one Request MessageContract and there are two Response MessageContracts: RetrieveCaseResponse and RetrieveCaseResponse1. The RetrieveCaseResponse1 is used as a wrapper contract for the RetrieveCaseResponse. Also notice the input parameter of the method RetrieveCase in the proxy. It’s a CaseNumber (string) and not a messagecontract like in scenario 1. It will wrap it into a messagecontract before sending it to the service.

public WCFService.Client.Proxy5.RetrieveCaseResponse RetrieveCase(string CaseNumber)
        {
            WCFService.Client.Proxy5.RetrieveCaseRequest inValue = new WCFService.Client.Proxy5.RetrieveCaseRequest();
            inValue.CaseNumber = CaseNumber;
            WCFService.Client.Proxy5.RetrieveCaseResponse1 retVal = ((WCFService.Client.Proxy5.CaseService)(this)).RetrieveCase(inValue);
            return retVal.RetrieveCaseResponse;
 }

Scenario 3

In the third scenario i have set both message contracts (request and response) to false. This results in the following proxy method:

public WCFService.Client.Proxy3.Case RetrieveCase(string CaseNumber)
        {
            WCFService.Client.Proxy3.RetrieveCaseRequest inValue = new WCFService.Client.Proxy3.RetrieveCaseRequest();
            inValue.CaseNumber = CaseNumber;
            WCFService.Client.Proxy3.RetrieveCaseResponse retVal = ((WCFService.Client.Proxy3.CaseService)(this)).RetrieveCase(inValue);
            return retVal.Case;
        }
As you can see, it will  accept a casenumber as input and a case object as return parameter. The proxy will wrap a messagecontract around the type before sending it to the service and strips the messagecontract before returning the response to the consumer of the proxy. Remember that you don’t always have the option to set the iswrapped property to false. When your messagecontract has multiple elements it will need the iswrapped property set to true.

Scenario 4

In this scenario I will set for both the Request and Response messages the IsWrapped property to true.

public WCFService.Client.Proxy2.Case RetrieveCase(string CaseNumber)
{
            WCFService.Client.Proxy2.RetrieveCaseRequest inValue = new WCFService.Client.Proxy2.RetrieveCaseRequest();
            inValue.CaseNumber = CaseNumber;
            WCFService.Client.Proxy2.RetrieveCaseResponse retVal = ((WCFService.Client.Proxy2.CaseService)(this)).RetrieveCase(inValue);
            return retVal.Case;
        }

As you can see this scenario contains the same proxy method as scenario 3.

I have experienced three of the four scenarios on projects and i was wondering how is it possible that my proxy is looking different when i am switching the iswrapped properties. I hope that this post will give you some information about the iswrapped property and will give you some ideas when you are running in the same kind of proxies with different faces.

Regards,

Dennis

Advertisements

Building transactional services with WSSF

When you are familiair with the WebService Software Factory (WSSF) you probably know that this tool uses three kind of models to make developing services much easier:

  • DataContractModel
  • ServiceContractModel
  • HostModel

In this post I would like to focus on the ServiceContractModel. This model generates messagecontracts and a servicecontracts. The servicecontract looks like a normal  interface where signatures of methods are defined. The only difference is that a servicecontract also contains two kind of attributes:

The properties of both attributes can be modified with the designer of WSSF. One drawback of WSSF is that it’s not possbile to add more attributes to the servicecontract. When you want to build a transactional WCF service with WSSF you have to do some coding by yourself. This isn’t a problem, but the combination of writing your own code and generate code with WSSF could become a problem if you not doing it right.

There are a couple of steps you need to take before your service is supporting transactions. For a guide step by step take a look here. In this post I will only talk about how you should decorate your interface and how to do this with WSSF. In your interface you are able to determine which operation could join or start a transaction. Foreach operation who should be available for a transaction you should decorate the operation with a TransactionFlowAttribute.  

Adding this attribute should be done by hand. When you have decorated your interface correctly and followed the steps in the blogpost above, then your ready to go. But what happens when you have checked in your code and your colleague is working on the servicemodel and clicks on the generate button. You don’t get any errors, but you don’t see any transaction enlisted anymore in your Distributed Transaction Coordinator (DTC). One of the steps you need for a transactional service is removed from your code. The servicecontract is regenerated, this means that the old servicecontract with the TransactionFlowAttribute is replace with the new one generated by WSSF.

I could only think of one solution to avoid such an situation. The solution would be adding the TransactionFlowAttribute to the class (the service) who is also implemeting the interface. This isn’t a perfect situation, but it could avoid strange behavior in your transactional service.

Regards,

Dennis

Entlib integration in WSSF

HI,

Avanade (Gerben van Loon and David Slot) build a very nice extension for WSSF. This extension makes Entlib integration possible for your service layer without programming a single line of code. Very cool. Check it out on CodePlex.

Regards

WSSF: ambiguous datacontracts

Hi all,

I’ve been working with Webservice Software Factory (WSSF) for 2 months now and i am pretty happy with this tool. The WSSF provides you with 3 models:

  • ServiceContract
  • DataContract
  • Host

These 3 models can help you with clicking a webservice together. For a nice introduction about WSSF check the following link:

http://msdn2.microsoft.com/nl-nl/magazine/cc164250(en-us).aspx

In this article my colleagues Gerben van Loon and Gerardo de Geest give you a very good first impression of the possiblities of WSSF.

One major thing that’s missing in WSSF is shared types. When you create multiple service contracts based on the same datamodel which is a pretty normal thing to do. Every service that is using the same classes (datacontracts) in the datamodel generates it own version of the class in the proxy.

So Lets say you have Service A and Service B. Both these services use the datacontract Address. When you generate a proxy in the HostModel there will be 2 proxies generated. Both proxies contain the Address datacontract. When you put these proxies in a project “ServiceAgent”, because you want to centralize every proxy in one project you will receive errors because the dataContract Address is ambiguous. 

I think that there are 2 ways to solve this problem:

  • use namspaces
  • generate one central datacontract

Use namespaces
Using namespaces could solve the problem. You can change the namespace that is standard used when you generate the proxy. This means that you should create a new namespace for every proxy you generate. Well i think that namespace should be used to give a good structure to the framework and should not be abused to fix a problem of double generate datacontracts.

Generate one central datacontract
Creating one datacontract which every service can use is ideal, but how could we fix this? When we look at the Host model of WSSF we only have two options:
– Generate Proxy
– Generate Service

If we want to separate the proxy from the datacontract, then we have to change the process for generating the proxy. This could be done in WSSF but if you want to fix this we have to rebuild the whole factory. You could also stop using the generate proxy option of WSSF and create you own generate proxy process with the command-line tool svcutil. This tool provides us with a lot of options to create different kind of objects. We want to create a datacontract (c# file) and a proxy. To fix this it’s important you should use the implementation project Datacontracts within your WSSF solution. This project becomes available when right-clicking on your solution. click Add and then there are 2 WSSF options:

  • ASMX implementation project
  • WCF implementation project

Datacontract

I have selected the second option. When you richt click in your DataContractDesigner you will see an option Generate Code. When your model is valid it will generate the code in 2 of your implementation projects:

  • <name of your project>.DataContract
  • <name of your project>.FaultContract

Because the datacontracts are generated into my implementation project (separated files) i need to build the projects to generate one dll file. This file is important as input for my datacontract and proxy generation. When the dll is available i can generate a file (in my case c#) which will contain all my datacontracts. See the command below:

  • svcutil.exe /dconly <Location of the Datacontract dll>
  • svcutil.exe /dconly <The generated XSD file> /out:<Output location>/n:<Namespace> /s
/dconly The /dconly switch is used to generate only a datacontract.
/out I use the /out switch because i want to define the location where my c# file will be deployed. My output location is the Client application which is also generated when you create your implementation projects. Because my output location is in my Client application i have directly access to my new generated datacontract.
/namespace I use this to make sure that the datacontract will have an appropriate namespace
/s The /s switch is used to make sure that every datacontract will be decorated with the serializable attribute.

The result of the first statement above will be a xsd file, which will be used as input for the second/final statement.

Proxy

Now that we have generated a datacontract we have to instruct the svcutil tool to generate a proxy without generating the datacontracts it uses. This means we have to give a reference to the datacontracts dll we want to use. The statement below is a statement that you can use to fix this:

svcutil.exe <The address of your webservice>  /r:<a reference to the datacontract dll> /r:<a reference to the faultcontract dll> /namespace:<namespace of your proxy> /out:<Output proxy file> /ct:<CollectionTypes>

/r: Used to make a reference to the datacontract or Fault contract dll. You can define multiple reference in on statement
/namespace I use this to make sure that every generate proxy will be in the same namespace
/ct You have to specify the CollectionType datacontracts you have in your datamodel. if you don’t these will still be generate into your proxy. I my example it could be a datacontract Addresses

When you have generated a datacontract and a proxy separately you will never have problems with ambiguous datacontracts.

Regards,

Dennis