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

Wednesday, March 11, 2009

WCF Queued Dual Router Updated

I've updated the source for the WCF Queued Dual HTTP Request Response Router to now support sending out-of-band fault and notification messages back to the consumer.


The added unified fault handling support for router and services is using ChannelFactory<T> were T is IOutputChannel to support generic one-way channel shapes. The same generic WCF channel shape is used for sending notification messages.

The messages sent over the IOutputChannel are created using Message CreateMessage(...) to keep things generic in the router and on the service end. The fault and notification messages on the consumer end are of course strongly typed.

Faults and notification messages are sent from service providers using a ThreadStart delegate to send messages on separate threads to avoid being blocked by ongoing processing. This code is in the RoutedResponseScope class.

The sample code also shows how to integration "unit" test async dual WCF request-response MEPs with static EventHandler<T> events using anonymous delegates and ManualResetEvent thread synchronization.

Download the router example code here. The code is provided 'as-is' with no warranties and confers no rights. This example requires Windows Process Activation Service (Vista/WinServer2008), MSMQ 4.0 and .NET 3.0 WCF Non-HTTP Activation to be installed.

Wednesday, February 25, 2009

WCF Queued Dual HTTP Request Response Router

There are a lot of examples available for how to make WCF-based publish/subscribe messaging solutions, but not very many thay provides a simple queued dual HTTP request-response router. IDesign provides the queued Response Service from Juval Löwy's book Programming WCF Services, which provides a feature rich set of WCF goodies. Recommended. I've used it in combination with Sasha Goldshtein's Generic Forwarding Router to create a dual channel queued router.

The router container uses HTTP endpoints externally to interact with consumers, and MSMQ queues internally to talk to the service providers. This gives fewer queues to manage and monitor, and the consumers need not know anything about MSMQ.

The message forwarding ChannelFactory is cached for best performance. Read more about Channel and ChannelFactory caching in Wenlong Dong's post Performance Improvement for WCF Client Proxy Creation in .NET 3.5 and Best Practices.

Some useful resources related to making this router work:

Note the poorly documented requirement that the WAS activated service endpoint path must be reflected in the MSMQ queue name:

<add key="targetQueueName" value=".\private$\ServiceModelSamples/service.svc" />

<endpoint address=
"net.msmq://localhost/private/servicemodelsamples/service.svc"


Failure to adhere to this convention will prevent messages added to the queue from automatically activating the WAS-hosted WCF service. Also ensure that the WAS app-pool identity has access rights on the queues.

Download the router example code here. The code is provided 'as-is' with no warranties and confers no rights. This example requires Windows Process Activation Service (Vista/WinServer2008), MSMQ 4.0 and .NET 3.0 WCF Non-HTTP Activation to be installed.

Friday, February 20, 2009

WCF: Message Headers and XmlSerializerFormat

Sometimes you need to use the classic XmlSerializer due to interoperability or when doing schema first based on XSD contracts that contains e.g. XML attributes in complexTypes. I've used the [XmlSerializerFormat] switch on services many times without any problems, but recently I had to make use of a custom header - and that took me quite some time to get working.

This is the wire format of the header:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" >
<s:Header>
<h:CorrelationContext xmlns:h="urn:QueuedPubSub.CorrelationContext" xmlns="urn:QueuedPubSub.CorrelationContext" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<CorrelationId>c4e03aae-9501-46e9-bbb8-a9ddf6c4fe15</CorrelationId>
<FaultAddress>feil</FaultAddress>
<Priority>0</Priority>
<ResponseAddress>svar</ResponseAddress>
</h:CorrelationContext>
. . .

The WCF OperationContext provides access to the message headers:

CorrelationContext context = OperationContext.Current. IncomingMessageHeaders.GetHeader<CorrelationContext> (Constants.CorrelationContextHeaderName, Constants.CorrelationContextNamespace);

I had used [XmlElement] attributes to control the name and namespace of the [Serializable] class members, only to get this error:

'EndElement' 'CorrelationContext' from namespace 'urn:QueuedPubSub.CorrelationContext' is not expected. Expecting element 'CorrelationId'.

That really puzzled me. To make a long story short, the MessageHeaders class and GetHeader<T> method only supports serializers derived from XmlObjectSerializer, such as the DataContractSerializer - but not XmlSerializer. To make this work, your header class must be implemented as a [DataContract] class even for [XmlSerializerFormat] services.

My working message header contracts looks like this:

[DataContract(Name = Constants.CorrelationContextHeaderName, Namespace = Constants.CorrelationContextNamespace)]
public class CorrelationContext
{
[DataMember]
public Guid CorrelationId { get; set; }
[DataMember]
public string FaultAddress { get; set; }
[DataMember]
public int Priority { get; set; }
[DataMember]
public string ResponseAddress { get; set; }
}


[MessageContract(IsWrapped = true)]
[Serializable]
public abstract class MessageWithCorrelationHeaderBase
{
[MessageHeader(MustUnderstand = true, Name = Constants.CorrelationContextHeaderName, Namespace = Constants.CorrelationContextNamespace)]
[XmlElement(ElementName = Constants.CorrelationContextHeaderName, Namespace = Constants.CorrelationContextNamespace)]
public CorrelationContext CorrelationContext { get; set; }
}

This code was made and tested on .NET 3.5 SP1.

Wednesday, October 01, 2008

WCF: WS-Security using Kerberos over SSL

WCF support typical scenarios with the system provided bindings such as basicHttpBinding and wsHttpBinding. These bindings work very well in WCF-only environments and for interop scenarios where all parties are completely WS* standard compliant.

However, interop always seems to need some tweaking, and the ootb bindings allow you to change many aspects of the binding configuration. But there will always be scenarios where these bindings just cannot be configured to fit your needs. E.g. if you need a binding that supports custom wsHttp over SOAP1.1 using a non-negotiated/direct Kerberos WS-Security token secured by TLS. In this case you need a custom binding, because e.g. even if you can turn of spnego for wsHttpBinding, you cannot tweak it into using SOAP1.1

WCF <customBinding> to the rescue:

<customBinding>
<binding name="wsBindingCustom">
<security authenticationMode="KerberosOverTransport"

requireDerivedKeys="false"
includeTimestamp="true">
</security>
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
</customBinding>


This custom binding combines HTTPS transport with direct Kerberos.
The timestamp is required for security reasons when using authentication mode Kerberos over SSL. Note that using the UPN/SPN type <identity> element is only supported NTLM or negotiated security, and cannot be used with direct Kerberos.

WCF by default requires that the response always contain a timestamp when it is in the request. This is a typical interop issue with e.g. WSS4J, Spring-WS and WebSphere DataPower.

The response with the signed security header timestamp should be like this:
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsu:Timestamp wsu:Id="uuid-c9f9cf30-2685-4090-911b-785d59718267" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2008-09-29T12:02:59Z</wsu:Created>
<wsu:Expires>2008-09-29T12:12:59Z</wsu:Expires>
</wsu:Timestamp>



Note the casing of the wsse: and wsu: namespace elements and attributes. This replay attack detection timestamp can be turned off using the includeTimestamp attribute, or it can be configured using the <localClientSettings> and <localServiceSetting> security elements.

Refer to the <security> element of the <customBinding> documentation for more details. Also review the settings for initiating a WS-SecureConversation if a session is needed.

Saturday, September 06, 2008

How "Oslo" relates to BizTalk

The Microsoft "Oslo" initiative is to provide a modeling (UML), management, and hosting platform for delivering model-driven service-oriented composite applications and S+S solutions; plus cloud computing through modeling.

The recently published BizTalk 2009 roadmap shows how "Oslo" features can be utilized also from BizTalk:

In fact, you won’t need to upgrade BizTalk Server to take advantage of "Oslo" – current BizTalk Server 2006 R2 or BizTalk Server 2009 customers can benefit from "Oslo" by being able to leverage and compose existing services into new composite applications. BizTalk Server today provides the ability to service enable LOB systems or trading partners as web services (using WCF supported protocols), which can be composed with the "Oslo" modeling technologies.

As the roadmap shows, WCF is the central enabler for connecting services from different systems into service-oriented solutions. WCF and WF are central to the new "Oslo" modeling tool and repository, allowing users to define and execute business processes (much like BPEL, XLANG). "Oslo" has a strong focus on enabling automation of business processes with strong support for humans as central actors in the processes (like BPEL4People, WS-HumanTask). Add the BAM interceptors for WCF and WF provided by BizTalk, and you have a platform that gives repeatability, consistency and visibility to your business process management efforts.

Wednesday, August 06, 2008

Service Virtualization: MSE on Channel9

Service virtualization can be an important architectual mechanism for your service-oriented solutions, and the Managed Services Engine is a free WCF-based tool available at CodePlex.

There are two videos at Channel9 about MSE that I recommend watching to learn about the capabilities of MSE:
  • Code to live: service virtualization, versioning, etc
  • Talking about MSE: virtual services and endpoints, protocol adaption, policy enforcement, etc
A topic related to service virtualization is consumer-driven contracts, and you can do that with MSE, but the WCF LOB Adapter Kit might be an even better tool for that.

Monday, August 04, 2008

How "Oslo" relates to SOA

The upcoming Microsoft "Oslo" offering might be a bit vague to grasp, which I can readily understand. It has been perceived as a SOA implementation toolkit, but is rather focused on being a modeling (UML), management, and hosting platform for delivering model-driven service-oriented composite applications and S+S solutions; plus cloud computing through modeling. Read Loraine Lawson's Best Explanation of Oslo So Far for a rather typical experience.

Also look at the Oslo PDC sessions posted by Matt Winkler, on how "Oslo" is a service repository and a platform for both lifecycle management and hosting of services and processes. The service and process implementation tools in "Oslo" will be Visual Studio, WF, WCF, BizTalk, Zermatt, etc - and "Oslo" will be the one initiative to rule them all.

Directions on Microsoft on "Oslo": Messaging, Workflow Roadmap Announced (PDF)

Tuesday, July 01, 2008

WCF, SVCUTIL Proxy Problems

We've had some rather strange proxy problems with our WCF client code lately, with some PCs not being able to connect to the services using DNS names ("There was no endpoint listening at ... that could accept the message"), but working fine using the service's IP address. This happened even if all PCs had the same MSIE "bypass proxy server for local addresses" and the same exception list in "do not use proxy server for addresses beginning with".

To make a long story short, there is a "sneaky gotcha" in the proxy exceptions logic: port numbers are not considered to be a sub-domain. So an exception like this "*.blogspot.com" might not include e.g. "*.blogspot.com:12001" depending on your system setup. Alas, you can add your own <bypasslist> directly in the <system.net/defaultProxy> element. Note that the bypass list addresses must be valid regex expressions. Read more about proxies and <system.net> at
Matt Ellis' blog.

<system.net>
<defaultProxy useDefaultCredentials="true" >
<proxy usesystemdefault="True" bypassonlocal="True"/>
<bypasslist>
<add address=".+\.blogspot\.com:\d{1,5}" />
</bypasslist>
</defaultProxy>
</system.net>

For more info about WCF and proxies and how to do this from code, see Setting Credentials for your HTTP Proxy by Kenny Wolf.

The <system.net> proxy configuration can also be applied to SVCUTIL.EXE when e.g. proxy authentication is required to get the WSDL from the MEX endpoint.

Create a file named svcutil.exe.config in the directory where SVCUTIL.EXE is located to apply the proxy configuration to the tool. To pass user name and password use "username:password@" in front of the URL in the proxyaddress attribute. Do not store passwords in clear text like this.

PS! note how the casing of the attributes and values in the <proxy> element differs from what's normal.

Wednesday, June 18, 2008

WCF: Using Shared Types

In WCF you can use shared types from existing assemblies when generating a service proxy. Use the advanced options in VS2008, otherwise use SVCUTIL.EXE with the /reference /r option. Note that you can only use /reference when your WSDL operations, types and messages adheres to the DataContractSerializer rules that I described this spring.

I'm currently trying to research why we are not able to use shared types for our wsdl:fault message parts.

<wsdl:message name="GetCustomerRequest">
<wsdl:part element="tns:GetCustomerRequest" name="parameters" />
</wsdl:message>
<wsdl:message name="GetCustomerResponse">
<wsdl:part element="tns:GetCustomerResponse" name="parameters" />
</wsdl:message>
<wsdl:message name="FaultDetailList">
<wsdl:part element="fault:FaultDetailList" name="detail" />
</wsdl:message>

<wsdl:portType name="CustomerService">
<wsdl:operation name="GetCustomer">
<wsdl:input message="tns:GetCustomerRequest" name="GetCustomerRequest" />
<wsdl:output message="tns:GetCustomerResponse" name="GetCustomerResponse" />
<wsdl:fault message="tns:FaultDetailList" name="FaultDetailList" />
</wsdl:operation>
</wsdl:portType>


<wsdl:binding name="CustomerServiceSoap11" type="tns:CustomerService">
<soap:binding style="document" transport="
http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetCustomer">
<soap:operation soapAction="" />
<wsdl:input name="GetCustomerRequest">
<soap:body use="literal" />
</wsdl:input>
<wsdl:output name="GetCustomerResponse">
<soap:body use="literal" />
</wsdl:output>
<wsdl:fault name="FaultDetailList">
<soap:fault name="FaultDetailList" use="literal" />
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>

Even if the fault details contains only xs:string elements, we get this error when generating the proxy:

Cannot import wsdl:portTypeDetail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporterError: Referenced type 'SharedDataContracts.FaultDetailType, MyService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' with data contract name 'FaultDetailType' in namespace 'urn:kjellsj.blogspot.com/FaultDetail/1.0' cannot be used since it does not match imported DataContract. Need to exclude this type from referenced types.

I thought that writing a unit-test to import the WSDL using the underlying SVCUTIL importer directly should help me deduce the cause of the error. You will find all the code that you need to import WSDL using DataContractSerializerMessageContractImporter here at the "nV Framework for Enterprise Integration" project as CodePlex.

Add these lines to enforce the use of /namespace, /reference and /ct from code (note that these switches can be used multiple times):

xsdDataContractImporter.Options.Namespaces. Add(new KeyValuePair<string, string>("*", "MyService"));
xsdDataContractImporter.Options.ReferencedCollectionTypes. Add(typeof(List<>));
xsdDataContractImporter.Options.ReferencedTypes. Add(typeof(SharedDataContracts.FaultDetailList));
xsdDataContractImporter.Options.ReferencedTypes. Add(typeof(SharedDataContracts.FaultDetailType));

Sure enough, I get the exact same exception in my unit-test. Inspecting the imported contract shows that the operation has a fault with a "null" DetailType XML Schema type (watch: contracts[0].Operations[0].Faults[0].DetailType). I suspect that it is the "null" DetailType in the FaultDescription of the imported ServiceDescription for the WSDL that causes the error for the referenced shared types.

As it turns out this is a bug that has been fixed in .NET 3.5 SP1. The workaround for earlier versions of SVCUTIL is to add nillable="true" to all elements that are reference types (strings and complexTypes) in your wsdl:types XSD schemas. Or just drop the /reference switch and cut'n'paste the generated code to use your shared types.

Sunday, May 04, 2008

On Tokens, Claims, Tickets, SAML

There always seems to be a lot of confusion about tokens, tickets, and claims; which in combination with the very broad term security (authN, authZ, confidentiality, integrity, auditing, devices, data, etc) make every discussion about "security" a bit obscure.

A simple explanation of tokens and claims: a Security Token is a signed and encrypted set of Claims. A claim is just some right on a specific resource of a given resource type that the token holder claims to have. To accept this claim, you need to trust the token issuer. The typical example of a claim is the user's identity (the claim), which e.g. can be the domain login name (the resource) asserted by Windows (the issuer).

The terms Security Token and Claim are used in the WS-Trust standard. Kerberos use the term ticket instead of token, i.e. the ticket proves the identity of the user. A SAML token is another type of security token.

Watch the Channel9 video where Vittorio Bertocci explains WS-Trust and the token encryption and signing mechanism in depth, using a claim set based on a driver license resource. Note that only video download seems to work.

In addition, read the post series by Sam Gentile about SAML, which expands into claims-based security and WS-Trust / WS-Federation.

Wednesday, April 30, 2008

EntLib3 Replace Handler, ExceptionHandlingException

Using the Enterprise Library 3 exception replace handler can help you handle e.g. WCF FaultException<T> on the client and replace it with your own exception derived from ApplicationException. This will shield your client app from the different types of FaultException<T> where T: FaultContract types defined in the WSDL as wsdl:fault schemas and provide a normalized application exception type. This client-side exception shielding mechanism ensures that the proxy fault types need not be exposed outside your service agent.

There is one exception best practice to remember to implement for the @replaceExceptionType configuration to work: your derived exception must implement the three recommended constructors default, message, message and inner exception. If you forget, the entlib HandleException call will throw an "unable to handle exception" ExceptionHandlingException error.

Note the [[fault contract type]] syntax to be able to specify handlers for generic exceptions:

<add type="System.ServiceModel.FaultException`1[[MyServiceAgent.Proxy.GetCustomerListFault, MyServiceAgent.Proxy, Version=1.0.0.0]], System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction="ThrowNewException" name="MyApplicationException">


You have to edit the .config file manually as the EntLib3 editor does not support generics

Thursday, April 17, 2008

WCF: Design of Client Domain Objects

The client Domain Objects [Evans] (aka business entity - BE) must be related to the data contracts provided by the web-services. Still, they will need to be enhanced with e.g. dirty-tracking, validation, state, property conversions (xs:date), business rules, and other aspects needed to produce a fully working client application. This article describes how to achieve this when sharing domain objects across layers is not an option (i.e. interop with JEE services), and the same applies to AOP.

There are two models for this: annotating the BEs with XML serialization attributes to decorate the WSDL data contract, or creating separate Mapper classes [Fowler] in addition to the BE classes. The mapper will then map to and from the service proxy DTO objects [Fowler] at run-time. Note that the mapper model will be required whenever the BE is significantly different from the data contracts. Thus, BEs should be implemented using the first model to the maximum extent possible, only using the second model for advanced mapping requirements.

The decorator option is easier, performs better, and gives less code to maintain - but requires knowledge of XML serialization and will not give compilation errors when the data contract changes (even if the proxy is updated). Good integration test coverage is needed to make this option viable, i.e. to detect that the DTO's XML payload has changed.

Easier, less code: Only one BE class to implement and maintain as the BE is a Decorator object [GoF] wrapping the "DTO" XML. Note that there is no auto-generation of these classes and that there are no mappers or DTO objects. The BE classes are shared directly by the service proxies.
Performs better: There will only be one de-serialization step directly into the BE because it wraps the XML directly. This also applies to any nested child objects and collections - there will be no looping code to create and map the BE structure. The same applies to sending BE objects to the services - they will be directly serialized into "DTO" XML.
Contract change risks: As the BE classes are not auto-generated from the data contracts, changes to the contracts will not be automatically reflected in the serialization attributes on the BE properties. As (de)serialization happens at run-time, any mismatch between the XML and the serialization attributes cannot be detected by the compiler. Thus, adequate integration tests are required to detect that BE properties are not being set/read during (de)serialization. Breaking data contract changes will require that the serialization attributes are updated accordingly.

The mapper option is also quite easy, but performs worse and requires more code to be implemented and maintained (two classes: BE and mapper). However, it requires no knowledge of XML serialization and it will give compilation errors when the proxy + DTO objects are updated after data contract changes. Note that good unit testing is required to ensure that the mappings to and from the DTO objects are correct, including the complete object graph (nested child objects and collections).

Quite easy, more code: Two classes to implement and maintain, one BE class and one related mapper class. The mapper class must cover nested child objects and collections, both to and from the DTO objects. The DTO objects are auto-generated and will never be manually maintained by developers.
Performs worse: In addition to the de-serialization step of the DTO objects, the service agent must execute the mapping code to fill the BE object with data from the DTO object. Add to this extra transformation looping through nested child objects and collections, and the performance gets proportionally worse with the complexity of the object graph.
Contract change risks: The DTO objects are auto-generated based on the WSDL and are thus always in synch with the data contracts. Any breaking changes to the DTO classes will cause the mapper classes to give compilation errors. Breaking data contract changes will require that the mapper classes are updated accordingly - both to and from the DTO classes.

To complement this BE design approach, read the programming models for the Decorator option and the Mapper option to learn about the technical details and issues of each option.

Wednesday, April 16, 2008

WCF: Client Domain Objects, Decorator Pattern

The client domain objects (aka business entity - BE) must be related to the data contracts provided by the web-services. Still, they will need to be enhanced with e.g. dirty-tracking, validation, state, property conversions (xs:date), business rules, and other aspects needed to produce a fully working client application. This article describes how to achieve this when sharing domain objects across layers is not an option (i.e. interop with JEE services), and the same applies to AOP.

One option for implementing the BE objects, described in this article, is to apply the Decorator pattern to the WSDL scema-based DTO objects to enhance them into full-fledged domain objects. Read ‘
Design of Client Domain Objects’ for an intro this option and the related Mapper option.

If you do not like this Decorator option due to the weak [XML attribute] link to the data contracts (see end of article), you can always use a derived decorator class instead of a partial class. Make all your BE enhancements in the derived class using a combination of DTO overrides and new domain logic. If you prefer explicit, debuggable code, you're better off using the Mapper option.

Service Proxy

Use the SVCUTIL.EXE /REFERENCE switch when generating the proxy code and messages to reuse your BE objects as DTOs and to avoid getting new, duplicate DTO objects generated (might not compile due to name clashes). Alternatively, just remove the DTO code from the generated proxy. Make sure that the proxy code reference the .NET namespace and interface assembly that contains your BE objects.

Business Entities

You can use the data contract DTO objects generated by SVCTIL.EXE /DCONLY to get started. This will give you data-binding enabled (/EDB) anemic entity objects with all the properties in place, annotated with XML serialization attributes. Just ensure that the output files from SVCUTIL.EXE do not overwrite your code. The DTO objects become your generated BE objects - ready for decoration.

The BE objects must be manually maintained whenever you make changes to the generated BE code, e.g. to add EntLib3 validation attributes on the properties. Keep your additions to the generated BE in a partial class as far as possible, e.g. add new properties and methods in a partial class extending the decorated class. If all your decorator code can be isolated into a partial class, then the generated BE code can be re-generated without losing your extended BE code.

Our programming model for decorator-based client domain objects is based on using two partial classes; one T.schema.cs class file for all code based originally on the data contracts, and one T.cs class file for all added aspects. T is the type name of the BE.

Note that BE constructors will not be called during deserialization. Create a method to be used as a surrogate constructor to be run after deserialization and mark it with [OnDeserialized]. This is a good place for resetting e.g. the dirty flag:

[OnDeserialized]
void DeserializationCtor(StreamingContext context)
{
_isDirty = false;
}

Your BE class must still have a constructor to initialize the object for normal use. The constructor must initialize all properties that must have a defined initial value. In addition, the c'tor must initialize all child objects that are exposed as (de-normalized) public properties, to avoid null reference exceptions when using the BE (make it simple to use the BE). This also applies to child collections; create the collection to make it ready for use.

public NominationType()
{
//NOTE: WILL NOT BE CALLED ON DE-SERIALIZATION
//initialize all normalized valueobjects with members
this.NominatedValueField = new UnitValueType();
this.NominatedValueField.Unit = String.Empty;
}

Also initialize all fields that are required by the XSD schema, failure to initialize these fields will give serialization errors:
[DataMemberAttribute(IsRequired=true, . . .) ]

Don't break the DRY principle by adding the value object initialization code multiple places.

Dirty Tracking

If your BE implements INotifyPropertyChanged to enable data-binding, then the event is a good place to add dirty-tracking: Simple Dirty Tracking in Domain Objects

Converting XML Data Types to/from Strongly Typed Properties

Note that xs:date becomes string in .NET as there is no Date only type, just DateTime. Do not let this kind of weak type design leak into your BE objects. Contain the weak typing inside your BE object by converting to/from strongly typed properties.

private string _demandDateData; //XML xs:date datatype

public DateTime DemandDate
{
get
{
return DateTime.ParseExact(this._demandDateData, WSDateFormat, null);
}
set
{
string xsDate = value.ToString(WSDateFormat);
if (this._demandDateData.Equals(xsDate) != true)
{
this._demandDateData = xsDate;
this.RaisePropertyChanged("DemandDate");
}
}
}

This keeps your BE object within the "Simple vs Easy" principle.

De-normalization of BE Value Objects

The data contracts provided by the web-services will most likely contain some DDD value objects for numeric types annotated with some related attributes (e.g. money with currency) and other similar cases. These value objects will become child objects of the BE object, which is not very data-binding friendly as most controls (grids, etc) needs the data to be non-nested properties of the bound object. In addition, one control can only have one binding source. Thus, unlike master-details type binding that can be resolved using multiple binding sources, nested value objects must be de-normalized and projected as normal properties directly on the BE objects.

Start by making the value object private and give the property a new name (e.g. suffix with Data) while specifying the original name in the serialization attribute to keep the link to the XML. Keep the RaisePropertyChanged parameter equal to the property name.

[DataMemberAttribute(Name = "NominatedValue", IsRequired = true, EmitDefaultValue = false, Order = 2)]
private UnitValueType NominatedValueData
{
get { return this.NominatedValueField; }
set { . . . }
}

Then create the de-normalized public properties (in a partial class) as required by the BE and data-binding needs. The new public properties should be wrappers exposing an element of the original private member value object, using a friendly name and the correct data type. Make sure that the new-old value comparison is correct. Keep the RaisePropertyChanged parameter equal to the new property name.

public Decimal NominatedValue
{
get { return this.NominatedValueField.Value; }
set
{
if (this.NominatedValueField.Value.Equals(value) != true)
{
this.NominatedValueField.Value = value;
this.RaisePropertyChanged("NominatedValue");
}
}
}

public string NominatedValueUnit
{
get { return this.NominatedValueField.Unit; }
set { . . . this.RaisePropertyChanged("NominatedValueUnit"); }
}

As can be seen from the example, the new public properties are named by concatenating the value object name and the exposed property name; except for when the property name is just repeating the last part of the value object (i.e. NominatedValue.Value).

Remember to initialize all the value object children in the BE c'tor; both create the child objects and set their initial values.

Keeping the BE Synchronized with the Data-Contract Schema

It is imperative that the XML serialization attributes in code are correct according to the data contract XSD when using the decorator approach on proxy DTO objects to implement BE objects. There are three typical changes that can break the mapping between the BE code and the payload XML:

  • Changes to the code by renaming properties without updating the XML serialization attributes accordingly
  • Changes to the data contract XSD schema without adding properties with correct XML serialization attributes
  • Changes to the data contract XSD schema without updating the XML serialization attributes accordingly
The first issue can happen when e.g. re-exposing a property by renaming and hiding the original property (such as for de-normalizing a value object). This will require updating the XML serialization attribute to keep the mapping of the code to XSD correct:

[DataMemberAttribute(Name = "NominatedValue", . . .) ]
private UnitValueType NominatedValueData

The next two issues are caused by adding new items to the data contract or changing some existing items. The latter is not recommended and is definitively not a recommended practice for published contracts:

  • It is a proven practice that published contracts are not changed, except for non-breaking changes in minor versions.
  • For new, non-breaking versions of the contract, items must only be added at the end of the existing contract.
When a new minor version of a published data contract must be incorporated into your BE class, then start by adding the properties to hold the new data items, then add the applicable XML serialization attributes with the correct sequence order value:

[DataMemberAttribute(. . . , Order=<order number in XML xs:sequence element for item>) ]

For new major versions of data contracts, you must consider creating a new version of the BE class in a new .NET namespace. This allows you to do controlled versioning of your domain objects in synchronization with the versioning policy of the service contracts.

However, during the development of the web-services, the contracts are bound to get breaking changes as the data contracts evolve (which is OK as they are still not published). For this reason, wait as long as you can to make changes to the generated BE code, stick to working on the partial class used to decorate the BE. This will allow you to re-generate the schema-bound parts of your BE to keep up with the changes in the data contracts.


A side note: deriving your BE objects from the DTO objects is an alternative to partial classes that strictly enforces the separation of decorator code from generated code, and allows the generated code to be auto-generated over and over again - like for the Mapper option. Alas, there are drawbacks to inheriting the DTOs also, as none of the generated proxy artifacts are geared towards this. Look into using an AOP framework to do dynamic subclassing if chosing to derive your BE objects.

For data contracts under development, any combination of adding, changing, removing and reordering of data contract items can be expected to occur. The XML serialization attributes must then be updated accordingly.

Tuesday, April 15, 2008

WCF+SCSF: Client Domain Objects, Mapper Pattern

The client domain objects (aka business entity - BE) must be related to the data contracts provided by the web-services. Still, they will need to be enhanced with e.g. dirty-tracking, validation, state, property conversions (xs:date), business rules, and other aspects needed to produce a fully working client application. This article describes how to achieve this when sharing domain objects across layers is not an option (i.e. interop with JEE services), and the same applies to AOP.

One option for implementing the BE objects, described in this article, is to apply the Mapper pattern to the WSDL scema-based DTO objects to transform them into domain objects. Read ‘Design of Client Domain Objects’ for an intro this option and the related Decorator option.

Service Proxy

The mapper option has no special requirements for the service proxy or its message and data contracts, as there are no shared objects between the proxy and the business entities, i.e. the proxy is totally self-contained. The mapper objects do all transformation to/from the DTO objects and the BE objects.

CAB EntityTranslatorService, CAB EntityMapperTranslator

The EntityTranslatorService class is a service that provides a registry of translators and translation services between two classes. The user must implement the translators and register them with the service.

For more information see: ms-help://MS.VSCC.v80/MS.VSIPCC.v80/ms.practices.scsf.2007may/SCSF/html/03-01-090-How_to_Translate_Between_Business_Entities_and_Service_Entities.htm

The EntityMapperTranslator class is a base helper implementation of an IEntityTranslator that provides placeholders to translate from business entities to service and viceversa.


For more information see: ms-help://MS.VSCC.v80/MS.VSIPCC.v80/ms.practices.scsf.2007may/SCSF/html/03-01-090-How_to_Translate_Between_Business_Entities_and_Service_Entities.htm

Mappers and the Translator Service

A mapper must be derived from the CAB class EntityMapperTranslator<BE, DTO> and implement two methods:

DTO = BusinessToService(BE)
BE = ServiceToBusiness(DTO)

A mapper must traverse the complete object graph to translate all child collections and objects when the mapped object is a DDD "aggregate root".

Always add a mapper for collections of the mapped DTO and BE objects. A list mapper must iterate the collection and use the applicable object translator to map each item in the list.

Each module must register its own mappers with the CAB translator service from the CAB module AddServices:

public override void AddServices()
{
AddEntityTranslators();
_workItem.RootWorkItem.Services.AddNew<MyService, IMyService>();

}

private void AddEntityTranslators()

{
IEntityTranslatorService translator = _workItem.RootWorkItem.Services.Get<IEntityTranslatorService>();

translator.RegisterEntityTranslator(new MyTranslator());
translator.RegisterEntityTranslator(new MyListTranslator());

. . .
}

The mappers are used by the service agents to map DTO objects to BE objects and vice verca. Each CAB service that depends on a service agent must have a [ServiceDependency] on IEntityTranslatorService:

[InjectionConstructor]
public MyService([ServiceDependency]IEntityTranslatorService translator)
{
_translator = translator;
_myServiceAgent = new MyServiceAgent(_translator);
}

MyService is a CAB service and will thus get the EntityTranslatorService injected by the DI-container. It then creates the required service agents using the translator service reference. MyServiceAgent is not a CAB service, thus it is not subject to any DI-container dependency resolving magic.

Service Agents Perform the Mapping

The service agents use the EntityTranslatorService to map the DTO objects returned by the service proxy into BE objects:

AllocationTypeList allocationTypeList;
NominationTypeList nominationTypeList = _proxy.GetNominationAndAllocation (periodType, out allocationTypeList);

nominationList = _translator.Translate <List<Nomination>>(nominationTypeList);
allocationList = _translator.Translate <List<Allocation>>(allocationTypeList);

The reverse mapping must be performed on all BE objects passed as DTO objects into the service proxies.

NEVER LET A DTO OBJECT BE USED OUTSIDE SERVICE AGENTS.

Mapping from DTO to BE

Your BE class must have a constructor to initialize the object for normal use. The constructor must initialize all properties that must have a defined initial value. In addition, the c'tor must initialize all child objects that are exposed as public properties, to avoid null reference exceptions when using the BE (make it simple to use the BE). This also applies to child collections; create the collection to make it ready for use. Don't break the DRY principle by adding the initialization code multiple places.

public Nomination()
{
//initialize all contained valueobjects with members
this.NominatedValueField = new UnitValueType();
this.NominatedValueField.Unit = String.Empty;
. . .
}

The mapper code will create a new instance of the BE class and initialize it based on values from the DTO object. This can involve the whole specter from simple value copying to complex conversion logic.

Mapping from BE to DTO

Your mapper class must initialize the created DTO object before using it. The mapper must initialize all properties that must have a defined initial value. In addition, the mapper must initialize all child objects that are exposed as (de-normalized) public properties, to avoid null reference exceptions when mapping the BE. This also applies to child collections; create the collection to make it ready for use.

//initialize all normalized valueobjects with members
dto.NominatedValueField = new UnitValueType();
dto.NominatedValueField.Unit = String.Empty;

Also initialize all DTO fields that are required by the XSD schema, failure to initialize these fields will give serialization errors:

[DataMemberAttribute(IsRequired=true, . . .)]

The mapper code will create a new instance of the DTO class and initialize it based on values from the BE object. This can involve the whole specter from simple value copying to complex conversion logic.

Converting XML Data Types to/from Strongly Typed Properties

Note that xs:date becomes string in .NET as there is no Date only type, just DateTime. DO NOT LET THIS KIND OF WEAK TYPE DESIGN LEAK INTO YOUR BE OBJECTS. Contain the weak typing in your DTO object by converting to/from strongly typed properties in the mapper.

dto.DemandDate = value.DemandDate.ToString(WSDateFormat);

entity.DemandDate = DateTime.ParseExact(value.DemandDate, WSDateFormat, null);

This keeps your BE object within the "Simple vs Easy" principle.

Dirty Tracking

If your BE implements INotifyPropertyChanged to enable data-binding, then the event is a good place to add dirty-tracking: Simple Dirty Tracking in Domain Objects.

Thursday, March 27, 2008

WCF: DataContractSerializer Schema Rules

Anyone who have tried to do contract/schema first design of data contracts or tried to generate proxies using SVCUTIL.EXE in an interop scenario with e.g. Spring-WS, will have run into how WCF magically decides to use the old XmlSerializer rather than the new DataContractsSerializer (DCS). And deducing which parts of a schema that cause this is not easy with real-life contracts.

The
XML schema rules/limitations for DCS is well documented, but the proxy generator will not tell you which of the rules your XSD/WSDL does not adhere to. Even worse, if you specify /serializer:DataContractSerializer and the rules are broken; the proxy will get generated without any error, but also without any messages and data transfer objects.

Note that the SVCUTIL switches /collectionType /ct and /reference /r only work with the DataContractSerializer, not the XmlSerializer. Thus, if the proxy generator falls back to the XmlSerializer, you will not get collections (List / BindingList / etc) for arrays nor any reuse of existing shared object types.


The only way I've found that will tell you why DCS is not used, is by using the /DCONLY option to extract the data contracts from the WSDL. Using this switch will disclose data contract (XSD) errors one at a time, but it is still better than not knowing why. Note that it will not disclose any errors related to the messages not being document/literal wrapped (WSDL).

The most common XSD schema lapsus is not wrapping arrays in a two-level complex type, one for the list of items and one for the items themselves. This is not very well documented in the DCS rules. The array XSD schema must follow this construct:

<xs:element name="ItemList" type="tns:ItemListType" />

<xs:complexType name="ItemListType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Item" type="tns:ItemType" />
</xs:sequence>
</xs:complexType>

<xs:complexType name="ItemType">
<xs:sequence>
<xs:element name="Id" type="xs:long" />
<xs:element name="Value" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>

Note that there is no need to use the prefix ArrayOf on the list element name.


The reason for wrapping the array might seem quite silly when the message contains elements of only one type. However, look at this XML segment that contains elements of multiple types:
<root><a/><b/><b/><b/></root>

The DCS does not like a XSD schema where the children of an element varies in numbers and are not of the same type; it requires that all child elements that varies in numbers must have the same type, thus the wrapper element:
<root><a/><itemList><b/><b/><b/></itemList></root>


This way the <root> element contains a fixed number of different elements, the <a> element and the <itemList> element; while the <itemList> element contains a varying number of <b> elements only. In addition, an empty/null array can still be represented in the XML.

The other typical WSDL lapsus wrt DCS is about the message part definitions and the related operation input and output elements plus the related binding section. The important rule here is to remember to use only one part in each message (WS-I Basic Profile) and to set the message part attribute @name = "parameters" (by convention) to make the messages document/literal wrapped. Other @name conventions are "header" for message headers and "detail" for fault message parts to be used as wsdl:fault elements in operations.

This is an example that will allow you to use the DataContractSerializer:

<wsdl:message name="GetItemRequest">
<wsdl:part element="tns:GetItemRequestType" name="parameters" />
</wsdl:message>

<wsdl:message name="GetItemResponse">
<wsdl:part element="tns:GetItemResponseType" name="parameters" />
</wsdl:message>

<wsdl:message name="FaultDetailList">
<wsdl:part element="fault:FaultDetailList" name="detail" />
</wsdl:message>


<wsdl:portType name="InspectValues">
<wsdl:operation name="GetItem">
<wsdl:input message="tns:GetItemRequest" name="GetItemRequest" />
<wsdl:output message="tns:GetItemResponse" name="GetItemResponse" />
<wsdl:fault message="tns:FaultDetailList" name="FaultDetailList" />
</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="InspectValuesSoap11" type="tns:InspectValues">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetItem">
<soap:operation soapAction="" />
<wsdl:input name="GetItemRequest">
<soap:body use="literal" /></wsdl:input>

<wsdl:output name="GetItemResponse">
<soap:body use="literal" /></wsdl:output>

<wsdl:fault name="FaultDetailList">
<soap:fault name="FaultDetailList" use="literal"/></wsdl:fault>
</wsdl:operation>
</wsdl:binding>

Note that if your message part element is a wrapped array, the referenced element must be marked as nillable. This is a SVCUTIL WSDL requriement, and applies even if using /DCONLY generates the contracts just fine.

If the generated DCS-based proxy interface contains operations that has no input or output messages, then your WSDL does not adhere to the above rules. The same is true if you get any "cannot import" errors or warnings related to wsdl:binding, wsdl:portType or wsdl:port. Note also that the element referenced as a message part must be a DCS allowable <xs:complexType> with an <xs:sequence> child (can also be empty). Read more about message schema rules in
Handcrafting WCF friendly WSDLs.

There are some known issues with SVCUTIL /reference regarding the mismatches between some XSD schema types and .NET types (e.g. xs:date, xs:positiveinteger), which will make /reference fail as the WSDL types don't correspond with the referenced .NET data contract types: .NET has no Date only data type, just DateTime - thus xs:date becomes string. Also watch out for enumerations being represented as pure strings without any defined enum items. These issues will cause /reference to fail.

Note also that your custom shared collection types must also be referenced using /ct even if already added using /reference. Forgetting this will give your duplicate classes for all your [CollectionDataContractAttribute] lists defined in your data contracts.

As you might have noticed, using nillable elements might be required for /reference to work properly. Always try setting nillable="true" if you can't get any code generated when using the DataContractSerializer.

Pre .NET 3.5 SP1: All xs:string elements are required to be nillable. The same applies to your custom collection types.

I wish the DCS rules documentation had included more XSD schema examples, both for allowable and invalid schema constructs.

The /reference option is very important when using an architecture like CAB/SCSF where the service implementation (proxy) is separated from the service definition (interface). Then, it is important that the data contracts are included in the service interface assembly for reuse across business modules; i.e. the DTO objects can not be inside the proxy implementation assembly. The proxy itself is most likely wrapped in a service agent and should never be exposed in the DDD service or repository pattern interface.

If you can't get the /dconly plus /reference combo to work, then you're stuck with generating the contracts and proxy into classes in a single file using a .Service.Interface namespace and then extracting the proxy code into a separate file in a .Service namespace using e.g. a RegEx script, followed by some namespace using/imports refactoring for the extracted proxy code file so that it references the data contracts in the interface namespace.

Monday, March 03, 2008

WCF: WS-Security, SSL, TransportWithMessageCredentials, Message Logging

I'm currently on a project where we're using WCF to interop with services provided by Spring-WS hosted on WebSphere. The basic WS-Security UsernameToken credential type over a basicHttpBinding with SSL was chosen for authentication.

The first problem we got was that the self-signed SSL certificate was not accepted by SvcUtil.exe or "Add service reference":

The remote certificate is invalid according to the validation procedure. Could not establish trust relationship for the SSL/TLS secure channel. The remote certificate is invalid according to the validation procedure.

Sure enough, opening the URL in MSIE showed two certificate errors: issuer trust and certificate common name/site name mismatch. The first issue was easily solved, the latter was not. However, a workaround is to save the WSDL to a file and use that file as the input to SvcUtil.exe. Of course, the same invalid SSL certificate will come back and bite you when trying to use the proxy - more on this later.

I took the generated the proxy code and config output and merged it into my code. Unsurprisingly, the unit test failed with the message "no WS-Security headers found in request". I turned on message logging on both service and transport level using SvcConfigEditor.exe, remembering to set LogEntireMessage to true. Sure enough, no wsse:UsernameToken element in the soap:Header. Grief...

A lot of research lead me to the knowledge that WCF will by design not allow any sensitive data to be sent on an unsecure channel. Time to look at the generated output.config. After a few hours of frustrated config tuning and log inspections, the issue was solved: SvcUtil.exe generates config that combines Username credentials with Transport mode security. This looks OK and gives no config validation exception, but it is absolutely not correct. This is the correct config for using WS-Security over basicHttpBinding and SSL:

<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None"realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>

WCF will not put any wsse: headers into the request unless TransportWithMessageCredential is used as the security mode. In addition, add the username and password using the .Username and .Password properties of the proxy.ClientCredentials.UserName object.

After a while it occurred to me that the Spring-WS generated WSDL contained no WS-Policy statements, thus there was no guidance in the WSDL for creating the security artifacts for the proxy and config.
Now my request went through to WebSphere! But, how long was I in paradise? Until the response came back:

System.ServiceModel.Security.MessageSecurityException: Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.

The problem is that WCF expects a timestamp in the response when it puts a wsse: timestamp in the request (see the transport level message log). I have not been able to turn the timestamp off using config for <basicHttpBinding>, but it can be done using a <customBinding> (see Kristian Kristensen's blog). Nicholas Allen provides code and a deeper explanation of the timestamp mechanism in his blog:

BindingElementCollection elements = proxy.Endpoint.Binding.CreateBindingElements();
elements.Find<SecurityBindingElement>().IncludeTimestamp = false;
proxy.Endpoint.Binding = new CustomBinding(elements);

While you wait for the WebSphere folks to install a valid certificate, you can intercept the certificate validation and override any SSL policy violations:

using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;...
ServicePointManager.ServerCertificateValidationCallback = 
delegate(object sender, X509Certificate certificate, X509Chain chain, 
         SslPolicyErrors sslPolicyErrors)
{
//http://msdn2.microsoft.com/en-us/library/system.net.security.remotecertificatevalidationcallback.aspx
//ignore invalid SSL: allow this client to communicate with unauthenticated serversreturn true;
}

At last my WCF client is able to invoke the web-service providing the expected WS-Security wsse:UsernameToken. What a wonderful interop world it is using WS-*.

Articles by IBM: Achieving Web services interoperability between the WebSphere Web Services Feature Pack and Windows Communication Foundation Part 1 and Part 2.

Tuesday, November 06, 2007

WCF: Caching Claims using System.Web.Caching

We use a custom legacy STS (Security Token Service) that assigns a ticket to our consumer applications, that they again pass as to our WCF services for authentication. The passed SAML token contains only the ticket, so we must then use the validated ticket to generate the System.IdentityModel claims used for authorization.

As the services are stateless, each WCF operation must recreate the AuthorizationContext and thus generate the claim sets again. When you compose a set of services into a business process, the claim sets will get generated over and over again. To avoid this, and get better performance, I needed to cache the claim sets by STS ticket for a limited time.

Many might not know this, but the System.Web.Caching.Cache can be used even in systems that are not an ASP.NET application or even hosted by IIS/ASP.NET. You will still get all the goodies, such as cache expiration, dependencies, throwing stuff out of the cache in case of low memory, etc.

We now cache the claim sets in a singleton using a generic <T> getter and setter with ticket-based keys like this:

public static class EApprovalCache
{
private static System.Web.Caching.Cache _cache = HttpRuntime.Cache;

public static Cache Cache
{
get { return _cache; }
}

public static object Add<T>(string ticket, T value)
{
string key = typeof(T).Name +":" + ticket;
return _cache.Add(key, value, null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
}

public static T Get<T>(string ticket)
{
string key = typeof(T).Name +":" + ticket;
return (T)_cache[key];
}
}

The claim set is retrieved and added to the cache like this:

_authorizationContext = EApprovalCache.Get<EApprovalAuthorizationContext> (context.Ticket);
if (_authorizationContext == null)
{
_authorizationContext = new EApprovalAuthorizationContext(session);
EApprovalCache.Add<EApprovalAuthorizationContext> (context.Ticket, _authorizationContext);
}

The claims are cached for max one hour; but if the user logs out and in again, then the user will have gotten another ticket and the claim set would be generated from scratch and not read from the cache.

Wednesday, October 31, 2007

Tools and platform for providing SOA and mashups

This week at the Microsoft SOA and BPM conference, two announcements were made that support the predictions of my last post (SOA: Top Two Tech Topics for 2008):
"Oslo" is based on the BizTalk concept (BizTalk Server + BizTalk Services) supported by the .NET framework (WCF, WF), model-driven design tools, and of course a repository for service life-cycle management.

Read more about "Oslo" in the Directions on Microsoft article provided on Christian Weyer's blog.

Sunday, October 21, 2007

BizTalk Services SDK, RelayBinding: Firewall Issue

I recommend that you download and try the samples of the BizTalk Services SDK (identity & access control, connectivity, web-style stuff) to get a deeper understanding of what the "internet service bus" concept provides to service-oriented solutions - both for the SaaS approach and for the Software+Service approach.

An error that you might run into when trying any of the connectivity samples is the "No DNS entries exist for host connect.biztalk.net" exception when calling host.Open() from e.g. the EchoSample server. You'll get a really lost feeling when googling for this error gives no hits:

System.ServiceModel.EndpointNotFoundException was unhandled
Message="No DNS entries exist for host connect.biztalk.net."
Source="System.ServiceBus"

StackTrace: at System.ServiceBus.RelayedOnewayClient.Connect()

The cause of this problem is that the RelayBinding uses an outbound TCP connection to connect to sb://connect.biztalk.net/ to set up your hosted endpoint; and if you're behind a firewall, this will fail unless permitted by the firewall. Refer to the ReadMe file of the SDK for more details.

Wednesday, September 26, 2007

IIS6: App-Domain could not be created

Each time when I have to deploy a ASP.NET/WCF application to a new Windows Server 2003 IIS web-site, I run into a "Server Application Unavailable" error and this logged in the application event log:

Failed to execute request because the App-Domain could not be created. Error: 0x80070005 Access is denied.

Exception: System.IO.FileLoadException
Message: Could not load file or assembly 'System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. Access is denied.

As always, I'm a bit puzzled by the access denied error as I have granted NTFS read+execute rights to the ASPNET and IUSR accounts as applicable to the application's disk folder and to the .NET 2.0 and 3.0 folders. Time for Microsoft System Internals Filemon to log file access failures to diagnose the problem.

Note to self: The cause of the problem is that the identity (e.g. NETWORK SERVICE) of the IIS application pool used to run the web application, needs read access to the application's web.config file to be able to launch the ASP.NET worker process.

Read the excellent MSDN article 'Extend Your WCF Services Beyond HTTP With WAS' to learn more about IIS/ASP.NET/WAS application pools, process models and app-domains.