Book review: Microsoft Silverlight 5 and Windows Azure Enterprise Integration

Disclaimer: I received a copy of this book from Packt Publishing.

The author, David Burela, though I didn’t hear about him before seems to be well known in the Australian community.

When you look at the contents of the book it looks like it’s covering the main integration parts with Windows Azure.

- Hosting Silverlight Applications in Azure
- Using Azure Queues with Silverlight
- Accessing Azure Blob Storage from Silverlight
- Storing Data in Azure Table Storage from Silverlight
- Relational Data with SQL Azure and Entity Framework
- RIA Services and SQL Azure
- Exposing OData to Silverlight Applications
- Application Authentication

The author expects you to already have some Silverlight knowledge and thus won’t explain the Silverlight parts in too much detail. My experience with Windows Azure is small, which makes me probably part of the target audience. The introduction helps you understand what Azure is, a good refresher for me. After that, chapter after chapter there’s an explanation on how to integrate Silverlight with the backend, running on Azure. All in all it stays very basic and a couple of times it refers to some MSDN pages for the details. Though I agree that copying information that’s already on the web is probably not a good thing, I was reading the book on the bench and this means, no details for me at the time. I would rather have a book that is complete and puts these kind of additional parts in an Appendix.

In the end I didn’t feel satisfied. Most of the integration was more like, you integrate with WCF and that WCF will integrate with Windows Azure. This doesn’t have anything to do with the book itself, the content is good. However is a book like this really needed? You have to judge that yourself. It is an engaging book that will introduce Windows Azure to Silverlight developers.

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.