I have developed a Windows Service whose task is actually to start a host with particular url and port. Below is what I have now.
Program.cs
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new WindowsDxService()
};
ServiceBase.Run(ServicesToRun);
}
ProjectInstaller.cs
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
}
}
WindowsDxService.cs
public partial class WindowsDxService : ServiceBase
{
public WindowsDxService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
var url = "http://127.0.0.1:9000";
using (var host = new NancyHost(new Uri(url)))
{
host.Start();
}
}
}
Configuration on serviceProcessInstaller1 and serviceInstaller1 in ProjectInstaller.cs [Design] file.
serviceProcessInstaller1
Account=LocalSystem
serviceInstaller1
StartType=Automatic
Library.cs
public class Library : NancyModule
{
public Library()
{
Get["/"] = parameters =>
{
return "Hello world";
};
Get["jsontest"] = parameters =>
{
var test = new
{
Name = "Guruprasad Rao",
Twitter="#kshkrao3",
Occupation="Software Developer"
};
return Response.AsJson(test);
};
}
}
Basically I followed this tutorial which actually shows how to do it with Console application which I succeeded though, but I wanted to have this as Windows Service which actually starts a host with specified port whenever the system starts. The service is started successfully and running but whenever I browse the url in the same system its not showing up the page, which means our basic This webpage is not available message. What else configuration I have to do so as to start the host? Hoping for a help.
You are disposing the host when you start your service. I would suggest something like this:
public partial class WindowsDxService : ServiceBase
{
private Host host;
public WindowsDxService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
this.host = new NancyHost(...)
this.host.Start();
}
protected override void OnStop()
{
this.host.Stop();
this.host.Dispose();
}
}
You'd probably find it a lot easier to write the service if you used TopShelf library.
Related
I'm trying to create a base class for a windows service so I can change as little as possible when deploying to different databases. I have this but there is an unhandled exception:
"An unhandled exception of type 'System.StackOverflowException' occurred in >Microsoft.VisualStudio.HostingProcess.Utilities.dll",
I'm new to services so I could totally be off on this, so far this is what I have:
public partial class Service1 : ServiceBase
{
namespace SecureVoiceBase
{
public Service1()
{
try
{
InitializeComponent();
}
catch (Exception e)
{
EventLog.WriteEntry(e.Message);
}
}
protected override void OnStart(string[] args)
{
//code here
}
//OnStop, Timers as well...
}
}
public class Version_10 : ServiceBase// Derived class, This is where I will call
{
//certain methods depending on which database I will use
Version_10 set = new Version_10();
public void Start(string[] args)
{
set.OnStart(args);
}
}
This is my Program.cs:
namespace testservice
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(params string[] args)
{
var service = new Version_10();
if (!Environment.UserInteractive)
{
var servicesToRun = new ServiceBase[] { service };
ServiceBase.Run(servicesToRun);
return;
}
Console.WriteLine("Running as a Console Application");
Console.WriteLine(" 1. Run Service");
Console.WriteLine(" 2. Other Option");
Console.WriteLine(" 3. Exit");
Console.Write("Enter Option: ");
var input = Console.ReadLine();
switch (input)
{
case "1":
service.Start(args);
Console.WriteLine("Running Service - Press Enter To Exit");
Console.ReadLine();
break;
case "2":
// TODO!
break;
}
Console.WriteLine("Closing");
}
// ServiceBase[] ServicesToRun;
// ServicesToRun = new ServiceBase[]
// {
// new Version_10()
// };
// ServiceBase.Run(ServicesToRun);
}
}
As usually I have other methods that I call but I figured it would just be a waste of space. Am I totally off on base classes?
You problem lies here:
public class Version_10 : ServiceBase
{
Version_10 set = new Version_10(); // <-- Recursive call on object construct
It has nothing to do with services or anything. Your code has a recursive call with trigger the StackOverflow exception.
UPDATE:
To solve your problem, change your Version_10 class to:
public class Version_10 : ServiceBase
{
public void Start(string[] args)
{
this.OnStart(args);
}
}
This part is recursive that's why you are getting a System.StackOverflowException.
public class Version_10 : ServiceBase
{
**Version_10 set = new Version_10();**
public void Start(string[] args)
{
set.OnStart(args);
}
}
Maybe you should check some articles:
A basic Windows service in C#
You are getting a Stack Overflow exception because of this:
public class Version_10 : ServiceBase
{
Version_10 set = new Version_10();
}
When you create an instance of Version_10 it creates an instance of Version_10 which creates an instance of Version_10 which creates an instance of Version_10 which creates an instance of Version_10 which creates an instance of Version_10 etc....
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);
}
}
I have a project that wants me to communicate with a server. I need to send data processed from a standalone application on client side to the server. For this I am using a wcf service that interacts with the server. This service is hosted in a windows service. Now my problem begins. I need to monitor a folder, write/read some files and delete them. For this I am using the same windows service as the one hosting the wcf service. How can I pass data between the two services? For example I would like to read a file using the windows service and pass the data to wcf service which then passes it to the server and back.
If you just want to be able to communicate between two services hosted in a windows service, one solution I have used is to store a static session state in the windows service itself. In Program.cs, I declare a static field which stores the session state, and I modify the constructors of my two services to take a reference to this object:
static class Program
{
private static SessionState sessionState = new SessionState() { SessionID = "100" };
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] servicesToRun;
servicesToRun = new ServiceBase[]
{
new Service1(sessionState),
new Service2(sessionState)
};
ServiceBase.Run(servicesToRun);
}
}
I have a class called SessionState which I use to store any data which I want to transfer between my hosted services. In this instance I am just giving the session an ID property:
public class SessionState
{
public string SessionID { get; set; }
}
Service1 and Service2 store a reference to the static session state, and in my example I just modify the sessionID in one of the two threads:
public partial class Service1 : ServiceBase
{
private SessionState sessionState;
public Service1(SessionState sessionState)
{
this.sessionState = sessionState;
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Console.WriteLine("Service 1 started.");
Task tsk = new Task(() => this.DoStuff());
tsk.Start();
}
protected override void OnStop()
{
}
private void DoStuff()
{
Console.WriteLine("Session state for service 1 is " + this.sessionState.SessionID);
Thread.Sleep(2000);
Console.WriteLine("Session state for service 1 is " + this.sessionState.SessionID);
}
}
public partial class Service2 : ServiceBase
{
private SessionState sessionState;
public Service2(SessionState sessionState)
{
this.sessionState = sessionState;
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Console.WriteLine("Service 2 started.");
Task tsk = new Task(() => this.DoStuff());
tsk.Start();
}
protected override void OnStop()
{
}
private void DoStuff()
{
Console.WriteLine("Session state for service 2 is " + this.sessionState.SessionID);
Thread.Sleep(1000);
this.sessionState.SessionID = "200";
Console.WriteLine("Session state for service 2 is " + this.sessionState.SessionID);
}
}
Now when I run the Windows Service (with a Console window attached) I get the following:
Hope this helps!
Alex
I've googled this one
but when i'm trying to apply it i get an error. So install/uninstall works fine, but service itself just doesn't start and after timeout it says that service doesn't respond. I don't know why. When i'm attaching to process it even doesn't enter into Main() method, static constructors and so on. I've used this addon for attach.
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += OnException;
if (Environment.UserInteractive)
{
AskUserForInstall();
}
else
{
ServiceBase.Run(new NotificatorService());
}
}
Service is also very simple:
using System.ServiceProcess;
using System.Windows;
namespace AZNotificator
{
public partial class NotificatorService : ServiceBase
{
static NotificatorService()
{
int x = 5;
}
public NotificatorService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
MessageBox.Show("Hello");
}
protected override void OnStop()
{
}
}
}
You can not call MessageBox.Show("Hello"); from the windows service since the service does not have the GUI.
If you want to do some interaction from the windows service have a look at this article
http://msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx
So remove MessageBox.Show("Hello"); from your OnStart method and your service should start just fine.
Application c:\pinkPanther.exe is running and it is application i wrote in c#.
Some other application starts c:\pinkPanther.exe purpleAligator greenGazelle OrangeOrangutan and i would like not to start new instance of c:\pinkPanther.exe with these arguments, but to currently running c:\pinkPanther.exe register it and react to it somehow.
How to do it?
EDIT!!!: i'm very sorry about pinkPanther.exe and ruzovyJeliman.exe that caused the confusion - i translated question from my native language and missed it :(
This is assuming your application is a WinForms app, as that will make it easier to keep it open. This is a very simple example, but it will show you the basics:
Add a reference to Microsoft.VisualBasic.
Create an Application class inheriting from WindowsFormsApplicationBase. This base class contains built-in mechanisms for creating a single-instance application and responding to repeated calls on the commandline with new arguments:
using Microsoft.VisualBasic.ApplicationServices;
//omitted namespace
public class MyApp : WindowsFormsApplicationBase {
private static MyApp _myapp;
public static void Run( Form startupform ) {
_myapp = new MyApp( startupform );
_myapp.StartupNextInstance += new Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventHandler( _myapp_StartupNextInstance );
_myapp.Run( Environment.GetCommandLineArgs() );
}
static void _myapp_StartupNextInstance( object sender, Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e ) {
//e.CommandLine contains the new commandline arguments
// this is where you do what you want with the new commandline arguments
// if you want it the window to come to the front:
e.BringToForeground = true;
}
private MyApp( Form mainform ) {
this.IsSingleInstance = true;
this.MainForm = mainform;
}
}
All you have to change in Main() is call Run() on your new class rather than Application.Run():
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
MyApp.Run( new MyMainForm() );
}
}
WindowsFormsApplicationBase has some other capabilities you can explore, as well.
To communicate with the other instance of the application, you need some sort of inter-process communication. Apparently, WCF is the recommended form of IPC in .Net. You can do that with code like this (using WPF, but WinForms would be similar):
[ServiceContract]
public interface ISingletonProgram
{
[OperationContract]
void CallWithArguments(string[] args);
}
class SingletonProgram : ISingletonProgram
{
public void CallWithArguments(string[] args)
{
// handle the arguments somehow
}
}
public partial class App : Application
{
private readonly Mutex m_mutex;
private ServiceHost m_serviceHost;
private static string EndpointUri =
"net.pipe://localhost/RuzovyJeliman/singletonProgram";
public App()
{
// find out whether other instance exists
bool createdNew;
m_mutex = new Mutex(true, "RůžovýJeliman", out createdNew);
if (!createdNew)
{
// other instance exists, call it and exit
CallService();
Shutdown();
return;
}
// other instance does not exist
// start the service to accept calls and show UI
StartService();
// show the main window here
// you can also process this instance's command line arguments
}
private static void CallService()
{
var factory = new ChannelFactory<ISingletonProgram>(
new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), EndpointUri);
var singletonProgram = factory.CreateChannel();
singletonProgram.CallWithArguments(Environment.GetCommandLineArgs());
}
private void StartService()
{
m_serviceHost = new ServiceHost(typeof(SingletonProgram));
m_serviceHost.AddServiceEndpoint(
typeof(ISingletonProgram),
new NetNamedPipeBinding(NetNamedPipeSecurityMode.None),
EndpointUri);
m_serviceHost.Open();
}
protected override void OnExit(ExitEventArgs e)
{
if (m_serviceHost != null)
m_serviceHost.Close();
m_mutex.Dispose();
base.OnExit(e);
}
}