This is the third part of the Tray Notify series which illustrates how a Windows client app can communicate with a Window Service.
The sample application monitors file change events from the Windows service and uses a WCF service to send the change events to a task bar tray application.
This article will walk through the creation of the WCF service and how to host it inside the Windows Service that was created in Part II.
2. WCF Overview
A complete overview of WCF Services beyond the scope of this article but essentially WCF Services is Microsoft’s newer approach to creating Web Services. Earlier asmx Web Services (.net 2.0 and before) relied on IIS for hosting. With WCF services introduced in .Net 3.0, Microsoft has removed the IIS hosting restriction and has enabled WCF services to be hosted in any application including IIS, a Windows Service, or a .Net console, Winforms or WPF application.
In addition, WCF offers bindings that allow different communication protocols such as http, TCP/IP and msmq to be used. WCF offers additional security options as well.
For further information on WCF Service, see the Reference section at the end of this article.
3. Why use a WCF service as the communication layer?
A WCF service was chosen as the communication layer between the Windows Service and the client Tray application because it offers two-way communication and it can be hosted from a Windows Service application. The client application calls a WCF service method to register itself with the service, and the service uses the dual binding to send notifications back to the client. In addition, WCF services are not session dependent so they are able to provide the communication layer between the Windows service running in session 0 and an interactive process running in a logged on user session (n).
4. Build out the WCF Service
Starting with the source code built in Part II, we are going to create a couple of WCF service interfaces as well as the code that monitors the file change events. The first interface will be the interface used by the client applications to registering themselves with the service on startup. This lets the WCF know where to send the file change notification events. The second interface is the callback event interface that passes the file change notification events to the clients.
4.1 Create the TrayNotify Interface
4.1.1 Remove the default Service files
Remove the Service1 files from the CG.TrayNotify.WCF.Service project. By default, Visual Studio always adds this interface to a WCF Service project. Since we’ll be adding our own interface, we can delete the files related to this interface.
- Load the CG.TrayNotify solution created in Part II
- Expand the CG.TrayNotify.WCF.Service project in the solution explorer.
- Delete the Service1.cs file
- Delete the IService1.cs file
- Open the App.config file and remove the entries between the <system.ServiceModel/> nodes.
- Since we’ll be hosting this WCF Service in the Windows Service application, you can remove the <system.web/> nodes.
You should be left with the following app.config entries:
<?xml version=”1.0″ encoding=”utf-8″ ?>
1.1.2 Create a ITrayNotify Interface
The ITrayNotify interface is used by the client application to register itself with the service.
- Right click on the CG.TrayNotify.WCF.Service project in the Solution Explorer.
- Choose, “New Item”
- Under “Templates:”, choose “WCF Service”
- Change the name to “TrayNotify.cs”
- Click “Add”
1.1.3 Modify the app.config file
The app.config file will contain the new ITrayNotify service config entries. Modify the app.config file as follows:
- Within the “serviceBehaviors/behavior” node, rename the “CG.TrayNotify.Wcf.Service.TrayNotifyBehavior” name attribute to “TrayNotifyBehavior”.
- In the “services/service” node, do the following:
- Change the behaviorConfiguration entry to “TrayNotifyBehavior”.
- Change the name attribute from “CG.TrayNotify.Wcf.Service.TrayNotify” to “CG.TrayNotify.Wcf.Service:CG.TrayNotify.Wcf.TrayNotify”.
Notice how the name contains a ‘:’. The left side of the colon contains the assembly name of the class contained on the right side. This isn’t a standard WCF services naming convention; however, this format will be used by the WcfServiceHost class which was added to the CG.TrayNotify.Common library in Part I.
- Change the binding attribute to “wsDualHttpBinding”. Dual binding will enable the WCF Service to make calls to the client application. More on this later in Part IV.
- Change the contract attribute to “CG.TrayNotify.Common.Interface.ITrayNotify”.
Note: at present the ITrayNotify interface is not located in the CG.TrayNotify.Common class library; however, we will move it to the common library later.
The completed app.config file should resemble:
<serviceMetadata httpGetEnabled=”true” />
<serviceDebug includeExceptionDetailInFaults=”false” />
<dns value=”localhost” />
<endpoint address=”mex” binding=”mexHttpBinding” contract=”IMetadataExchange” />
<add baseAddress=”http://localhost:8071/TrayNotify/” />
1.1.4 Add the interface methods and callback interface
Open the ITrayNotify.cs file and modify the default interface.
- Add attribute parameters to the ServiceContract attribute
- Add the SessionMode = SessionMode.Required
- Add the CallbackContract = typeof( ITrayNotifyCallback )
The complete ITrayNotify and ITrayNotifyCallback interfaces should look like:
[ServiceContract( SessionMode = SessionMode.Required, CallbackContract = typeof( ITrayNotifyCallback ) )]
public interface ITrayNotify
void Register( Guid instanceId );
void UnRegister( Guid instanceId );
void Start( Guid instanceId, string folderToMonitor );
void Stop( Guid instanceId, string folderToMonitor );
public interface ITrayNotifyCallback
void OnFileChangeEvent( FileEventArgs e );
WCF Service comment
Setting the SessionMode parameter to Required forces WCF to retain session state between service calls. This is necessary in order to retain the connection to the ITrayNotifyCallback interface which gets registered when the client first connects to the server.