To start off, I would like to stress that I am not a WCF expert and if you go around my blog, you can notice me writing about lot of different things – WPF, DLR, Web Development and what not. So what I present is just something that I made recently as a part of a bigger project that I plan to release. Apparently, this is pretty good start for what I envision for avoiding Configuration Hell in WCF services.
The StockTrader sample from Microsoft comes with a great library – Configuration Service 2.04. The library is pretty good and provides wonderful functionality but the major problem with that, for me, is its strong dependency on the SQL Server backend. In short, the configuration service maintains a service configuration repository which is used to provide centralized configuration repository, load balancing, fail-over in WCF based SOA applications. And I always wanted such a repository which would minimize my effort in developing distributed applications using WCF.
I believe, WCF should allow very simple way to develop services and should provide an easier means to configure them. One way away from configuration through App.Config is to code the configuration, but there seems to be a big lack of proper documentation and decent-real-world samples explaining code-based WCF configuration. Anyway, I would envision hosting a service to be as simple as :
var serviceHost = new AutoConfiguredServiceHost<ServiceImpl>();
With no or minimal configuration, the service host should be clever enough to determine what the configuration defaults are. Similarly, consuming the service should be as simple as :
var client = new RemoteServiceProxy<IService>();
The proxy should be created by accessing the repository to figure out implementation for IService and then use the configuration obtained to create the proxy.
With these goals in mind, the config station has been developed and here is what I have so far.
Sample : Test Service which hosts the ConfigRepository as well as a sample WCF Service implementation. The host method is shown below.
class Program
{
static void Main(string[] args)
{
using (var configHost = new ConfigStationHost())
{
var hostFacade = new ServiceHostFacade<TestImpl>();
var host = hostFacade.Host;
host.Open();
Console.WriteLine("Test service launched.Enter to Stop");
Console.ReadLine();
//host.Close();
host.Abort();
}
}
}
If you look at the using block, I am creating an instance of ConfigStationHost – which actually hosts the ConfigStation – a repository WCF service. At the moment, this service requires App.Config based configuration of the service – which can be easily removed and which would be my next enhancement to the project. In this example, I am actually hosting the ConfigStation within the same process as my actual WCF service, which is not required at all. You can host the ConfigStation in a totally separate program – all you have to do is create the instance of ConfigStationHost (see required configuration below) and dispose it when you are done.
The configuration for the Test Service is shown below.
<configuration>
<appsettings>
<add value="net.tcp" key="ServiceScheme" /> <!-- you can set this to http as well or even msmq ...-->
<add value="9989" key="ServicePort" />
</appsettings>
<system.servicemodel>
<services>
<service name="ConfigStation.Repository">
<endpoint contract="ConfigStation.ServiceContracts.IRepository" binding="wsHttpBinding" address="http://localhost:8731/ConfigStation/Repository" />
</service>
</services>
<!-- This demo acts as a client to ConfigStation, so it is all good-->
<client>
<endpoint name="ConfigStation" contract="ConfigStation.ServiceContracts.IRepository" binding="wsHttpBinding" address="http://localhost:8731/ConfigStation/Repository">
</endpoint>
</client>
</system.servicemodel>
</configuration>
In the shown configuration, the <service> element configuration is used to host the ConfigStation repository in the current process. The <client> configuration is the WCF client configuration which is used to access the ConfigStation service hosted. The TestService makes interacts with the ConfigStation using WCF and the ConfigStation is treated as a WCF service hosted somewhere remote. So, if we were to host the configstation separately the only configuration required would be that of the <service> defined. The TestService would then have the AppSettings and the <client> configuration – which is pretty easy to set and even easier for me to remove.
Now, the ServiceScheme dictates what communication protocol (BINDING, in terms of WCF) would be used when exposing the service and what binding would be used by the clients consuming this service. The ServicePort tells what port the service should be hosted on. Note that WCF allows hosting multiple services on the same port as long as their address is different (Except for MSMQ, i think).
The test client to consume the TestService is a different program, whose configuration is shown below. The program contains a WCF client to the TestImpl service whose details are obtained from the ConfigStation. Thus, the client process requires configuration which points to the ConfigStation.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:8731/ConfigStation/Repository" name="ConfigStation"
binding="wsHttpBinding"
contract="ConfigStation.ServiceContracts.IRepository">
</endpoint>
</client>
</system.serviceModel>
</configuration>
As you can see, the above is the only configuration required – which would be eliminated once I enhance the ConfigStation. The actual code to access the client is shown below.
namespace Test.Client
{
class Program
{
static void Main(string[] args)
{
var cf = new ClientProxyFacade<ITest>();
ITest test = cf.Interface;
var td = test.SayHello();
Console.WriteLine("Remote Server returned : " + td.Message);
}
}
}
You just create the ClientProxyFacade Of ITest, the service contract used by TestImpl. Then the interface is obtained via the “Interface” property. Then you can execute any method exposed by the Service Contract.
The library is available on codeplex – making this my first public release of open source software, of any kind. In the process, I would like to stress that the library uses the amazing ServiceModelEx library from Juval Lowy, IDesign. I actually tried to contact Juval whether or not to use his library but guess he is too busy so I took the liberty to publish the project having seen a WCF project on google code doing the same. In case I breach any license, please go easy on me and let me know so that I can fix my mistake.
I appreciate any positive feedback and any expert advice on the library. I am glad to learn and fix any changes requested. :) Hope this helps a few of us devs who like to play with some convention based WCF programming. I would be talking more details on the actual implementation, on how the library performs auto-generation of the service configuration and how bad the current repository implementation is, in my next post.