Creating new AppDomain instances inside a Windows service doesn't work - c#

I am trying to create a Windows service with C# which spawns multiple processes inside it.
For this I am using AppDomain functionality and creating multiple of them at startup in the OnStart method of my service:
public partial class MyService : ServiceBase
{
public ServiceBase()
{
InitializeComponents();
}
protected override void OnStart(string[] args)
{
var setup = new AppDomainSetup();
setup.ApplicationBase = Path.GetDirectoryName(GetMyExePath());
var ad = AppDomain.CreateDomain("Domain NEW", null, setup);
var t = new Thread(() => {
ad.ExecuteAssembly(GetMyExePath());
AppDomain.Unload(ad);
});
t.Start();
}
}
(I know I should put a check to prevent recursively starting new domains from each new one, but for now it doesn't even start the first one)
When I try the same in a Console Application, it works fine.
But when I build it as a Windows Service and run it from the service manager, it seems to terminate after startup.
Opening the Event Viewer, I see this about my service:
"Service can not be started. An instance of the service is already running."
Running it without the app domain creation code works just fine. It fails to start even a single domain as it seems to view them as trying to start the same process twice instead making a new domain within the process.
Is there a way to get this to run on services or does it only work for regular applications?

Related

How to run c# windows service application run under services rather than background processes?

I have a windows service application which i build with c# in visual studio. Basically the application is fetching data from a API service and saving into an another software installed on my machine using SDK. The application is working fine but it runs under the background processes of the windows. But i want it to run in the services
Here is my program.cs main() code
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Service1 myService = new Service1();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
}
What i can change here to run it under the windows services?
You need to register your .exe in your services.
you can do it running this line in your powershell:
New-Service -Name "YourServiceName" -BinaryPathName <yourproject>.exe
For more details:
https://learn.microsoft.com/en-us/dotnet/framework/windows-services/how-to-install-and-uninstall-services
Short answer: recreate your project using the "Windows service" template as described here:
https://learn.microsoft.com/en-us/dotnet/framework/windows-services/walkthrough-creating-a-windows-service-application-in-the-component-designer
then install it using installutil or using the integrated installer
Longer answer:
A service is a "Console application" with specific entry points, so this is the very basic code to create the service:
using System.ServiceProcess;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
public Service1()
{
this.ServiceName = "Service1";
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
}
as you can see, the main class inherits and implements the "ServiceBase" class and override a few methods. The main methods are "OnStart" (called when you start a service) and "OnStop", called when you stop it.
There are a lot of other properties and methods, described here (or pressing F12 in visual studio on the class name):
https://learn.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicebase
Taking a look at the "main", you can see how it works:
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
a few things you have to remember:
a service is executed in c:\windows\system32 as base path. Do not use relative paths.
OnStart has to be quick. Do not perform long operations in that method. Best course of action is perform all start checks and Launch a thread.
change the main in this way to allow debugging (obviously TestMode should be the code to test):
bool isInteractive = Environment.UserInteractive || args.Contains("--interactive");
if (isInteractive)
((Service1)ServicesToRun[0]).TestMode();
else
ServiceBase.Run(ServicesToRun);
Once built you .exe file, use installutil to install it as a service
Install a Windows service using a Windows command prompt?

Windows service programmed in C# can be installed and started, but doesn't "do" what it should?

So basically I'm trying to program a Windows Service in C# under Visual Studio 2017. As the service didn't do what i wanted to do i made a test service with a very rudimentary logic to test if it even does what i want in the OnStart() Method. The reason why i chose to manually write a string into the event log is because i want to make sure that there is no writing permission issue. I mean if the service is installed and started, it should write the line into the log shouldn't it?
So:
namespace WindowsService3
{
public class Program : System.ServiceProcess.ServiceBase
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
protected override void OnStart(string[] args)
{
this.EventLog.WriteEntry("Hello");
}
protected override void OnStop()
{
}
}
}
I added a ProjectInstaller, added the service name to it as well as specifying it for LocalSystem. Then i used the following line to install it:
C:\Windows\system32>sc \\10.10.0.122 create TESTService binPath= "C:\temp\service\WindowsService1.exe"
The service can now be seen in the service manager and even started. Without problems... In the eventlog though i don't see the specified line. So it seems the service is correctly started, but it doesn't user the logic in the OnStart() method. I have no idea why. I also tried things like creating a text file via the OnStart() method at first... Also no success. What am i doing wrong? Again, the service IS installed and IS started as the Event log and the service manager suggest.
Edit: My problem is that no code is executed in OnStart at all. I can't write a file, i can't write a log, nothing. The service is just installed and can be started, but i doesn't do anything that is put into OnStart() and i don't know why. My coworkers can't figure it out either.
Edit2: The VS2017 template tells me to make the Program class static. But then I can't use OnStart() in it. But maybe this is my missunderstanding? In my example i made the Program class just public to implement OnStart() but maybe that was the mistake?
You have written your service code in the class Program, but your service that is started is named Service1, probably defined by the template in another file.
Either edit Service1.cs to include your startup code, or edit your Program.cs to start your class:
ServicesToRun = new ServiceBase[]
{
new Program() // <----
};
Putting your service and Program.cs in the same class is uncommon, it's indeed a good approach to keep them separate and have a separate Service class.
Try logging this way and then check in event logger under Application errors:
using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = "Application";
eventLog.WriteEntry("Message", EventLogEntryType.Error);
}

C# WCF service implemented in a DLL

I have a WCF service written in C# what works fine. It's the usual self-hosted type in a Win32 console application. But now, for reasons of special updating (it's not a simple desktop computer where you simply update a program using the usual installers but a special embedded system) I'd like to move the actual type implementing the service to a DLL which is loaded by a very simple loader executable using reflection:
string DllFilename = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "myservice.dll");
var ServicesDll = Assembly.LoadFrom(DllFilename);
var ServicesType = ServicesDll.GetType("MyNamespace.MyServices");
var Instance = (ServiceBase)Activator.CreateInstance(ServicesType);
ServiceBase.Run(new ServiceBase[] { Instance });
I can deploy the service all three ways, either installing it normally via MSI, or using sc.exe, or even with a self-managing code like this:
ServicesType.GetMethod("InstallService").Invoke(null, null);
ServicesType.GetMethod("StartService").Invoke(null, null);
where
public class MyServices : ServiceBase {
//...
public static void InstallService() {
if (!IsInstalled())
using (AssemblyInstaller installer = GetInstaller()) {
var state = new Hashtable();
try {
installer.Install(state);
installer.Commit(state);
}
catch {
installer.Rollback(state);
throw;
}
}
}
public static void StartService() {
if (IsInstalled())
using (var controller = new ServiceController("MyService")) {
if (controller.Status != ServiceControllerStatus.Running) {
controller.Start(); // fails here
controller.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(10));
}
}
}
//...
}
As I mentioned in the beginning, everything works just fine in an EXE. But as soon as the MyService type is in the DLL, InstallService is still OK but StartService fails with System.ComponentModel.Win32Exception: %1 is not a valid Win32 application. It seems that Windows expects the service executable (which it stores itself not as the EXE I actually installed but as the DLL the service was implemented in) to be an executable to be called at its leisure.
How can I circumvent this limitation, maybe to signal somehow that it's my loader EXE that I want to be called, not the dependent DLL?
Split your MyServices into two classes - one a thin wrapper inherited from ServiceBase (to live in .EXE) and another doing real work including self-hosting to live in updatable .DLL. The first one can take an instance of the second as a .ctor argument and delegate start/stop calls to it.
You may also want to look at Topshelf.
I finally went with Rene's suggestion, the bulk of the service stays in an EXE and loaded as an assembly into the loader. Fortunately, loading an assembly can be done both from EXE and DLL.

C# Windows Service

Scenario
I've created a windows service, but whenever I start it, it stops immediately. The service was concieved from a console application that used to subscribe to an event and watch processes on a server. If anything happened to process (i.e. It was killed), then the event would trigger the process to be restarted. The reason I'm telling you this is because the original code used to look like this:
Original Console App Code:
static void Main(string[] args)
{
StartProcess sp = new StartProcess();
//Note the readline that means the application sits here waiting for an event!
Console.ReadLine();
}
Now that this code has been turned into a Windows Service, it is essentially EXACTLY THE SAME. However, the service does not sit there waiting, even with the readline, it just ends.....
New Windows Service Code:
protected override void OnStart(string[] args)
{
ProcessMonitor pm = new ProcessMonitor();
Console.ReadLine();
}
Thoughts
Since the functionality is entirely encapsulated within this single class (It quite literally starts, sets up some events and waits) - How can I get the service to actually sit there and just wait? It seems to be ignoring the readline. However this works perfectly as a console application, it is just far more convenient to have it as a service.
Typically you would want something like this. As Joe mentioned in the comments you want Start to initialize and release control to another thread to make sure that you return within 30 seconds.
private readonly ProcessMonitor processMonitor = new ProcessMonitor();
protected override void OnStart(string[] args)
{
processMonitor.Start();
}
protected override void OnStop()
{
processMonitor.Stop();
}
In a Service there is no concept of a readline - there's no keyboard. I wouldn't be surprised if this is throwing an exception at that call. Have you checked your Application Log?
Well... A service doesn't have a console input/output. So the ReadLine won't stop it from executing.
What does ProcessMonitor do?
Typically, for services your code lives in a thread that monitors whether the service has been stopped or paused.
OnStart() must complete and end successfully for the service to be considered "Started"
Move your Console.ReadLine(); into your ProcessMonitor() constructor, and create your ProcessMonitor inside the constructor for the service. Your OnStart method can be empty. Despite what people are saying the Console methods will NOT crash your service, however it is probably not best practice. I guess the proper way to keep a service running (after your timers are started) is to use a while loop with a Thread.Sleep(60000) inside it.
When I am writing a service I put all the functionality in a Class Library project, then I create a Console Application project to test the service functionality, and then a Windows Service project. Both the Console Application and Windows Service project call one method in the Class Library to start the service functionality. If you use this technique you can call Console.WriteLine in the Class Library which can be viewed when running the Console Application. PS Topshelf is overrated, writing a windows service is not that difficult.
public partial class ProcessMonitor_Service : ServiceBase
{
public ProcessMonitor_Service()
{
InitializeComponent();
ProcessMonitor pm = new ProcessMonitor();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
public class ProcessMonitor
{
public ProcessMonitor()
{
// start timers
Console.ReadLine();
}
}

How to start a WPF application from a web service?

a web service is running with IIS.
When calling the initialize service, some libraries are dynamically loaded in order to start a wpf application.
The code compiles, runs... but the window never shows up. No exception is thrown whatsoever.
Below is the code that is executed to create the WPF application:
public void Start()
{
ThreadStart ts = Run;
Thread t = new Thread(ts);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
[STAThread]
public void Run()
{
try
{
App app = new App();
MainWindow w = new MainWindow();
w.Show();
app.Run(w);
} catch (Exception e)
{
LogManager.GetLogger("general").Debug(e.StackTrace);
}
}
If I run that in a console application, it works perfectly:
static void Main(string[] args)
{
MyApplication app = new MyApplication();
app.Start();
Console.ReadKey();
}
But if I run it from the web service, code is correctly executed (as I can debug it, and no exceptions) but the window never shows up:
public void initialize() {
IMyApplication application = assembly.CreateInstance(namespaceValue + ".MyApplication") as IMyApplication;
application.Start();
}
I can see in the process manager that the WPF process is running... Any idea why the window does not show up ?
Regards,
Francois
Is there something special to do to grant all access/rigths to the web service ?
Check your application pool and tell me what user it uses - or if you use impersonation.
My first guess would be that this runs as a service user (with no rights to mess with a desktop and especially not with your desktop). In general I think this is a strange thing to do..
Why don't you use a Silverlight out of browser application? Why no ClickOnce?

Categories

Resources