Make use of WCF FaultContracts in Silverlight clients

I think every Silverlight developer has seen at least once, an exception showing a message “The remote server returned an error: NotFound” while connecting to a WCF Service. Alright, that message could have been a better message, but why are we getting this message?

Yes, you probably figured that out yourself, something is wrong with your WCF Service, and it’s not a missing WCF Service. Yes it feels something is seriously wrong, why do we get this strange NotFound message?

If anything goes wrong, the WCF Service returns some data, but also sets the HTTP Status code to 500. The browser HTTP stack doesn’t allow to read the data when the HTTP Status code is 500.

Solution 1:

There’s an easy solution to solve this: Don’t use the browser HTTP stack but the client HTTP stack instead. Just a matter of adding the below line of code in the Application_Startup method in the App.xaml.cs.

WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);

Solution 2:

Because sometimes you don’t want to make use of the client HTTP stack but rather like the browser HTTP stack there’s a solution for that as well. If you’re using the browser HTTP stack you’ll get things like Windows Authentication and automatic Cookie handling.

Because of the extreme flexibility of WCF and really a lot of hook-points we can change the behavior of the HTTP Status code in case of errors. There’s a MSDN article which explains this in detail. The only real important part is line 18, which changes the Status code to 200 in case of Faults.

public class SilverlightFaultBehavior : BehaviorExtensionElement, IEndpointBehavior
{

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
   {
       var inspector = new SilverlightFaultMessageInspector();
       endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
   }

   public class SilverlightFaultMessageInspector : IDispatchMessageInspector
   {

       public void BeforeSendReply(ref Message reply, object correlationState)
       {
           if (reply.IsFault)
           {
               // Here the response code is changed to 200.
               var property = new HttpResponseMessageProperty { StatusCode = System.Net.HttpStatusCode.OK };

               reply.Properties[HttpResponseMessageProperty.Name] = property;
           }
       }

       public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
       {
           // Do nothing to the incoming message.
           return null;
       }


   }

   public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
   {
   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
   {
   }


   public void Validate(ServiceEndpoint endpoint)
   {
   }

   public override System.Type BehaviorType
   {
       get { return typeof(SilverlightFaultBehavior); }
   }

   protected override object CreateBehavior()
   {
       return new SilverlightFaultBehavior();
   }

}

Of course you need to configure the services to use this behavior.

<system.serviceModel>
	<extensions>
		<behaviorExtensions>
			<add name="silverlightFaults"
				type="Silverlight.Poc.SilverlightFaultBehavior, Silverlight.Poc, Version=1.0.0.0, Culture=neutral"/>
		</behaviorExtensions>
	</extensions>
	<services>
	...
	</services>    
	<behaviors>
		<endpointBehaviors>
			<behavior name="">
				<silverlightFaults/>
			</behavior>
		</endpointBehaviors>
		<serviceBehaviors>
			<behavior name="">
				<serviceMetadata httpGetEnabled="true" />
				<serviceDebug includeExceptionDetailInFaults="false" />
			</behavior>
		</serviceBehaviors>
	</behaviors>
	<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>

Exception details

Next you might actual want to see the details of exceptions that occur in the service on the client. The simple solution is to just allow the service to include the exception details in Faults.

<serviceDebug includeExceptionDetailInFaults="true" />

You would want to do this in a development and maybe in a test environment, but not for production. In the production environment you’ll only want to provide known faults. Yes in a lot of situations there are known faults which in essence are very similar to application specific exceptions.

If you want to enable a known Fault on your WCF Service you will need to create a FaultContract and also decorate the ServiceContract with information about what kind of Faults in can expect. Let’s start with a simple FaultContract which is in this case a simple DataContract.

[DataContract]
public class AuthenticationFault
{
   [DataMember]	
   public string Reason { get; set; }
}

We decorate the Service with a FaultContract attribute which references the datacontract we created in the previous step.

[OperationContract]
[FaultContract(typeof(AuthenticationFault))]
List<Package> FindPackages(PackageQuery query);

Alright we now only need a way to fire a WCF Fault. This is similar to the way we fire normal exceptions, but an instance of the Fault DataContract will be added to the Fault.

throw new FaultException<AuthenticationFault>(new AuthenticationFault(), new FaultReason("Authentication failed."));

The Local History project: Some challenges

Some time ago I mentioned thinking about a project on Local History. This project is still in a very conceptive application. But I already know that I want to have Windows Service and a Windows UI. More on other details later, but now let's talk about communication between the Windows Service and the Windows UI.

It's possible to do some very basic communication with a Windows Service. This can be done like this:

On the Windows Service handle commands like this:

1 protected override void OnCustomCommand(int command) 2 { 3 base.OnCustomCommand(command); 4 //Do your handling. 5 }

On the Windows UI send the commands like this:

1 ServiceController sc = new ServiceController("WindowsServiceName"); 2 int customCommand = 21; 3 sc.ExecuteCommand(customCommand);

Yes you can see this are just very basic commands, you can send integers to the Windows Service that it needs to handle. I'm sure there are enough samples to find that only needs this basic commands. But I need more, much more.

How can we do more advanced communication between the Windows UI and the Windows Service?

In the old world, .NET 1.1 or .NET 2.0, we would turn to .NET Remoting using Named Pipes. But nowadays we have .NET 3.0 and even .NET 3.5, specially we have Windows Communication Foundation (WCF). I didn't have any opportunity to use WCF. So I thought why not give WCF a try using Named Pipes.

So first thing I did, was forget about the communication channel and model the service contract and data contract.

The Service Contract is still very generic and should probably need some modifications in the future, but so far this is it:

1 [ServiceContract] 2 public interface ILocalHistory 3 { 4 [OperationContract] 5 void Do(ServiceAction action); 6 }

As you can see I make use of "ServiceAction" as data. For those interested "Operation" is a very basic enumeration. For the "ServiceAction" I have a DataContract:

1 [DataContract] 2 public class ServiceAction 3 { 4 [DataMember] 5 public Operation Operation { get; set; } 6 7 [DataMember] 8 public string Path { get; set; } 9 }

The next step was some basic code to host the service:

1 ServiceHost localHistoryServiceHost = new ServiceHost(typeof(LocalHistoryWcfService)); 2 localHistoryServiceHost.Open();

After this I still needed to configure the service:

1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <system.serviceModel> 4 <services> 5 <service name="MM.LocalHistory.Service.LocalHistoryWcfService"> 6 <endpoint address="net.pipe://localhost/LocalHistory/Service" 7 binding="netNamedPipeBinding" 8 contract="MM.LocalHistory.Service.Common.ILocalHistory"/> 9 </service> 10 </services> 11 </system.serviceModel> 12 </configuration>

The very minimum configuration you need to get the service listening to a named pipe is the above. I say very minimum, because a lot of times you might want more that this.

But let me explain something first. As you can see in lines 5 and 8 a Fully Qualified Name is used to specify the service implementer and the service contract. I'm used to also specify the Assembly name, but don't do that, it would not work.

So now we have ourselves a Service providing a Named Pipe service, I thought time for a consumer, a Named Pipe client. As I'm more used to working with Webservices I thought why not add a Service Reference from within Visual Studio 2008. But I learned the hard way, you first have to add a metadata exchange service to your WCF service or else Visual Studio won't be able to generate a proxy, or even discover the service.

But the nicest thing about this is, you only have to change the configuration to add a Metadata Exchange Service (MEX). Although, it took me a while to figure out this was all I needed to do.

1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <system.serviceModel> 4 <services> 5 <service name="MM.LocalHistory.Service.LocalHistoryWcfService" 6 behaviorConfiguration="MetadataSupport"> 7 <endpoint address="net.pipe://localhost/LocalHistory/Service" 8 binding="netNamedPipeBinding" 9 contract="MM.LocalHistory.Service.Common.ILocalHistory"/> 10 <endpoint address="net.pipe://localhost/LocalHistory/Service/mex" 11 binding="mexNamedPipeBinding" 12 contract="IMetadataExchange"/> 13 </service> 14 </services> 15 <behaviors> 16 <serviceBehaviors> 17 <behavior name="MetadataSupport"> 18 <serviceMetadata/> 19 </behavior> 20 </serviceBehaviors> 21 </behaviors> 22 </system.serviceModel> 23 </configuration>

The first step is about adding a Service Behavior to the behaviors (line 16 - 19). Besides this you also need an endpoint to provide the IMetaDataExchange contract (line 10-12). I chose for an mexNamedPipeBinding because it fits nice beside the netNamedPipeBinding, but you can choose whatever binding type you like, for example: mexTcpBinding and mexHttpBinding.

Now we have set up the Metadata Exchange we can add a Service Reference to generate our proxy. Normally you can use the Discover functionality to Discover Services in your Solution, but sadly this doesn't work for Named Pipes. So instead of automatic discovery I used the url: "net.pipe://localhost/LocalHistory/Service/mex" (make sure you have the service running).

After the discovery of the service you can click the Advanced button to configure some other options. For example you can set the Collection type to be System.Collections.Generic.List instead of System.Array. Also it's the default to reuse types in all referenced assemblies. This is something I wanted to have for the old Webservices for ages, read my other blog entry about this. You don't have newly generated types for all the services types, it just uses the types found in the referenced assembly.

image image

In the Generated code example A you can see that ServiceAction is used from the references assembly instead of a custom generated type.

 

1 public void Do(MM.LocalHistory.Service.Common.ServiceAction action) { 2 base.Channel.Do(action); 3 }

Generated code example A: Use of a referenced assembly.

public void Do(MM.LocalHistory.UI.LocalHistoryWcfServiceInterface.ServiceAction action) { base.Channel.Do(action); }

Generated code example B: Not using a referenced assembly.

A long post around the end of the year. More about the Local History project in the future, and more about WCF I think.

Reusing Class Library between Web Service and consumer

.NET and Visual Studio make it Web Service consumers very easy to generate a proxy for accessing the Web Service. It uses the WSDL to generate all the methods, even the asynchronous access methods. Also all data-structures are generated. Sadly all lists are generated like simple array's.

Wouldn't it be nice to use the same data-structures on the consumer as we can on the Web Service? I've been thinking about this for a long time, but as far as I knew it wasn't possible. Also a lot of people told me it just wasn't possible.

I've been thinking about a solution to do some of the deserialization on the generated proxy myself. But in my trial to create a solution and searching the Internet for possible solutions I found out about a feature called Schema Importer Extension. This can be used during proxy generation by wsdl.exe or from within Visual Studio 2005 (and maybe 2008).

Some time ago Jelle Druyts wrote an article: Customizing generated Web Service proxies in Visual Studio 2005. In this article he explains how the Schema Importer Extension works. Besides this he also writes an Schema Importer Extension that can be configured for all the data-structures that need to be reused. It's a very nice solution, only it's sad that I need to configure it. While it would be nice if discovering was automatically. But in this case you can see there is a solution to the problem where data-structures are shared between Web Service and consumer by using a class library.

Windows Communication Foundation already supports some kind of reusing. When adding a Service Reference instead of a Web Reference you can choose to reuse existing classes. I tried to use this with a plain ASP.NET Web Service without luck.

Getting Astoria to work with ADO.NET Entity Framework Beta 2

Hmm, still trying to test Astoria out, this time in combination with ADO.NET Entity Framework Beta 2. Still not succesful however. I noticed the following things.
  • When I try to add a "Web Data Service", I got stuck in a Visual Studio error. Error: this template attempted to load an untrusted component 'msastoriavs, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35'. For more information on this problem and how to enable this template, please see documentation on Customizing Project Templates.
  • Besides this I compared the Entity Model I created, they greatly differ between Beta 1 and Beta 2.
    • The extension is changed from .csdl to .edmx.
    • The schema-prefix changed from edm: to edmx:
My conclusion so far. The projectteam for Astoria has to do some work to make Astoria work with Beta 2 of ADO.NET Entity Framework.

Using Astoria Service for setting up Getting Things Done Data Service

A few days ago I wrote about trying out Astoria. Yesterday I started trying out. First I thought about using Astoria local, but that wasn't succesful. On the Astoria Getting Started Guide it says you need to have Visual Studio 2008 Beta 1 in combination with Astoria. In my case I already have Visual Studio 2008 Beta 2, which in case doesn't have ADO.NET Entity Framework available. And as a matter of fact Astoria is built on top of WCF and makes use of the ADO.NET Entity Framework. But that's no problem for setting up your own Astoria Data Service. Below are the detailed steps I took. entitymodel.jpg First of all I designed my rough model in Visio. Using the central entity Task and all the other things around Task like: Project, Context, Priority and User. The model is designed with Getting Things Done in my mind. A topic I blogged about some time ago. This tryout wasn't about building a complex model, it was all about getting started with Astoria. So let's translate this model in ADO.NET Entity Model. One thing before you start: I've had some trouble because the setting up of the model took me some time, and I wasn't able to complete because of some small error in the Session. Fast setting up does work though. First you need to set up some basic settings about your Data Service you're setting up. After this you need to create the entities, properties on those entities and all the assocications. Take a look at the images on the bottom for the way I translated the entity model to Astoria. After this I just completed the service. Next time I'm going to use the Getting Things Done Data Service to read and write data. Do you think this is an interesting service? At least, I do. step-1.jpgstep-2-priority.jpgstep-2-user.jpgstep-2-context.jpgstep-2-project.jpgstep-2-taskproject.jpgstep-2-taskcontext.jpgstep-2-task.jpg