How to run project from windows service project - c#

I have 3 projects in my solution:
Scheduler (Windows application)
WCF Service (WCF)
WindowsService (Windows Service)
My Scheduler use WCF Service functions and runs them when Scheduler decide.
All this works fine,and know i add new project Windows Service that his purpose is to launch Scheduler every time when PC is up, and here I fail.
I never worked with Windows Service sow i am new at this.I added the reference of Scheduler to WindowsService and still can't find the way to run it.
I will be very glad for any help.
Here my code that i tried.
My WindowsService project
My namespace WindowsService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
// Scheduler myscheduler = new Scheduler();
// Scheduler.SchedulerForm myForm = new Scheduler.SchedulerForm();
}
protected override void OnStop()
{
}
}
}
And my Scheduler Project (Main)
static void Main()
{
string step = "";
try
{
ServiceHost client = new ServiceHost(typeof(WcfService.Service));
try
{
using (client = new ServiceHost(typeof(WcfService.Service)))
{
step = "1";
if (client.State == CommunicationState.Faulted)
{
step = "2";
System.Windows.Forms.MessageBox.Show(step);
System.Windows.Forms.MessageBox.Show("Faulted state. " + step);
client.Abort();
}
client.Open();
SysTrayApp();
Application.Run();
}
}
catch (Exception ex)
{
if (client.State == CommunicationState.Faulted)
{
step = "Faulted";
System.Windows.Forms.MessageBox.Show(step);
client.Abort();
client = new ServiceHost(typeof(WcfService.Service));
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message + " " + ex.Source + " " + ex.StackTrace);
}
}

Related

ASP.NET Boilerplate & Windows service

I am creating a simple ASP.NET solution that is based on the ABP and as a part of this solution I use a standard Windows service that is supposed to do small background operations (so far only ICMP ping, but later probably more).
Is it possible to use the ABP application services inside of this Windows service (ideally using IoC)?
Thanks for any suggestion.
ofcourse you can use your AppServices in a Windows Service project. Also you can write background jobs in the windows service. You need to reference to your Application project from Windows Service. As each project behaves as module. Your new Windows Service needs to be registered as module. so you can use dependency services and other useful ABP libraries.
I'll show you some sample codes about moduling. But i recommend you to read the module doc : https://aspnetboilerplate.com/Pages/Documents/Module-System
MyWindowsServiceManagementModule.cs
[DependsOn(typeof(MySampleProjectApplicationModule))]
public class MyWindowsServiceManagementModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
MyWindowsServiceWinService.cs
public partial class MyWindowsServiceWinService : ServiceBase
{
private MyWindowsServiceManagementBootstrapper _bootstrapper;
public MyWindowsServiceWinService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
_bootstrapper = new MyWindowsServiceManagementBootstrapper();
_bootstrapper.Initialize();
}
catch (Exception ex)
{
//EventLog.WriteEntry("MyWindowsService can not be started. Exception message = " + ex.GetType().Name + ": " + ex.Message + " | " + ex.StackTrace, EventLogEntryType.Error);
}
}
protected override void OnStop()
{
try
{
_bootstrapper.Dispose();
}
catch (Exception ex)
{
//log...
}
}
}
MyWindowsServiceManagementBootstrapper.cs
public class MyWindowsServiceManagementBootstrapper : AbpBootstrapper
{
public override void Initialize()
{
base.Initialize();
}
public override void Dispose()
{
//release your resources...
base.Dispose();
}
}
Ps: As I wrote the codes on the top off my head, it might throw errors but basically this should guide you.

How to initialize singleton class in Windows Service Hosted WCF Service on startup

I wrote windows service hosted wcf service.
Service behavior is:[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
I read some data from DB and create some shared classes on startup. There are also some timers should work even if there is no request. Also initialization takes some time.
All this initialization happens in a singleton class which is in another dll. I try different signleton class initializations described here.
But the singleton class is not initialized until first request arrives. Timers, object loaded from DB ... etc. all of them is in this singleton class. After first request arrives everthing working just fine. Also service seems working on Services window even if classes are not initialized.
In debugger before a request arrives, dll doesn't even loading.
How can i initilalize this singleton class on startup?
Is this a service behavior problem or should i change Windows Service installer?
EDIT:
Reformat question.
You can start your WCF service on OnStart windows service event and stop it on OnStop windows event. You can add some diagnostic info to your windows event log to see if there is any exception and check if service is stared or not etc.
using System;
using System.ServiceModel;
using System.ServiceProcess;
using System.Diagnostics;
using System.Configuration;
using System.Timers;
using System.Collections.Generic;
namespace MyWCF
{
public partial class WcfOverHttpService : ServiceBase
{
private ServiceHost m_host;
public WcfOverHttpService()
{
System.Diagnostics.EventLog.WriteEntry(" WCF Interface", " Constructor called.", EventLogEntryType.Information);
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
System.Diagnostics.EventLog.WriteEntry(" WCF Interface", "On Start called.", EventLogEntryType.Information);
StartWcfService();
}
catch (Exception ex)
{
System.Diagnostics.EventLog.WriteEntry(" WCF Interface","On Start failed :"+ex.ToString(), EventLogEntryType.Error);
throw ex;
}
}
private void StartWcfService()
{
try
{
System.Diagnostics.EventLog.WriteEntry(" WCF Interface", "Start Wcf Service.", EventLogEntryType.Information);
m_host = new ServiceHost(typeof(MyWCFService));
m_host.Open();
System.Diagnostics.EventLog.WriteEntry(" WCF Interface", "WCF Service HostOpen.", EventLogEntryType.Information);
}
catch (Exception ex)
{
System.Diagnostics.EventLog.WriteEntry(" WCF Interface", "Start WCF Service failed :" + ex.ToString(), EventLogEntryType.Error);
throw ex;
}
}
protected override void OnStop()
{
try
{
System.Diagnostics.EventLog.WriteEntry(" WCF Interface", "On Stop called.", EventLogEntryType.Information);
if (m_host != null)
{
System.Diagnostics.EventLog.WriteEntry(" WCF Interface", "Stop WCF Service.", EventLogEntryType.Information);
m_host.Close();
m_host = null;
}
}
catch(Exception ex)
{
System.Diagnostics.EventLog.WriteEntry(" WCF Interface", "On Stop failed :" + ex.ToString(), EventLogEntryType.Error);
throw ex;
//handle exception
}
}
}
}
This is how you could implement timer logic.
using System;
using System.ServiceModel;
using System.ServiceProcess;
using System.Diagnostics;
using System.Configuration;
using System.Timers;
using System.Collections.Generic;
namespace MyAppNameSpace
{
public partial class MyWCFService : ServiceBase
{
private ServiceHost m_host;
System.Timers.Timer MyProductionTimer = null;
bool _MyProductionRunOnce = false;
//// Put this values in Config
private string MyProductionSchedule = "DAILY";
private string MyProductionToRun = "MANY";
private string MyProductionStartTime = "10:00 PM";
private int MyProductionPollInterval = 60000;
public MyWCFService()
{
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Constructor", " Constructor called.", EventLogEntryType.Information);
InitializeComponent();
//Create Timer Object and register tick event
this.MyProductionTimer = new System.Timers.Timer(MyProductionPollInterval);
this.MyProductionTimer.Elapsed += new ElapsedEventHandler(this.MyProductionTimer_Tick);
}
protected override void OnStart(string[] args)
{
try
{
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Start", "On Start called.", EventLogEntryType.Information);
StartWcfService();
// Setup timer and start it
this.MyProductionTimer.Interval = MyProductionPollInterval;
this.MyProductionTimer.Enabled = true;
this.MyProductionTimer.Start();
System.Diagnostics.EventLog.WriteEntry("My MyProduction Timer Start", "MyProduction Timer Start At :" + DateTime.Now.ToString(), EventLogEntryType.Information);
}
catch (Exception ex)
{
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Start Error","On Start failed :"+ex.ToString(), EventLogEntryType.Error);
throw ex;
}
}
protected override void OnStop()
{
try
{
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Stop", "On Stop called.", EventLogEntryType.Information);
//Stop the timer
this.MyProductionTimer.Stop();
System.Diagnostics.EventLog.WriteEntry("My MyProduction Timer Stop", "MyProduction Timer Stopped At :" + DateTime.Now.ToString(), EventLogEntryType.Information);
if (m_host != null)
{
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Stopped", "Stop Wc fService.", EventLogEntryType.Information);
m_host.Close();
m_host = null;
}
}
catch(Exception ex)
{
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Stop Error", "On Stop failed :" + ex.ToString(), EventLogEntryType.Error);
throw ex;
//handle exception
}
}
//Timer Tick Event
private void MyProductionTimer_Tick(object sender, EventArgs e)
{
this.MyProductionTimer.Stop();
this.MyProductionTimer.Interval = MyProductionPollInterval;
bool runFlag = false;
try
{
// Find out if it is time to run logic based on schedule
string dw = DateTime.Now.DayOfWeek.ToString();
if ((MyProductionSchedule.ToUpper() == "DAILY" && MyProductionToRun.ToUpper() == "ONCE") ||
(MyProductionSchedule.ToUpper() == dw.ToUpper() && MyProductionToRun.ToUpper() == "ONCE"))
{
if (checkPolTime(MyProductionStartTime))
_MyProductionRunOnce = true;
if (_MyProductionRunOnce)
{
_MyProductionRunOnce = false;
runFlag = true;
}
}
else if ((MyProductionSchedule.ToUpper() == "DAILY" && MyProductionToRun.ToUpper() == "MANY") ||
(MyProductionSchedule.ToUpper() == dw.ToUpper() && MyProductionToRun.ToUpper() == "MANY"))
{
if (!_MyProductionRunOnce)
{
if (checkPolTime(MyProductionStartTime))
_MyProductionRunOnce = true;
}
if (_MyProductionRunOnce)
runFlag = true;
}
else
{
_MyProductionRunOnce = false;
}
if (runFlag)
{
// Your Timer Business Logic goes here
}
}
catch (Exception exc)
{
System.Diagnostics.EventLog.WriteEntry(" MyProduction Timer Error",
exc.Message, EventLogEntryType.Error);
}
finally
{
this.MyProductionTimer.Start();//To restart the processing of production
}
}
private void StartWcfService()
{
try
{
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Create Host", "Start Wcf Service.", EventLogEntryType.Information);
m_host = new ServiceHost(typeof(WcfService));
m_host.Open();
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Host Opened", "WCF Service HostOpen.", EventLogEntryType.Information);
}
catch (Exception ex)
{
System.Diagnostics.EventLog.WriteEntry("My WCF Interface Exception", "Start WCF Service failed :" + ex.ToString(), EventLogEntryType.Error);
throw ex;
}
}
// Utility to check if it is time to run the timer logic
public static bool checkPolTime(string ProdStartTime)
{
DateTime t1 = DateTime.Now;
DateTime t2 = Convert.ToDateTime(ProdStartTime);
int i = DateTime.Compare(t1, t2);
if (i >= 0)
{
return true;
}
else
{
return false;
}
}
}
}

EasyNetQ Windows Service messaging architecture not quite working

So I am trying to experiment (based on this EasyNetQ toturial: Quick Start - EasyNetQ) with a simple EasyNetQ messaging architecture involving a Publisher and a Subscriber and it doesn't seem to be working quite as expected. Both my Publisher and Subscriber are Windows Service projects in Visual Studio 2015 and the message being sent between them is an instance of a custom type (TextMessage), which is a simple Class Library that looks like this:
namespace Messaging.Messages
{
public class TextMessage
{
public string Text { get; set; }
}
}
My Publisher looks like this:
namespace Messaging.Publisher
{
public partial class ReportService : ServiceBase
{
private Timer timer = null;
public ReportService()
{
this.InitializeComponent();
}
protected override void OnStart(string[] args)
{
Library.WriteErrorLog("Report Publisher Service started");
using (var bus = RabbitHutch.CreateBus("host=localhost"))
{
bus.Publish(new TextMessage
{
Text = "Hello"
});
}
}
protected override void OnStop()
{
this.timer.Enabled = false;
Library.WriteErrorLog("Test window service has stopped");
}
}
}
So nothing fancy. All it does is publish one message of type TextMessage and logs to a text file "PublisherLogFile.txt":
namespace Messaging.Publisher
{
public static class Library
{
public static void WriteErrorLog(string Message)
{
StreamWriter sw = null;
try
{
sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\PublisherLogFile.txt", true);
sw.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture) + ": " + Message);
sw.Flush();
sw.Close();
}
catch (Exception)
{
throw;
}
}
}
}
And the Subscriber looks like this:
namespace Messaging.Subscriber
{
public partial class ReportSubscriberService : ServiceBase
{
public ReportSubscriberService()
{
this.InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteErrorLog("Report Subscriber Service started");
using (var bus = RabbitHutch.CreateBus("host=localhost"))
{
bus.Subscribe<TextMessage>("testId", HandleTextMessage);
}
}
protected override void OnStop()
{
WriteErrorLog("Exiting Report Subscriber Service");
}
private static void HandleTextMessage(TextMessage textMessage)
{
WriteErrorLog("Got message: " + textMessage.Text);
}
private static void WriteErrorLog(string Message)
{
try
{
var sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\SubscriberLogFile.txt", true);
sw.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture) + ": " + Message);
sw.Flush();
sw.Close();
}
catch (Exception)
{
throw;
}
}
}
}
Also very simple. All it does is receive messages of type TextMessage and prints out the value of their Text attribute to a log file "SubscriberLogFile.txt". The problem is that it doesn't seem to be receiving the message because it doesn't log to the text file above. It looks like the HandleTextMessage handler in my Suscriber is never called. This is the content of "SubscriberLogFile.txt":
Also, looking at the RabbitMQ management console, no connections or channels are created, just one queue:
And the RabbitMQ log:
When I first did the same experiment, but with the difference that the Publisher and Subscriber were Console Applications instead of Windows Services, things seemed to work fine. What could be the problem here?
The problem was that I was disposing the bus as soon as I opened it. Instead it has to stay open and only be disposed when the service is stopped, on the OnStop event.

Start WCF service in a new AppDomain to enable shadow copy (Windows Service hosted)

I have a WCF service library (MyWCFService), which uses MEF to load plugins and hosted by Windows services (All .NET 4.0). I am now trying to run it in a new AppDomain and to enable ShadowCopyFiles in a hope that I can update plugins in the runtime. Here is the code in the Windows service project.
Program.cs
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
}
}
MyService.cs
public partial class MyService: ServiceBase
{
internal static ServiceHost MyServiceHost = null;
public MyService()
{
// this works but is deprecated..
AppDomain.CurrentDomain.SetShadowCopyFiles();
//this is not working.. DLLs still get locked. Require for a new AppDomain
//AppDomain.CurrentDomain.SetupInformation.ShadowCopyFiles = "true";
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if(MyServiceHost !=null)
{
MyServiceHost.Close();
}
try
{
MyServiceHost= new ServiceHost(typeof(MyWCFService));
MyServiceHost.Open();
}
catch(Exception)
{
}
}
protected override void OnStop()
{
if (MyServiceHost!= null)
{
MyServiceHost.Close();
MyServiceHost= null;
}
}
}
Is there any way of doing it? I have done a lot of search, but still don't know how to make it work with my current settings (or I just can't understand...)
I have tried to create a new AppDomain inside Main() and used
domain.DoCallBack(new CrossAppDomainDelegate(() => { ServiceBase.Run(ServicesToRun); })) to start the service but I can't start it and keep getting "Error 1053: The service did not respond to the start or control request in a timely fashion".
And then I tried to just enable Shadow copy for the current appdomain by setting AppDomain.CurrentDomain.SetupInformation.ShadowCopyFiles = "true"; in MyWCFService.cs just before InitializeComponent(); I can start the service but the dlls are still locked. however, if I use AppDomain.CurrentDomain.SetShadowCopyFiles(); (a deprecated method) to enable the shadow copy, everything works. I'm more confused.
OK, I ended up with creating a shell/proxy class inherited from MarshalByRefObject and start the service from there, and here is the code:
ServiceShell.cs
public class ServiceShell:MarshalByRefObject
{
internal static ServiceHost MyServiceHost = null;
public void Run()
{
if (MyServiceHost != null)
{
MyServiceHost.Close();
}
try
{
MyServiceHost = new ServiceHost(typeof(MyWCFService));
MyServiceHost.Open();
}
catch (Exception)
{
}
}
public void Stop()
{
if (MyServiceHost!= null)
{
MyServiceHost.Close();
MyServiceHost = null;
}
}
}
MyService.cs
public partial class MyService: ServiceBase
{
AppDomain domain;
ServiceShell runner;
public MyService()
{
var setup = new AppDomainSetup
{
ShadowCopyFiles = "true"
};
domain = AppDomain.CreateDomain("MyServiceHostDomain", AppDomain.CurrentDomain.Evidence, setup);
runner = (ServiceShell)domain.CreateInstanceAndUnwrap
(typeof(ServiceShell).Assembly.FullName, typeof(ServiceShell).FullName);
InitializeComponent();
}
protected override void OnStart(string[] args)
{
runner.Run();
}
protected override void OnStop()
{
runner.Stop();
AppDomain.Unload(domain);
}
}

Service on local computer started then stopped error

I have a windows service. It was working fine until I added code for it to begin logging. Now when I try to start the service I receive the following error:
The GBBService service on local computer started then stopped. Some
services stopped automatically if they have no work to do, for
example, the performance logs and alert service
Here is the code for my service:
- From inside project installer
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
string eventSource = "GBBServiceLog";
public ProjectInstaller()
{
InitializeComponent();
EventLogInstaller installer = FindInstaller(this.Installers);
if (installer != null)
{
installer.Source = eventSource;
installer.Log = "My GBBServiceLog";
}
}
private EventLogInstaller FindInstaller(InstallerCollection installers)
{
foreach (Installer installer in installers)
{
if (installer is EventLogInstaller)
{
return (EventLogInstaller)installer;
}
EventLogInstaller eventLogInstaller = FindInstaller(installer.Installers);
if (eventLogInstaller != null)
return eventLogInstaller;
}
return null;
}
protected override void OnCommitted(IDictionary savedState)
{
base.OnCommitted(savedState);
// Start the service after installation
using (ServiceController sc = new ServiceController(this.serviceInstaller1.ServiceName))
{
sc.Start();
}
}
}
From within my service:
public GBBService()
{
InitializeComponent();
EventLog.Source = eventSource;
EventLog.Log = "My GBB Service Log";
}
protected override void OnStart(string[] args)
{
EventLog.WriteEntry("GBBService Service Started");
}
Did I do something wrong in my code?
I think the problem is you are trying to write to a EventLog that does not exist.
In the ServiceInstaller you create the EventLog My GBBServiceLog
if (installer != null)
{
installer.Source = eventSource;
installer.Log = "My GBBServiceLog";
}
But in the Service you try to write to My GBB Service Log
public GBBService()
{
InitializeComponent();
EventLog.Source = eventSource;
EventLog.Log = "My GBB Service Log"; <--------------
}
I think it should be:
public GBBService()
{
InitializeComponent();
EventLog.Source = eventSource;
EventLog.Log = "My GBBServiceLog";
}

Categories

Resources