Running consol application in debug mode with WCF selfhosting? - c#

I have a WCF service hosted in a consol application(that also acts as the Windows Service installer), pleas see more here : http://msdn.microsoft.com/en-us/library/ms733069.aspx
This is how the class in the consol application looks like :
public class MyAppWindowsService : ServiceBase
{
public ServiceHost _MyAppClientServiceHost = null;
public ServiceHost _MyAppIntegrationServiceHost = null;
public ServiceHost _MyAppserviceHost = null;
public MyAppWindowsService()
{
// Name the Windows Service
ServiceName = "MyApp Service";
}
public static void Main()
{
ServiceBase.Run(new MyAppWindowsService());
}
private void StopService(ServiceHost serviceHost)
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
private ServiceHost StartService(Type serviceType)
{
ServiceHost serviceHost = null;
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(serviceType);
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
return serviceHost;
}
private void StartServices()
{
StopService(_MyAppClientServiceHost);
StopService(_MyAppIntegrationServiceHost);
StopService(_MyAppServiceHost);
_MyAppClientServiceHost = StartService(typeof(MyApp.ServiceImplementation.MyAppClientService));
_MyAppIntegrationServiceHost = StartService(typeof(MyApp.ServiceImplementation.MyAppIntegration));
_MyAppServiceHost = StartService(typeof(MyApp.ServiceImplementation.HL7Service));
}
private void StopServices()
{
StopService(_MyAppClientServiceHost);
StopService(_MyAppIntegrationServiceHost);
StopService(_MyAppHl7ServiceHost);
}
// Start the Windows service.
protected override void OnStart(string[] args)
{
StartServices();
}
protected override void OnStop()
{
StopServices();
}
}
This is made for running in a Windows Service, how do I make so I can run this as a regular selfhost in debug mode(during development)? or do I really have to start a special project to be able to debug this servuce during runtime?
Edit:
I decided to use the existing windows service project but change the main to something like this :
public static void Main()
{
if (Debugger.IsAttached)
{
Console.WriteLine("--- MyApp Services ---");
Console.WriteLine("Starting services...");
Instance.StartServices();
Console.WriteLine("--Finished--");
Console.WriteLine("Press any key to exit");
Console.ReadKey();
Instance.StopServices();
}
else
ServiceBase.Run(new MyAppWindowsService());
}

This is what I do
Solution A
Install a Windows Service using InstallUtil from my Debug\bin folder
Stop and start service using sc start or sc stop
Once service started do Debug > Attach to Process... and attach VS to the service
Solution B
Have a Debugger.Break call on the first line of the OnStart method.
Solution C
Add a temp separate console application that does the same job as your service.

Related

How to communicate to Windows Service through WCF?

I have Windows Service, which is running tasks on timer tick. I also selected to communicate with Windows Service through WCF named pipe channel. I can create WCF Service instance and open it for listening. But how I access objects relying in Windows Service via WCF?
This is what my Windows Service looks like:
public partial class MyService : ServiceBase
{
private ServiceHost m_svcHost = null;
private myObject = null;
...
// Run this method from external WCF client
private void SomeMethod()
{
}
protected override void OnStart(string[] args)
{
if (m_svcHost != null) m_svcHost.Close();
m_svcHost = new ServiceHost(typeof(MyCommunicationService));
m_svcHost.Open();
// initialize and work with myObject
}
protected override void OnStop()
{
if (m_svcHost != null)
{
m_svcHost.Close();
m_svcHost = null;
}
}
}
So what I want, to have access to myObject within WCF Service, when client will make inquiry. Or even run a method on myObject.
You can create a communication channel between your MyService (WCF Hosting entity) and the MyCommunicationService (WCF Service instance) simply using a static property:
//This can be put into a separate DLL if needed.
public interface IMyHostCallbacks
{
void HostCallback(string iSomeDataFromWCFToHost);
}
public static class Host
{
public static IMyHostCallbacks Current;
}
public partial class MyService : ServiceBase, IMyHostCallbacks
{
protected override void OnStart(string[] args)
{
//Set the static callback reference.
Host.Current = this;
if (m_svcHost != null) m_svcHost.Close();
m_svcHost = new ServiceHost(typeof(MyCommunicationService));
m_svcHost.Open();
// initialize and work with myObject
}
//Here you have data from WCF and myObject available.
void IMyHostCallbacks.HostCallback(string iSomeDataFromWCFToHost)
{
//Be careful here.
//Depending on your WCF service and WCF clients this might
//get called simultaneously from different threads.
lock(myObject)
{
myObject.DoSomething(iSomeDataFromWCFToHost);
}
}
}
Surely you can even put the static field into your MyService class but at least some abstraction between MyService and MyCommunicationService would not hurt.
Now, in any place in your MyCommunicationService you can:
void WCFServiceMethod()
{
Host.Current.HostCallback("some data");
}

ServiceBase OnStart Not receiving args from serviceController.Start

As I understand it, the serviceBase.Onstart(args) should recieve arguments that are present in serviceController.start(args).
Here is my service controller implementation
if (serviceController.Status == ServiceControllerStatus.Stopped)
{
try
{
string[] args = {"execute-service"};
serviceController.Start(args);
ServiceManager.WaitForStatusChange(......);
}
catch (InvalidOperationException ex)
{
EventLog.WriteEntry(.....);
return 1;
}
}
Here is my service.cs
protected override void OnStart(string[] args)
{
this.OnStart(args);
this.scheduler.StartScheduler();
}
When I attempt to start my service, the argument "execute-service" is not passed to the main program.cs. I have a logFile that is being created and can see the args are not there.
Looking for some ideas on how to pass the args, as I read online, I am doing it correctly using the servicebase.onstart().
Thoughts on how to debug or fix?
I don't think there is enough information shown here to debug this issue. For comparison, this is what I do in a console application designed to run as a Windows service:
public sealed partial class ServiceMain : ServiceBase
{
// Service startup modes.
private const string DEBUG = #"/d";
private const string INSTALL = #"/i";
private const string UNINSTALL = #"/u";
Then ServiceMain.Main() is set is set as the startup method:
// This is the entry point for this service.
// This method runs on an SCM thread.
public static void Main(string[] args)
{
if (Environment.UserInteractive && args.Length > 0)
{
switch (args[0])
{
// Debug the service as a normal app, presumably within Visual Studio.
case DEBUG:
ServiceMain DebugService = new ServiceMain();
DebugService.OnStart(null);
break;
Which calls the ServiceMain.OnStart() method:
// SCM requests service start using its own thread.
// This method must complete within 10 seconds of it
// starting. Otherwise the SCM diagnoses a hang.
protected override void OnStart(string[] args)
{
this.AppLog = new Log();
AppLog.Information("SCM requested service start.", "ServiceMain.OnStart");
You can see the whole service in context here.

C# command prompt app to windows service - How to create an installer class

How do I convert a command prompt app to a windows service? So far this is what I have, but when I try to install it with InstallUtil.exe I'm received an error:
No public installers with the RunInstallerAttribute.Yes attribute could be found in the ....
I didn't know I had to create an installer class and I'm not sure how to go about this. Can someone help me by telling me how to write an installer class so that I can install my app as a windows service?
class Program
{
public const string ServiceName = "ProcessingApp";
public class Service : ServiceBase
{
public Service()
{
ServiceName = Program.ServiceName;
}
protected override void OnStart(string[] args)
{
Program.Start(args);
}
protected override void OnStop()
{
Program.Stop();
}
}
private static void Start(string[] args)
{
// onstart code here
StartCode();
}
private static void Stop()
{
// onstop code here
ServiceController service = new ServiceController(ServiceName);
try
{
TimeSpan timeout = TimeSpan.FromMilliseconds(100000);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
}
catch
{
}
}
static void Main(string[] args)
{
if (!Environment.UserInteractive)
// running as service
using (var service = new Service())
ServiceBase.Run(service);
else
{
// running as console app
Start(args);
Console.WriteLine("Press any key to stop...");
Console.ReadKey(true);
Stop();
}
For that to work, you need to have a class that inherits from System.Configuration.Install.Installer in System.Configuration.Install.dll. TThe constructor should configure a ServiceProcessInstaller and a ServiceInstaller, and add them both to the Installers collection - setting the Account, StartType, ServiceName, Description, etc.
MSDN has an example: https://msdn.microsoft.com/en-us/library/system.serviceprocess.serviceprocessinstaller(v=vs.110).aspx

C# - Is it possible to have a single .exe act as an application (when clicked) or a service (when run by windows)

Is it possible to have an application that runs as a service if it is registered as such but if it is double clicked simply starts a regular interactive application?
Yes. You can use the Environment.UserInteractive variable. You will need to create a small wrapper around your service to expose the OnStart() and OnStop() methods since they are protected.
var service = new MyService();
if (Environment.UserInteractive)
{
service.Start(args);
Console.WriteLine("Press any key to stop program");
Console.Read();
service.Stop();
}
else
{
ServiceBase.Run(service);
}
Wrapper Class (Make sure to extend ServiceBase)
public partial class MyService : ServiceBase
{
protected override void OnStart(string[] args)
{
//start code
}
protected override void OnStop()
{
//stopcode
}
public void Start(string[] args)
{
OnStart(args);
}
}

ServiceHandle is 0

I'm trying to write simple wcf service self hosted in windows service
But ServiceHandle of windows service is always 0
I need to detect hardware change using RegisterDeviceNotification
One of it's parameters is Handle, in my case is ServiceHandle
public partial class MyService : ServiceBase, IMyService
{
private ServiceHost host;
public static void Main()
{
ServiceBase.Run(new MyService());
}
public MyService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
host = new ServiceHost(typeof(MyService), new Uri(#"net.pipe://localhost/MyService"));
host.Open();
}
catch (Exception e)
{
EventLog.WriteEntry("MyService:", e.Message);
}
}
protected override void OnStop()
{
host.Close();
}
#region IMyService Members
public void Register()
{
//Here the ServiceHost is 0
}
#endregion
}
What can cause the problem?
Thanks
The ServiceHandle - no matter what value - is not required to host a WCF service as a Windows service. Simply instantiate the ServiceHost in OnStart and close it in OnStop and you should be fine.
This is why ServiceHandle is always 0 in your case:
Your Windows service class implements your WCF service contract. This is not a good thing and is also the cause for the ServiceHandle property being 0. For every call to the WCF service a new instance of the MyService class is instantiated (if you didn't change the defaults). This instance is a normal instance of the class that doesn't know it's a Windows Service, so all Windows Service related properties have their default values. Only the instance that's created by the Windows Service manager has all the appropriate properties set.
You can try for yourself: In OnStart, insert the following line and inspect the value for myServiceVar.ServiceHandle. You'll see it is 0:
MyService myServiceVar = new MyService();
What you really want to do is the following: Have a different class implement the service contract, for example like that:
public class MyWCFService : IMyService
{
public static IntPtr ServiceHandle;
public void Register()
{
// Use MyWCFService.ServiceHandle here
}
}
In the OnStart method, set the ServiceHandle variable of MyWCFService:
protected override void OnStart(string[] args)
{
try
{
MyWCFService.ServiceHandle = this.ServiceHandle;
host = new ServiceHost(typeof(MyWCFService), new Uri(#"net.pipe://localhost/MyService"));
host.Open();
}
catch (Exception e)
{
EventLog.WriteEntry("MyWCFService:", e.Message);
}
}

Categories