Jul 262010
 

Some time ago I got a bit fed up with the standard way that Visual Studio creates WCF client proxies. I.e. right click and add service reference. Although it is fairly simple to create service clients this way, it generates a load of horrible code within you project. It also has the following short comings:

  • It doesn’t offer compile time checking against the service contracts – i.e. if the service contract changes the compiler doesn’t tell you. this is of course the expected behaviour for 3rd party services but not really what you want for internal services.
  • If you want to layer any extra code on top of your service clients, for example error handling or logging then you have to repeat this code for each service client using a mechanism such as partial classes.

Fortunately there is a better way to achieve this in the form of Channel Factories. If you have access to the assemblies containing the service contracts (this should be the case for internal services) then you can use channel factories to create the service proxy on the fly.

I have put together some infrastructure code for managing WCF client proxies (see attached Zip file at the bottom of the post).

This code also provides the following:

  1. Some code based default endpoints for Http and NamedPipes.
  2. Convention based approach to config.
  3. Wraps the WCF client with error handling to safely managed the faulted state.

The usage is a as follows:

Registering a WCF client proxy for an Http Endpoint.

IWindsorContainer container = new WindsorContainer();
container.Register.Component.For().ImplementedBy().
   ImplementedBy().LifeStyle.Transient);
WindsorProxyHelper.RegisterDefaultProxyTypeOf(Container, "MyServiceAddress");

// Now resolve the proxy.
IServiceProxy myServiceProxy = container.Resolve>();

Two things to note from the above code are:

  1. It assumes that you are using Windsor to resolve your service proxy, so make sure that all of the dependent objects are registered.
  2. Its assumes that you have added the appsetting “MyServiceAddress” in your config file. This should be the address of you service e.g. http://service.me.com/MyService.svc.

To use the proxy client use the following syntax:

// Now resolve the proxy.
IServiceProxy myServiceProxy = container.Resolve>();

// Assuming the service has a method called "Calculate" which accepts an integer and returns a
// decimal...
decimal result;
   
myServiceProxy.Use( s => result = s.Calulate(25));
The syntax above may look a little different but the “Use” method wraps the service call with some extra error handling.
That’s it really, my plan is to update this code to work with a number of IOC containers and I also plan to add some extra sample code. This was all put together in a bit of a rush for a colleague of mine……


 Posted by at 12:47 pm
Mar 122010
 

Background

Sometimes it is desirable to configure a WCF service to support on more than one endpoint. Implementing this on a service which is hosted outside IIS (in a console app or Windows service say) is very straight forward and logical. Surprisingly achieving this on a service which is hosted in IIS is just as easy – but it is slightly less logical.

Example

Say for example I had a simple WCF service which I want to host in IIS and support the basicHttpBinding and the wsHttpBinding. All I need to do is to add two endpoints in the config, one for each protocol, see:

<system.serviceModel>
   <services>
      <service name="WcfDualEPsHost.Service1"
          behaviorConfiguration="WcfDualEPsHost.Service1Behavior">
         <!-- Ws Endpoint -->
         <endpoint address="" binding="wsHttpBinding" 
            contract="WcfDualEPsHost.IService1"></endpoint>

         <!-- Basic End Point -->
         <endpoint address="basic" binding="basicHttpBinding" 
             contract="WcfDualEPsHost.IService1"></endpoint>
      </service>
   </services>
   <behaviors>
      <serviceBehaviors>
         <behavior name="WcfDualEPsHost.Service1Behavior">
         <serviceMetadata httpGetEnabled="true"/>
         <serviceDebug includeExceptionDetailInFaults="false"/>
         </behavior>
      </serviceBehaviors>
   </behaviors>
</system.serviceModel>

The only thing to note is that the endpoints cannot have the same address, notice that the wsHttpBinding endpoint uses the default address (the IIS route path e.g. http://localhost:3985/Service1.svc) and the basicHttpBinding use the “basic” address which will resolve to http://localhost:3985/Service1.svc/basic or something similar.

For more info see: Multiple Endpoints.

 Posted by at 12:05 pm