Geniune channel server in a windows service? - c#

I am developping a server with geniune channel in a windows service , it seems that it's not as simple as the console application. When the thread that creates the server finishes his job , all variables that were declared in the thread scope are destroyed so the client cannot connect to that server anymore. With Console application we can avoid that with console.readline() but it's not the same case for windows service. So the first block of code is for windows service thread that creates the server and the second one is for the console application.
public void startServer()
{
System.Configuration.ConfigurationSettings.GetConfig("DNS");
GenuineGlobalEventProvider.GenuineChannelsGlobalEvent += new GenuineChannelsGlobalEventHandler(GenuineChannelsEventHandler);
var Path = AppDomain.CurrentDomain.BaseDirectory;
RemotingConfiguration.Configure(Path + "Server.exe.config");
RemotingServices.Marshal(new Agent(), "Server.rem");
}
static void Main(string[] args)
{
System.Configuration.ConfigurationSettings.GetConfig("DNS");
GenuineGlobalEventProvider.GenuineChannelsGlobalEvent += new GenuineChannelsGlobalEventHandler(GenuineChannelsEventHandler);
var Path = AppDomain.CurrentDomain.BaseDirectory;
RemotingConfiguration.Configure(Path + "Server.exe.config");
RemotingServices.Marshal(new Agent(), "Server.rem");
Console.ReadLine();
}
Have I missed somthing ? How can i achieve the availability of the server ?

Try to store the Agent in your service class when Start is called and dispose of it in the service shutdown when Stop is called.
On a side note, if that's the problem, there's no good reason your console app works either. C# isn't C++, there are no destructors that are called when you leave scope. Also, why remoting instead of something more supported?

Related

Is there a way to execute my wpf application using msmq trigger?

My Executable file (C# WPF Solution) is not running properly when being called by MSMQ Trigger.
I am sending a notification mesasge to the queue (named sometestname):
I have a class called MyNotification that includes this static method:
public class MyNotification {
public static void SendNotification(String destination,String msg){
string s = #".\Private$\sometestname" + "-" + destination;
if(!MessageQueue.Exists(s))
MessageQueue.Create(s,false);
MessageQueue q = new MessageQueue(s);
Message msg = new Message();
msg.Body = msg;
q.Send(message);}
}
a WPF Solution that uses this class:
void ButtonBase_OnClick(object sender,RoutedEventArgs s){ MyNotification.SendNotification("user1","testing message");}
the .exe that will be fired from trigger (when the message is received) :
Public MainWindow(){
String queueName = #".\Private\sometestname-user1";
MessageQueue msgq = new MessageQueue(queueName,false);
try{
msgq.Purge();
}
catch(MessageQueueException e){
string filename = #"C:\Users\user1\Desktop\error.txt";
File.Create(filename);
}
}
Note that:the message is arriving to the queue,and the executable file is showed running in the background,but it catches an error.
When the executable file is executed manually,it executes nromally without any errors(i.e. no file is created).
But When its fired from the MSMQ Trigger(Includes a rule the invoke standalone executable when message arrives),it catches an exception(i.e. file is created).
I think you could create a windows service that runs your exe.
Instead of having a MSMQ trigger, the service would listen to msmq for a message to appear.
A windows service still can't just run a desktop app. At least not in a straight forward way.
It can use the approach explained here:
https://www.codeproject.com/Articles/35773/Subverting-Vista-UAC-in-Both-and-bit-Archite
There's a comment in this thread from someone says they got the approach to work on Win10.
How can I run an EXE program from a Windows Service using C#?
Having said that.
You will need to write, install and run that windows service.
Maybe a simpler approach would be to start up your wpf app minimised and with it's taskbar icon hidden when the user logs on. That then listens for the msmq message. When it receives one it shows a window.

C# Running console application as windows service - The service didn't respond error

I'm trying to run some console app as windows service, I followed this question, and I made a few changes to make it fit to my app.
My main code looks like that:
public static class Program
{
public class Service : ServiceBase
{
public Service(string serviceName)
{
this.ServiceName = serviceName;
}
protected override void OnStart(string[] args)
{
Program.Start(args);
}
protected override void OnStop()
{
Program.Stop(this.ServiceName);
}
}
#endregion
static void Main(string[] args)
{
if (!Environment.UserInteractive)
// running as service
using (var service = new Service("TestService"))
ServiceBase.Run(service);
else
{
// running as console app
Start(args);
}
}
private static void Start(string[] args)
{
while(true)
{
//DO SOMTHING
}
}
private static void Stop(string serviceName)
{
//Writing to log that 'serviceName' stopped
}
}
I tried to run the following console app as a service, by using the following steps:
1) Use the command: sc create ServiceTestName123 binPath= "PATH TO THE EXE FILE IN THE PROJECT DEBUG FOLDER".
2) Use the command: sc start ServiceTestName123 "parameter1".
And I got an error:
"StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion"
I read about the error in the internet and found out that I can try to solve this problem by running the start function with another thread, so I updated the OnStart function to the following function:
protected override void OnStart(string[] args)
{
Thread t = new Thread(() => Program.Start(args));
t.Start();
}
After trying to re-create the service (delete the old one and create the service again with the new OnStart function) and re-run it I got the same error.
By the way, when I ran this code as console app it worked properly.
Could someone please explaing me what am I doing wrong?
Thanks a lot.
I tried your exact steps and it worked for me. I will highlight a few key points that I came across
OnStart should definitely return in a timely fashion. i.e. the work should happen in a separate process/thread. I used your code for thread and it worked fine for me.
Make sure the executable is on a local drive which can be accessed from your "Local System" account without any permission issues.
Make sure when you create the service, you provide the absolute path and not relative path.
Make sure the sc create ... command responds back with [SC] CreateService SUCCESS
Check the service was created in the service control panel
Make sure you can start it from the service control panel before attempting it from command line
Also, open task manager or process explorer to make sure the service executable is running or not (irrespective of what status is returned by service control panel or scm start)
For debugging, I logged the information into a local temp file - again watch out for permissions issues with Local System account.
If for whatever reasons you have to delete the service, make sure that it indeed disappeared from the service control panel
To debug what's going on, you can attach the debugger at the very beggining of your program start up.
This way, you can check what your program is doing.
You can also check in the Windows ever viewer, the error that windows is throwing.
Put this line at the start trace of your program:
System.Diagnostics.Debugger.Launch()

C# Topshelf TimeoutException

As a First step I created Windows Service project configured it properly and
On second Step I have added TopShelf Version 3.1.135.0 in my project If I run my service through (F5 Run) then it is loading Top-shelf Console and service is completed successfully.
However When I am running it to install and Start it from command prompt I am having below TimeOut Error.
Topshelf.Hosts.StartHost Error: 0 : The service failed to start., System.Service
Process.TimeoutException: Time out has expired and the operation has not been co
mpleted.
public class AppService
{
LoggingService loggingService = new LoggingService(typeof(AppService).Name);
public void Start()
{
loggingService.Info("SampleService is Started");
ExtractProcess.Start();
TransformProcess.Start();
}
public void Stop()
{
loggingService.Info("SampleService is Stopped");
}
}
-- Updated Code to fix this issue
public void Start()
{
loggingService.Info("MPS.GOA.ETLService is Started");
ThreadStart myThreadDelegate = new ThreadStart(StartService);
Thread myThread = new Thread(myThreadDelegate);
myThread.Start();
}
private void StartService()
{
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnElapsedTime);
timer.Interval = 60000 * ServiceIntervalInMinutes; //1 minute 60000 milliseconds
timer.Enabled = true;
Process();
}
private void Process()
{
ExtractProcess.Start();
TransformProcess.Start();
}
Any Suggestions?
This error is happening because you are running the extract and process methods in the Start method of the service. This is OK in Visual Studio, but when you install the service and start it, the Service Control Manager waits for the Start method to return, and if it does not do so within a certain time (30 seconds by default) then it will return this error.
You have several options, all of which will allow the Start method to return immediately:
Invoke the extract and transform methods on a separate thread
Invoke the extract and transform methods asynchronously
Use a timer to start the extract and transform process
In case you (like me) is struggling to get the service to start - and all you've found so far is references to starting work in a separate thread (and you already did) this might be the solution right here..
My problem was that I had an external JSON config file being read from the project's directory path. What I needed was to get the assembly path, so that when the .NET application is published and installed with Topshelf - it looks for the config file at the right place.
string assemblyPath = Path.GetDirectoryName(typeof(MyConfigManagerClass).Assembly.Location);
var builder = new ConfigurationBuilder()
.SetBasePath(assemblyPath)
.AddJsonFile("config.json", optional: false);
myConfigurationObject = builder.Build();
Topshelf gave an error saying the service couldn't be started, but now I finally know why.
In my case it was neither of the above solutions that solved it, but actual permissions within the topshelf service, that required access to a file that resided in an external server.
TopShelf program running on test server
Log file located on Production server
Test server does not have access to external servers, for security
reasons.
So I changed the program to refer everything internally inside it's own server, and it worked fine.

c# windows service with filewatcher

First time posting long time reader.
I built a working filewatcher inside of a windows forms application functioning 100% properly before moving it to a windows Service and am now recieving two seperate issues. This file watcher reads a flatfile for line updates(lastwrite), deletes/recreates file(streamwriter), and finally parses through a strongly typed data set and then uploads to an SQL server.
(This is my first Windows Service)
Questions:
1. Does the double event trigger in filewatcher effect the service differently then a forms application?
2. Does anyone have an answer about why the thread will break if the class I am calling has no issue?
3. Are there any known issues with Windows Authentication through a windows service?
4. Does anyone have any strong debug methods for windows services?
Here is my code from the windows Service, thanks in advance and my apologies if there is a silly mistake in the code, again first time making a windows service.
FileMonitor m_FileMonitor;
public WindowsService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
Thread myThread = new Thread(DoTheWork);
myThread.Start();
}
catch
{
}
}
void DoTheWork()
{
m_FileMonitor = new FileMonitor(Properties.Settings.Default.PathToFileToWatch, Properties.Settings.Default.PathToErrorLog);
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
}
For debugging, make sure your project type is Windows Application, and then use this:
[DllImport("kernel32")]
static extern bool AllocConsole();
private static void Main(string[] args)
{
var service = new MyService();
var controller = ServiceController.GetServices().FirstOrDefault(c => c.ServiceName == service.ServiceName);
if (null != controller && controller.Status == ServiceControllerStatus.StartPending)
{
ServiceBase.Run(service);
}
else
{
if (AllocConsole())
{
service.OnStart(args);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
service.OnStop();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
If the code is running because the Windows Service was started, it will run as a Windows Service. Otherwise it will allocate a console, run the service, then wait for a key press before exiting the service. You could build on this for testing pause and continue.
For debugging:
You have to use the ServiceBase.Run method in Main() to execute as a windows service, but you can make a switch in the main method to run the same application as a normal console application (e.g. --standalone). I'm using this on all my services to make them easy to debug.
Regarding the other problems:
I'm not completely sure which problems you encounter and what you mean by "class break" and "double event trigger".
Windows services run under a special service account, which might or might not have permissions to watch the directory you are interested in. You can change the service account or give it permission for the directory if you need to.
Links:
Here is a link to a codeproject article who seems to have implemented a file watcher windows service. Maybe it helps:
http://www.codeproject.com/Articles/18521/How-to-implement-a-simple-filewatcher-Windows-serv

How to determine that a WCF Service is ready?

I have the following scenario:
My main Application (APP1) starts a Process (SERVER1). SERVER1 hosts a WCF service via named pipe. I want to connect to this service (from APP1), but sometimes it is not yet ready.
I create the ChannelFactory, open it and let it generate a client. If I now call a method on the generated Client I receive an excpetion whitch tells me that the Enpoint was not found:
var factory = new ChannelFactory<T>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe//localhost/myservice");
factory.Open()
var Client = factory.CreateChannel();
Client.Foo();
If I wait a little bit before calling the service, everything is fine;
var Client = factory.CreateChannel();
Thread.Sleep(2000);
Client.Foo();
How can I ensure, that the Service is ready without having to wait a random amount of time?
If the general case is that you are just waiting for this other service to start up, then you may as well use the approach of having a "Ping" method on your interface that does nothing, and retrying until this starts responding.
We do a similar thing: we try and call a ping method in a loop at startup (1 second between retries), recording in our logs (but ultimately ignoring) any TargetInvocationException that occur trying to reach our service. Once we get the first proper response, we proceed onwards.
Naturally this only covers the startup warmup case - the service could go down after a successfull ping, or it we could get a TargetInvocationException for a reason other than "the service is not ready".
You could have the service signal an event [Edited-see note] once the service host is fully open and the Opened event of the channel listener has fired. The Application would wait on the event before using its proxy.
Note: Using a named event is easy because the .NET type EventWaitHandle gives you everything you need. Using an anonymous event is preferable but a bit more work, since the .NET event wrapper types don't give you an inheritable event handle. But it's still possible if you P/Invoke the Windows DuplicateHandle API yourself to get an inheritable handle, then pass the duplicated handle's value to the child process in its command line arguments.
If you're using .Net 4.0 you could use WS-Discovery to make the service announce its presence via Broadcast IP.
The service could also send a message to a queue (MSMQ binding) with a short lifespan, say a few seconds, which your client can monitor.
Have the service create a signal file, then use a FileSystemWatcher in the client to detect when it gets created.
Just while (!alive) try { alive = client.IsAlive(); } catch { ...reconnect here... } (in your service contract, you just have IsAlive() return true)
I have had the same issue and when using net.pipe*://localhost/serviceName*, I solved it by looking at the process of the self-hosted application.
the way i did that was with a utility class, here is the code.
public static class ServiceLocator
{
public static bool IsWcfStarted()
{
Process[] ProcessList = Process.GetProcesses();
return ProcessList.Any(a => a.ProcessName.StartsWith("MyApplication.Service.Host", StringComparison.Ordinal));
}
public static void StartWcfHost()
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var Process2 = new Process();
var Start2 = new ProcessStartInfo();
Start2.FileName = Path.Combine(path, "Service", "MyApplication.Service.Host.exe");
Process2.StartInfo = Start2;
Process2.Start();
}
}
now, my application isn't called MyApplication but you get my point...
now in my client Apps that use the host i have this call:
if (!ServiceLocator.IsWcfStarted())
{
WriteEventlog("First instance of WCF Client... starting WCF host.")
ServiceLocator.StartWcfHost();
int timeout=0;
while (!ServiceLocator.IsWcfStarted())
{
timeout++;
if(timeout> MAX_RETRY)
{
//show message that probably wcf host is not available, end the client
....
}
}
}
This solved 2 issues,
1. The code errors I had wend away because of the race condition, and 2
2. I know in a controlled manner if the Host crashed due to some issue or misconfiguration.
Hope it helps.
Walter
I attached an event handler to client.InnerChannel.faulted, then reduced the reliableSession to 20 seconds. Within the event handler I removed the existing handler then ran an async method to attempt to connect again and attached the event handler again. Seems to work.

Categories