CmdLineService (what is does / how to use)

Project Description

This project is both a discussion about .Net3.0 hosting (WCF/WF) and a sample project.

You probably meet the same needs regularly :
- hosting a WCF server in a win-service,
- handle faulted exceptin to restart your WCF server in case of failure,
- creating an installer for that service,
- accessing the WCF server directly in case of Singleton pattern,
- debug this service without having to reinstall it each compile time (just like in command line host).

For these reasons (and some few others) here is a code that will give you a very simple way to do so in less than a single minute.

How to use it

With "MyServiceHost", the name of you win-service class.
With "TheNameOfTheWCFServiceClass", the class exposed as a WCF service, not the interface.
With "MyServiceName", the name of your win-service itself (see below for more details).

1/3) First create the host service

In your solution, add a new console application, and reference your WCF project.
Add a reference to CmdLineService, System.ServiceProcess, and System.Configuration.Install
Leave the Program.cs for later use, and add a Host.cs.

Write down these few lines in Host.cs :
using System.Runtime;

class MyServiceHost : CmdLineService<TheNameOfTheWCFServiceClass>
{
    public override string ServiceName { get { return "MyServiceHost"; } }
    protected override void  OnStart(string[] args) { StartHosting(); }
    protected override void  OnStop() { StopHosting(); }
}


2/3) Then create the Main() function and the installer

Modify your Program.cs like this :
using System.Runtime;
using System.ComponentModel;

class Program
{
    static void Main(string[] args)
    { ProgHelper.DoWork(new ServiceBase[] { new MyServiceHost() }, args); }
}

[RunInstaller(true)]
public class ProjectInstaller : ProjectInstallerHelper
{ 
    public ProjectInstaller() : base("MyServiceHost") { } 
}



3/3) Run it !

Using Visual Studio under Administrative rights (to be allowed to start hosting) :

If you've followed the lines before, you're done !
- If you want to install your new service, go to command prompt (the one provided with Visual Studio),
and, in the output directory, enter : "installutil ProjectName"
OR
- If you want to start hosting from Visual Studio, add "/c" as the Command line argument.
(To do so, just double click "Properties" in your host, and select the Debug tab.
Also in the Property page / Application tab : don't forget to specify the project output as a "Console Application"...)


(OPTIONAL) Hosting a Workflow Foundation (WF) server

See bellow, in the next section...

The way it works

Building a host

About the window services

There are many advantages in building a win service host (instead of a webservice) :
  • It can start up and close with a server
  • The WCF server integrated in a win service can function with every kind of protocol (as webservices can, but only under IIS7)
  • Managing cluster from win services health is easy (using MSCS)
  • The only management to configure is in the configuration file.

About the wcf services

There are two main kind of WCF Servers :
  • Those using the Singleton pattern
  • Those, like webservices, with session handling, parallelized.
When creating a WCF service, you can choose to build it by reflexion, from the type of the object,
or from a single object, that you can use later :
switch (attrinfo.InstanceContextMode)
{
case InstanceContextMode.Single:
    m_myServiceHost = new ServiceHost(m_refObject);
    break;
default:
    m_myServiceHost = new ServiceHost(typeof(T));
    break;
}

<to be continued...>

About command prompt

The main advantage for using the command line is testing the startup.
Accessing other functionalities is risky because you might not have access to it at run time.
<to be continued...>

About project installer

Project installer works by inspecting the body of the assembly.
Just specifying the name helps install your service.
<to be continued...>

Link with WF

The concept

One of the main question regarding WF is "how can we host it" ?
In fact, for people that deal with BPM, the answer is obvious : 2 functions make it easy.
(each using the OperationContext.Current.ServiceSecurityContext.WindowsIdentity to get the user identity from WCF)
  • One function to get the list of tasks the current user can access,
  • One function returning the list of functions authorized to the user for that task
But one question remains : how to handle functions that do not need a human interaction,
such as sending an e-mail to inform a customer a trial period has expired ?
In fact, holding the service runtime alive is sufficient, which means :
  1. Create a Singleton for the WF runtime,
  2. Hold the Runtime into the WCF Singleton Service,
  3. Hold the WCF Service into a host.
Try with a mailing activity : take care that the WF Runtime needs up to 2 minutes to weak up the first time,
short, for most of your needs, but very long, for a single test...

Application with CmdLineSerice tool

The last, but not the least, function avaible, is the direct access to your WCF server.
One common use-case is hosting a WorkflowRuntime.

For example, if your Workflow has a persistent DelayActivities, these one may wake up at any time (with a precision of 2 minutes delay, due to the WF Runtime engine), so the Workflow needs to stay alive.

Add an Init() method to your WCF server :
[ServiceContract]
public interface IWFServer
{
    [OperationContract]
    void Init();
}

[ServiceBehaviorAttribute(InstanceContextMode=InstanceContextMode.Single)]
public class WFServer : IWFServer
{
    (...)
    public void Init()
    { this.workflowRuntime.StartRuntime(); }
}

Finally, modify your Host code to call the init method at startup :
    protected override void  OnStart(string[] args) 
    { 
         //The WCF initialisation
         StartHosting(); 

         //The WF startup
         RefObject.Init();
    }


RefObject is a direct pointer to your WCF server, because you ran it as a Singleton pattern : [ServiceBehaviorAttribute(InstanceContextMode=InstanceContextMode.Single)]...

Last edited Jul 16, 2008 at 5:36 AM by poupou, version 28