Tray Notify – Part III (WCF Service)

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

1. Introduction

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.


  • Part I – Covers the basic architecture and the creation of the common class library.

  • Part II – Covers the creation of the Windows Service and service installer using C#.

  • Part III – Covers the creation of the WCF service and how it’s hosted inside the Windows Service.

  • Part IV- Covers the WPF tray application and its communication with the WCF service.

  • 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.


    1. Load the CG.TrayNotify solution created in Part II

    2. Expand the CG.TrayNotify.WCF.Service project in the solution explorer.

    3. Delete the Service1.cs file

    4. Delete the IService1.cs file

    5. Open the App.config file and remove the entries between the <system.ServiceModel/> nodes.

    6. 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″ ?>
    <configuration>
    <system.serviceModel>
    </system.serviceModel>
    </configuration>


    1.1.2 Create a ITrayNotify Interface

    The ITrayNotify interface is used by the client application to register itself with the service.


    1. Right click on the CG.TrayNotify.WCF.Service project in the Solution Explorer.

    2. Choose, “New Item”

    3. Under “Templates:”, choose “WCF Service”

    4. Change the name to “TrayNotify.cs”

    5. 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:


    1. Within the “serviceBehaviors/behavior” node, rename the “CG.TrayNotify.Wcf.Service.TrayNotifyBehavior” name attribute to “TrayNotifyBehavior”.

    2. 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.



    3. In the “services/service/endpoint” node, do the following:


      • 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.



    4. In the “services/service/endpoint/host” node, change the baseAddress attribute to “http://localhost:8071/TrayNotify”

    The completed app.config file should resemble:


    <configuration>
    <system.serviceModel>
    <behaviors>
    <serviceBehaviors>
    <behavior name=”TrayNotifyBehavior”>
    <serviceMetadata httpGetEnabled=”true” />
    <serviceDebug includeExceptionDetailInFaults=”false” />
    </behavior>
    </serviceBehaviors>
    </behaviors>
    <services>
    <service behaviorConfiguration=”TrayNotifyBehavior”
    name=”CG.TrayNotify.Wcf.Service:CG.TrayNotify.Wcf.Service.TrayNotifyEndpoint”>
    <endpoint address=””
    binding=”wsDualHttpBinding”
    contract=”CG.TrayNotify.Common.Interface.ITrayNotify”>
    <identity>
    <dns value=”localhost” />
    </identity>
    </endpoint>
    <endpoint address=”mex” binding=”mexHttpBinding” contract=”IMetadataExchange” />
    <host>
    <baseAddresses>
    <add baseAddress=”http://localhost:8071/TrayNotify/” />
    </baseAddresses>
    </host>
    </service>
    </services>
    </system.serviceModel>
    </configuration>

    1.1.4 Add the interface methods and callback interface

    Open the ITrayNotify.cs file and modify the default interface.


    1. Add attribute parameters to the ServiceContract attribute


      • Add the SessionMode = SessionMode.Required

      • Add the CallbackContract = typeof( ITrayNotifyCallback )


    2. Add the Register, Unregister, Start and Stop methods

    3. Create the ITrayNotifyCallback interface and method

    The complete ITrayNotify and ITrayNotifyCallback interfaces should look like:


    [ServiceContract( SessionMode = SessionMode.Required, CallbackContract = typeof( ITrayNotifyCallback ) )]
    public interface ITrayNotify
    {
    [OperationContract]
    void Register( Guid instanceId );

    [OperationContract]
    void UnRegister( Guid instanceId );

    [OperationContract]
    void Start( Guid instanceId, string folderToMonitor );

    [OperationContract]
    void Stop( Guid instanceId, string folderToMonitor );
    }

    [ServiceContract]
    public interface ITrayNotifyCallback
    {
    [OperationContract]
    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.

    More by Author

    Get the Free Newsletter!

    Subscribe to Developer Insider for top news, trends & analysis

    Must Read