The Aw Bus Remote Client

All of the Wcf contracts for Aw Bus are in an assembly by themselves. That assembly will be distributable. The admin program uses the service contract types directly rather than creating a proxy.

To use the channel factory, you need to specify the binding, address, contracts, etc. There’s a lot of setup there.

I usually wrap this up into an object than does the work for me. The constructor creates the service; the dispose destroys it.

This snippet is used to retrieve a list of all of the services hosted on a particular node.

NOTE: I don’t know why the code samples aren’t rendering correctly.

 BusServiceDescription[] descriptions; using (RemoteClient<INodeService> client1 = RemoteClient<INodeService>.GetClient("NodeAdmin")) { 	descriptions = client1.Proxy.GetServiceDescriptions(""); } tvOverview.Invoke(new MethodInvoker(delegate 

“NodeAdmin” is the name of the service. I append that to the base uri. Later, it will be used to determine all of the things it needs to properly connect to the service.

It handles all of the binding information, etc. Currently, all of the necessary goodies are hard coded. This will seriously evolve as new types of endpoints are exposed. There will be an endpoint provider on the back end.

I’ve used this wrapper approach before. I thought there was a problem with the dispose, though. We saw that if an exception occurs within the using clause, then another exception occurs within the dispose, the first exception is lost and the second bubbles up. We hacked a solution to that i’m not proud of, but it works.

When I built this new wrapper for Aw Bus, I set out to conquer that problem elegantly. And I did so, which I’ll get to. I started to prepare some code samples to demonstrate the problem and the solution; and wouldn’t you know it… I couldn’t reproduce it. I think I understand why, but what I don’t yet understand is why I didn’t figure it out before. I have to look at the other wrapper and see if I’m remembering it correctly. Simply putting a catch-all in the dispose allows the original exception to bubble up.

Anyway. Prior to realizing I didn’t need a solution, I built the solution. The solution no longer appears to be useful for that problem, but will be helpful for other purposes. Basically, I use reflection to inspect the service contract, then generate my own implementation of that interface which will call the service. Its an on-the-fly proxy generator. I control the code that gets generated, so I can put in any injection points or tracking that I’d like.

The generated type is stored in a cache, so it only gets generated once as long as each call uses the same cache. That will all be hidden form the user anyway; RemoteClient will take care of it.


INodeService is the service contract.

I generate INodeServiceProtectedProxy, which implements the interface. (I will drop the leading I.) The constructor creates the channel factory and the binding. The methods call the method on the channel. The dispose closes the channel, etc.

Here’s an example of a generated proxy. This is pretty minimal. But, as I said, its all template based. So, I can just slap around the template and have it do anything I want to. (I haven’t implemented the dispose pattern yet.

using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using System.ServiceModel.Channels;  namespace AllardWorks.AwBus.RemoteClient.ProtectedProxy {     public class INodeServiceProtectiveProxy : AllardWorks.AwBus.Contracts.Services.INodeService, IDisposable     {         private readonly ChannelFactory<AllardWorks.AwBus.Contracts.Services.INodeService> _proxy;         private readonly AllardWorks.AwBus.Contracts.Services.INodeService _instance; 		 		// temporary. remove soon 		public INodeServiceProtectiveProxy() 		{ 		} 		         public INodeServiceProtectiveProxy(Binding binding, string url)         {             _proxy = new ChannelFactory<AllardWorks.AwBus.Contracts.Services.INodeService>(binding, new EndpointAddress(url));             _instance = _proxy.CreateChannel();         }  		             [OperationContract]             public AllardWorks.AwBus.Contracts.BusServiceDescription[] GetServiceDescriptions (System.String token)             {                 try                 {                     return  _instance.GetServiceDescriptions(token);                 }                 catch                 {                     Close();                     throw;                 }             }                                  [OperationContract]             public AllardWorks.AwBus.Contracts.RemoteWcfEndpointDescription[] GetAdminServiceEndpoints (System.String token, System.String serviceName)             {                 try                 {                     return  _instance.GetAdminServiceEndpoints(token, serviceName);                 }                 catch                 {                     Close();                     throw;                 }             }                                  [OperationContract]             public AllardWorks.AwBus.Contracts.RemoteNodeDescription GetNodeDescription (System.String token)             {                 try                 {                     return  _instance.GetNodeDescription(token);                 }                 catch                 {                     Close();                     throw;                 }             }                      		         private bool _closed;         private void Close()         {             if (_closed)             {                 return;             }             try             {                 _proxy.Close();             } 			catch 			{ 			}         }          private bool _disposed;         public void Dispose()         {             Close();         }     } } 

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: