Having defined a WCF service in code, and built that code into an assembly, a runtime instance of the service must be “hosted” somewhere in order for other application to be able to connect to and interact with the service. There are several ways to host WCF services. In an earlier post I described how to Host a WCF Service in an ASP.NET Web Application, which is a commonly used approach. But in some situations, for example if the only requirement for an IIS web server is to host a WCF service, it is preferable to host a service in a different way. In this post I will describe how to do just that, by leveraging capabilities of the .NET Framework which allow WCF services to be “self hosted”.
This is the fifth in a series of posts relating to the various ways in which Synergy developers can use of Windows Communication Foundation (WCF) when building their applications. The posts in the series are:
As its name suggests, self hosting a WCF service refers to the ability to host a WCF service within another application that you write, rather than hosting the service in a container such as that provided by Internet Information Services (IIS), or Windows Process Activation Services (WAS).
The .NET Framework provides various classes that can be used to host WCF Services within the context of a .NET application. This could be any type of .NET application, including console applications and desktop applications. However, in most cases WCF services need to be continually available, and it is often not convenient to host a service in a console or desktop application, because those applications typically execute in the context of a logged in user session.
A Windows Service application on the other hand can provide an excellent mechanism for hosting a WCF service. Windows Services are generally designed to automatically start when a system boots, stopped when the system is closed down, be continually available while the system is running, and are not associated with the desktop of any logged in user.
Since 9.5.1a Synergy .NET has included a project template which makes creating a Windows Service very easy, and as you are about to see, adding the code necessary to instantiate and host a WCF service is relatively straight forward.
In this post I’m assuming that you have already created a WCF service that you wish to host. If you have read the earlier posts in this series you will already know of two ways to create a WCF service, and in a later post I’ll show you another way.
Using Synergy .NET it is very easy to create a Windows Service. We provide a project template called “Windows Service”, and when you create a new project from the template you essentially have all of the code that you need to implement the service. Of course, apart from starting and stopping a service the default code that you get from the template doesn’t actually do anything … that’s where you come in!
You’ll need a Windows development system with the following products installed
Follow these steps to create a new Windows Service:
As you can see, in my example I have named my service MyWcfHostService and have created the project below my c:temp folder.
Once the Windows Service project has been created, if you look in Solution Explorer you should see something like this:
You will notice that three source files were added to the project. In my example the file MyWcfHostService.dbl contains the code for the service itself, MyWcfHostServiceInstaller.dbl contains code used when the service is registered (installed), and Program.dbl is simply the main-line program that actually launches the service when the process starts.
Take a look at the main service source file (the one that ends …Service.dbl) and you will see that the code is relatively self explanatory. The class defined in the source file extends a parent class called ServiceBase. This means that our class has inherited a lot of functionality which essentially makes it a Windows Service.
You’ll also see that the class has a constructor method with the same name as the class itself, and the constructor calls a method called InitializeComponent, which sets various properties in order to configure various capabilities of the service.
private method InitializeComponent, void endparams proc this.ServiceName = "MyWcfHostService" this.AutoLog = true this.CanPauseAndContinue = false this.CanHandlePowerEvent = false this.CanShutdown = false this.CanStop = true endmethod
All Windows services have the ability to be started, and as you can likely derive from the code, by default a new service has the ability to be stopped, but not to be paused and continued, or to respond to changes in the systems power state (mains vs. battery).
So, our new service can start, and it can be stopped. All we need to do is define what code should be executed when the service starts, and when the service stops. And if you scroll down a little you will notice that the code already contains place-holder event handlers where we can add whatever code we need:
protected override method OnStart, void byval args, [#]String endparams proc ;;TODO: Add code to execute when the service is instructed to start endmethod protected override method OnStop, void endparams proc ;;TODO: Add code to execute when the service is instructed to stop endmethod
Our task is relatively straight forward. All we need to do is add whatever code is necessary to create and expose an instance of a WCF service in the OnStart method, and to stop the service in the OnStop method.
The WCF service that we will be hosting has already been created in a separate assembly, so to get access to it we need to add a reference to that assembly in our Windows Service project.
If your WCF service is defined in an xfNetLink .NET assembly then there are two additional steps that you will need to complete.
Add a reference to xfNetLink .NET
Because your WCF service is defined in an xfNetLink .NET assembly, that assembly will require that your project also has a reference to the xfNetLink .NET assembly.
Supply xfNetLink .NET Connection Information
Because your WCF service uses xfNetLink (to connect to xfServerPlus in order to execute your Synergy methods), you must tell xfNetLink where the instance of xfServerPlus is listening (host name or IP address, and port number). The best way to do this is via an application configuration (app.config) file.
Having added the configuration file to the project you need to specify the required configuration information, something like this:
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <sectionGroup name="xfnlnet"> <section name="default" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </sectionGroup> </configSections> <xfnlnet> <default> <add key="host" value="192.168.1.10" /> <add key="port" value="2356" /> </default> </xfnlnet> </configuration>
Note: You can also use the Synergy .NET Configuration Utility to add this information to the file. Clearly you should replace the IP address and port number with the correct values for your own instance of xfServerPlus.
In the most basic form, self-hosting a WCF service in another application essentially turns that application into a web server. The web server capabilities are provided by a class in the .NET Framework called ServiceHost. This class is found in a namespace called System.ServiceModel, and is provided the System.ServiceModel.dll assembly.
The code that we’ll be adding will use these web server capabilities to expose a “WCF Endpoint” at a specified HTTP address.
In addition to exposing an endpoint which is an instance of your WCF service, you will usually also want to expose a second “metadata endpoint”. This allows other applications that may need to interact with your WCF service to download the metadata for your service. The metadata fully describes the service and its capabilities, and is made available automatically by WCF. Clients applications can use a standard protocol called Metadata Exchange (often referred to as MEX) in order to download a WCF services metadata from a metadata endpoint. In code, we use a second class called ServiceMetaDataBehavior to expose our services metadata. This class is in the System.ServiceModel.Description namespace, and is also in the System.ServiceModel.dll assembly.
If all of this is starting to sound really complicated, well it is! Luckily the .NET Framework hides most of these requirements from us, and does most of the work. Despite sounding really complicated, the code that we need to write is remarkably simple.
To self host a WCF service there are generally three main things you will need:
So, lets write this thing:
import System.ServiceModel import System.ServiceModel.Description
private baseAddress ,String private host ,@ServiceHost private smb ,@ServiceMetadataBehavior
In the procedure division of the OnStart method, add code like this:
protected override method OnStart, void byval args, [#]String endparams proc ;;Define the URI for the service endpoint baseAddress = "http://" + Environment.MachineName + ":8080" ;;Create a ServiceHost instance for the WCF service host = new ServiceHost( & ^typeof(spc2011.SynergyServer), & new Uri(baseAddress)) ;;Add a BasicHttp endpoint host.AddServiceEndpoint( & ^typeof(spc2011.ISynergyServer), & new BasicHttpBinding(), & "SynergyServer") ;;Create a ServiceMetaDataBehavior instance smb = new ServiceMetadataBehavior() smb.HttpGetEnabled = true smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15 ;;Add a MEX endpoint host.Description.Behaviors.Add(smb) ;;Start the listener host.Open() endmethod
In my example, the namespace in which my WCF service is defined is “spc2011” and the name of the WCF service class is “SynergyServer”. You would need to:
IMPORTANT: When GENCS –W is used to create a WCF service, it applies the ServiceContract attribute to the CLASS that is created, rather than to the INTERFACE. So for xfNetLink .NET WCF services both of the above references should point to the CLASS.
Other than that, the code should work for any WCF service.
Now all that remains it to add the code to stop the WCF service when the Windows service stops. In the procedure division of the OnStop method, add this code:
protected override method OnStop, void endparams proc host.Close() host.Finalize() endmethod
It’s time to build the application and see how good your typing is!
------ Build started: Project: MyWcfHostService, Configuration: Debug Any CPU ------ ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
If your application does not build correctly then you’ll need to review the instructions above and make sure that you completed the required steps.
Now that you have a Windows service there are only two more steps that you’ll need to complete before the service can be tested. Those steps are:
To register the service you’ll need to open a Visual Studio command prompt window and then go the the folder that contains your applications executable. This will generally be the binDebug or binRelease folder below your project. Once you’re there you should be able to register your service like this:
..binDebug> INSTALLUTIL MyWcfHostService.exe
Look for messages that indicate that the service was successfully installed, then start your service like this:
..binDebug> NET START MyWcfHostService
Look for messages indicating that the service was started correctly.
If your Windows service started correctly then your WCF service should now be running. To verify that it is, open a browser and navigate to the URI that was specified in the code.
You should see a WCF service home page similar to this:
If you see a service page like this then you should be able to start using the service. Of course we haven’t talked about how to do that yet … that’s for another day!
You probably want to stop and unregister your Windows Service before you forget that it’s running. To do do, return to the Visual Studio command prompt and use commands like these:
..binDebug> NET STOP MyWcfHostService ..binDebug> INSTALLUTIL /u MyWcfHostService.exe