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.
Related
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()
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?
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
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.
I am writing a C# console application that connects to a server trough TCP, it uses a separate thread to listen for incoming messages from the server and I want it to write them to the console while at the same time reading a message from the console. I was able to do that, but I have a problem.
The console displays this while I type and a messages comes in:
msg from server
msg from server
my msmsg from server
g to server
And i want it to separate my message from the servers mesages like so:
msg from server
msg from server
msg from server
my msg to server
If I receive a message I still want to keep my typed message, but I don't want it to mix up with the received message, I want it to remain complete on the last line.
Can I do that? And how?
Can I shift my message to the end of the console, when a message from the server comes in?
I believe this is in fact possible with the standard .NET Console API, using a bit of hackery. What you need to do is create an asynchronous Read/ReadLine method (which I assume you have already done, judging by your post) and allow it to be cancelled as soon as new data arrives. I'm going to assume you're sending input line by line for now. The pseudocode for the "new data handler" might be something like this:
Save the current input buffer.
Cancel the current asynchronous read.
Reset the cursor position to the end of the last writing of new data.
Output the new data.
Save the cursor position.
Restart the asynchronous read event.
In particular, you'll need to mess around with Console.CursorLeft and Console.CursorTop properties. You might be able to avoid some of the hackery by interfacing with the Win32 API console functions directly, but it's possibly not worth the bother.
Hope that helps.
You can't do this directly via the BCL in C#. There are two main alternatives, though.
1) Turn this into a GUI app, and have separate input/output areas. This is the most "clear" option from a user's POV, but requires a GUI app instead of a console app.
2) P/Invoke into the console API directly. This gives you complete control of the console's view, point by point. See SetConsoleCursorPosition and WriteConsole, etc.
You need to use a lock on some object to stop both threads using the console at the same time. Declare something like this:
public static class ThreadSafeConsole
{
private static object _lockObject = new object();
public static void WriteLine(string str)
{
lock (_lockObject)
{
Console.WriteLine(str);
}
}
}
Now call ThreadSafeConsole.WriteLine instead of Console.WriteLine.
If I understand you correctly, you'd have to define what the beginning and ending of 'typing to console' is for your application so that you can still lock on an object while that is happening, and not inserting messages from your listener thread into your typed text.
public static Object consoleLock = new Object();
public static void Main(string[] args)
{
lock (consoleLock)
{
// now nothing can write to the console (if it's trying to lock onto it)
Console.WriteLine("Please Input Something");
// read from console
}
// now, your separate thread CAN write to the console - without
// interrupting your input process
}