ServiceHandle is 0 - c#

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);
}
}

Related

How to write events from multiple applications(sources) to the same event log?

I have created a custom event log and would like all my applications to write to the same event log. As you can see below in the image attached, DistributedCOM and Svc Ctrl Mgr are 2 sources writing to the same event log System.
Similarly, I have 2 services that I want to write to the same eventLog.
I tried doing that by creating one event log and passing different source names from the 2 Windows Services that I have created. But I find only one Service writing to the log while the other doesn't.
Below is the class library that I created for Event Log.
public class EventLogger
{
private EventLog eventLog1 = new System.Diagnostics.EventLog();
public EventLogger(string logSource)
{
if (!System.Diagnostics.EventLog.SourceExists(logSource))
{
System.Diagnostics.EventLog.CreateEventSource(logSource, "SampleLog");
}
eventLog1.Source = logSource;
eventLog1.Log = "SampleLog";
}
public void WriteLog(string message)
{
eventLog1.WriteEntry(message);
}
Created 1st Windows Service
public partial class Service1 : ServiceBase
{
private EventLogger.EventLogger eventLog;
public Service1()
{
InitializeComponent();
eventLog = new EventLogger.EventLogger("WinService1");
}
protected override void OnStart(string[] args)
{
try
{
eventLog.WriteLog("Service started in 1st");
}
catch (Exception ex)
{
EventLog.WriteEntry(ex.ToString());
}
}
protected override void OnStop()
{
eventLog.WriteLog("Service stopped");
}
}
Created the 2nd windows Service as well, as above.
public partial class Service2 : ServiceBase
{
private EventLogger.EventLogger eventLog;
public Service2()
{
InitializeComponent();
eventLog = new EventLogger.EventLogger("WinService2");
}
protected override void OnStart(string[] args)
{
try
{
eventLog.WriteLog("Service started in 2nd");
}
catch (Exception ex)
{
EventLog.WriteEntry(ex.ToString());
}
}
protected override void OnStop()
{
eventLog.WriteLog("Service stopped");
}
}
Service1 doesn't seem to log anything, whereas, I can see the logs for Service2. I might be doing a lot of things incorrectly here. Please help me in finding a solution to this. Also, if this can be achieved by using log4Net then solutions with respect to that are welcome as well. thanks in advance.
EDIT: Also, when I try to stop the services, Service 1 fails to stop and throws an error. Image given below.
EDIT 2: Just changed the constructor of the EventLogger class as below and then it worked!! I am not entirely sure if this was the actual cause for the improper functioning. And I'm not quite sure if it had anything to do with the setting of the Log property either. Any light thrown on this by any one of you would be appreciated. I would like to understand better as to what exactly happened here. Thanks.
string logName = "NewLog";
public EventLogger(string logSource)
{
if (!System.Diagnostics.EventLog.SourceExists(logSource))
{
System.Diagnostics.EventLog.CreateEventSource(logSource, logName);
}
eventLog1.Source = logSource;
}

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");
}

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);
}
}

Running consol application in debug mode with WCF selfhosting?

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.

Categories