Before going into the details of using ChannelFactory, if you are not familiar with service proxies (or have used them but don’t understand why they’re important) here’s a little bit of background. When a client application makes a call to a service, it shouldn’t know or care about the implementation details or physical location of the service. All the client should be aware of is that there is an object which provides some useful functionality. Everything else about the service should be hidden away.
And this is exactly what a proxy does – it hides the technical details of the service from the client by adding an extra layer in between. The proxy object exists in the same memory address space as the client and marshals calls across to the service on the client’s behalf. The service could be a WCF service with TCP bindings which is hosted somewhere on the same local area network as the client, or it could be a RESTful HTTP service hosted in the cloud on the other side of the world. It simply doesn’t matter. All the client needs to know are the details of the proxy. The service which sits behind the proxy is effectively invisible.
This is good software design and ensures your clients and services remain loosely coupled and are therefore easier to maintain. If there are any physical changes to a service (e.g. a newer version becomes available which just happens to be implemented in a different technology) it is the proxy that will change, not the client. With any luck, you shouldn’t have to touch the client code at all. However avoiding changes to the client is less easy if the interface to an existing service changes. I describe how to minimise the impact of changes to service contracts on the client in more detail here.
Using the ChannelFactory<T> class to make calls to your WCF services is an easier alternative to the laborious process of generating proxies via the SvcUtil tool every time a service contract changes. As its name suggests, ChannelFactory is a factory for creating service communication channels at runtime. This means no matter how often your service contracts change, you won’t have to manually re-generate proxy classes or alter client-side service model config each time.
ChannelFactory<T> takes a generic parameter of the service type you want to create a channel for (this must be the contract interface). And as an absolute minimum, it requires a specific binding and endpoint address. You can supply additional information, but this is enough to achieve a remote connection to the service.
Because ChannelFactory only requires knowledge of the service contract, it makes good design sense to put your service/data contracts and service implementations in separate assemblies (never put your service contracts and service implementation in the same assembly). This way, you can safely distribute contract assemblies to third parties who wish to consume your services, without the risk of disclosing their actual implementation.
As an example, here’s a very basic service contract. To keep things simple, I haven’t used any data contract parameters but if there were any, the data contract type declarations should be included with the service contract interfaces in the same contract assembly. This is so that you can share the contract assembly with other solutions or distribute to third parties (otherwise clients won’t be able to instantiate the parameter types).
Here is the service implementation.
And here is the client-side code to call the service using ChannelFactory<T>.
As you can see it’s surprisingly simple. It doesn’t look like much but we are still supplying the essential ABC requirements of WCF. A is the address of the service endpoint, B is the binding (in this case I’ve used basic HTTP binding because that is the default service binding – client and service bindings must always match), and C is the contract interface. You don’t need any more than this to achieve a service connection. At this point you are probably wondering why you’ve spent so much time messing around with complicated client-side WCF config!
A reusable proxy base class
But as I explained earlier, you don’t want this sort of infrastructure code dotted throughout your client applications. It should be wrapped in a service proxy class. You also don’t want boilerplate service code duplicated over and over again in different proxy classes, so here is a generic base class to take care of the specific details of creating a channel. If you don’t already have one, create a WCF infrastructure assembly and add the proxy base class to it for future reuse with different solutions.
Notice that the base class is thread-safe – a crucial but sometimes overlooked issue with server-side classes. Also notice for the sake of clarity, I omitted the region which implements IDisposable which is shown below:
You could also extend the base class constructor to take different bindings, etc, but I’ll leave that down to you. Now to see this in action, all you need is a concrete proxy class which is strongly typed to your service contract:
Notice that the proxy class name is the name of the service but with a ‘Client’ suffix. This is a standard WCF naming convention which you should follow so that other developers will immediately understand its purpose. Also notice how the GetMessage method is simply a wrapper for a call to the GetMessage operation exposed by the service contract, but the client has no knowledge of this. All it knows is that it calls a local method and gets a return value.
Wrapping it all up
Finally, put the concrete proxy class in its own service proxy assembly (don’t be tempted to just add it directly to a client project). Having the abstract base and concrete proxy classes in separate assemblies will promote reuse with different client applications and across different solutions meaning you and other developers will be able to use these assemblies straight out of the box when they need to communicate with the same service.
And here is the revised client code which now calls the service via the proxy:
See how simple this has become compared to the original client code earlier which called ChannelFactory<T> directly? I have included a service endpoint URL in this example but even that would be hidden away in a config file in a real application, so the client really is achieving quite a lot through some very minimal code. This will keep your client code clean and simple, speed up development time in the future and reduce maintenance costs.
Also see the follow-up post how to avoid changing WCF service contracts which describes good contract design.