I have a Windows Service that I am writing in .NET C#. The service is going to act as a file processor. It just watches a directory for File Created events and adds these files to a queue for processing. A separate thread pulls files from the queue and processes them.
My question is whether there is a way to query the windows service to get its "state". I would like to be able to query the service some way and see a list of the files currently waiting in the queue etc.
I know this can be done in Linux via the /proc file system and I was wondering if there is anything similar for Windows. Any tips/pointers would be greatly appreciated.
If you are looking for a non-UI method (eg to write the names to a file or to standard output), it is possible to use the ExecuteCommand Method on the service.
ServiceController sc = new ServiceController("ServiceName");
sc.ExecuteCommand(255);
This simply passes this command to your your service and your service will handle it via the OnCustomCommand
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
if (command == 255
{
... // Your code here
}
}
You may need to store your queue/service status in a static variable so you can access it from the OnCustomCommand routine.
You could create a hosted WCF service inside of the windows service with whatever methods you need to access the state.
http://msdn.microsoft.com/en-us/library/ms733069.aspx
WCF would be good to do that, especially it can be hosted inside of Windows Service. Might be in your case it makes sense to use XML-RPC with WCF
Related
Here is my scenario, I have a windows service that runs a task every 20 minutes, the task is: requesting updates from an API hosted by a remote website.
The response is a list of JSON objects, When the Service receives the list, it carries out a set of operations then appends more JSON objects, finally the service must push the list to a running console application.
My very specific question is: how to transfer this data from the windows service to the console App both directly and professionally
By directly I mean without intermediate solution like writing in a temp file or saving in SQL table ... etc.
By professionally I mean the best optimal solution especially without p/Invoke from the service to the console App.
You would definitely need a medium to communicate between these two processes. The communication can be done in a lot of ways on the same system.
With your explanation in Question it looks like one way communication. May be you can go for Inter-process communication via sockets(raw level) or Use a messaging framework for communication(WCF/SignalR) or you can even use a Message Queue system(MSMQ/RabbitMQ) etc.
You can get a specific answer if you can narrow down your question.
A nice, clean, 'modern' way of doing this, would be to host a Web API directly in the console application, and accept JSON input.
This is relatively easy to set up, and very easy to test and use.
Other methods include .NET remoting (which is not very modern any more), some other kind of service, like WCF, or any of the multitude of windows IPC methods.
I wrote an answer here that has some applicable code. Basically, the OP there wanted to send strings from a Windows Forms application to a console application and have the console application print the strings.
My recommendation is to use a Message Queue.
A few quick notes: first, you may have to enable the feature in Windows if you've never done so. Also, I guess under certain configurations of Windows you can't create the Message Queue directly from C#; if that's the case for you, you can create it manually (or there's probably a way to do it as part of an install script or something).
Here's the Windows Forms code:
private void button1_Click(object sender, EventArgs e)
{
// Or whatever name you end up calling it if you created the queue manually
const string myQueue = ".\\myQueue";
// It's possible that this won't work on certain computers
// If not, you'll have to create the queue manually
// You'll also need to turn the Message Queueing feature on in Windows
// See the following for instructions (for Windows 7 and 8): https://technet.microsoft.com/en-us/library/cc730960(v=ws.11).aspx
if (!MessageQueue.Exists(myQueue))
{
MessageQueue.Create(myQueue);
}
using (MessageQueue queue = new MessageQueue(myQueue))
{
queue.Formatter = new XmlMessageFormatter(new[] { typeof(string) });
queue.Send("Test");
}
}
Console application:
static void Main(string[] args)
{
// Or whatever name you use
const string myQueue = ".\\myQueue";
// See my comment on the corresponding line in the Windows Forms application
if (!MessageQueue.Exists(myQueue))
{
MessageQueue.Create(myQueue);
}
MessageQueue queue = new MessageQueue(myQueue);
queue.Formatter = new XmlMessageFormatter(new[] { typeof(string) });
while (true)
{
Message message = queue.Receive();
string messageText = message.Body.ToString();
// Close if we received a message to do so
if (messageText.Trim().ToLower() == "exit")
{
break;
}
else
{
Console.WriteLine(messageText);
}
}
}
I have successfully compiled and run Windows Service with WCF. With installutil, the Windows Service is successfully getting installed and started. I think I am at the end of my development and just need to invoke/call the method DoJobs() inside WCF. I don't need any user interaction and so I don't have any Windows forms or anything. I just want to invoke/call my WCF function programmatically just after serviceHost.Open();
The base address in app.config file is
http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary1/Service1/
I am deploying my WCF from Windows service with the following code.
// Create a ServiceHost for the CalculatorService type and provide the base address.
serviceHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1));
// Open the ServiceHostBase to create listeners and start listening for messages.
serviceHost.Open();
I have also added the service reference and created the below proxy, but not sure of its use.
WcfServiceLibrary1.WCFServiceRef.Service1Client
I have searched tutorials, the examples show how to invoke the WCF function on button_click event of any form after running Windows service. I just want to do that programmatically on start-up of Windows Service.
EDIT: The code inside my DoJobs() fetches the active tab url of firefox with DDE Client, which throws exception when done only in a Windows Service project but runs successfully when done in WCF project. Please see this for reference.
So I made a C#.Net solution with WCF called from a Windows Service and then I called DoJobs() inside Windows Service as shown below.
WcfServiceLibrary1.WCFServiceRef.Service1Client wcfObj = null;
...
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1));
serviceHost.Open();
if (wcfObj == null)
{
wcfObj = new WcfServiceLibrary1.WCFServiceRef.Service1Client();
wcfObj.DoJobs();
}
}
But, it makes the call happen at the windows service layer, and is throwing the same DdeClient exceptions.
Can the base address url help any way to programmatically invoke DoJobs() in Web-Service? OR there are some other solutions.
Any help is highly appreciated.
Thanks.
This is my aggregated answer from my various comments I made to your post and to Noctis's answer (specifically that we did not know you were using DDE in the OP):
You can't use Dynamic Data Exchange (DDE) in a Windows Service because the latter does not have a message pump. Also DDE requires a Window handle to be passed as a parameter to DDE functions. You can use DDE in programs which do have a message pump does as a WinForms app. See this article for more information
Once your GUI app is running you can either minimize it to a Sys Tray icon or hide the app completely so the user is unaware. Regardless of its visible nature you should have no problem utilising DDE since it will have a message pump.
Now it may be the case you could add a message pump to a Windows Service but I wouldn't recommend it because it falls into the category of because you can do a thing, does not mean you should do a thing. A topic for another time. It's very similar to a recent SO question about how to display a WinForm in a console app - by default you can't and if you managed to you end up with an odd hybrid with much re-inventing of wheels. Not to mention its an ugly hack.
In summary, my best advice is to proceed with a GUI app.
Assuming you have :
// I'm assuming this is your proxy?
var proxy = WcfServiceLibrary1.WCFServiceRef.Service1Client;
// All you need to do is :
proxy.DoJobs() ;
Having seen your update and Micky`s answers, I'm just wondering why you're using DDE. Not sure what your requirements look like, but you can always use your MSMQ to send messages and queue things.
I have a console application I wrote in C# that polls multiple devices, collects some data, and stores the information on a database. The application runs on our web server, and I was wondering how to invoke a method call from the command console (so I can exec a command from php that will be read by the console application, a shell command would work as well).
Anyone got any ideas? I've been floating around 'the google' and have found nothing that will supply my current needs.
Also, i'm not adverse to making changes to the console application if an overhaul is needed there. Please, if your answer is COM Interop, provide a GOOD example of how I would build and call this from PHP / Apache2.
You could create a Service like this:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(
Method = "GET",
UriTemplate = "/magic")]
void MagicMethod();
}
And a service implementation like this:
public class Service : IService
{
public void MagicMethod()
{
//magic here
}
}
to start a HTTP Service it should look like this:
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri("http://127.0.0.1:8080"))
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
ServiceDebugBehavior stp = host.Description.Behaviors.Find<ServiceDebugBehavior>();
stp.HttpHelpPageEnabled = false;
host.Open();
This will start a HTTP server on port 8080.
Then you can make a HTTP Get request to 'http://localhost:8080/magic' to invoke the method call.
Perhaps your console app can poll a directory for a certain file, and react to that.
Then your php app will only need to create that file and the console app should notice it and do whatever you want. I'm not really sure what you want to do.
I would look at using WCF. Your C# application would host a WCF service and then your PHP application could call into it, I believe PHP5 comes with a SOAP library which should make this relatively simple. Any other application you write will be able to easily call in to, especially if they're written in .NET.
I imagine COM would work fine, but I like the scalability of WCF, as if you have to end up moving these applications onto separate servers then you wouldn't need to change anything besides a URL.
There's a good example on this blog. If you're using PHP5 it should be a doddle, if you're having to use 4 then it will still be possible but will require just a bit more legwork.
i did set start my windows service or NT service like everybody says a then
came up this message:
The service myService on local computer started an then stopped.Some services stop automatically if they are not in use by another services or programs
i've started other services and it never hapened...
before i change the value of a parameter that have to find it's value on a web service method
that look on a sql database...
and other change is that got formatted the hard disk...maybe i have to enable somethig
please i need help
It happens most likely because
you have an exception at startup... try to debug your things either by
using a log or by trying to reproduce your behavior in a windows app....
You can even debug your windows service using the following method...
Write the following code in your Service file...
public void OnDebug()
{
OnStart(null);
}
In the program file,
YourService myService = new YourService();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
This can happen when the logic performed using a windows service exceeds the default timeout.
We cannot overcome the default timeout of a windows service. Usually windows services are used to instantiate a method. So start a child thread within the OnStart event of the windows service and call your method within it.
If this is not solving your issue, put the code in try catch and log the exceptions. This error can happen if there is any exception within OnStart event too.
My project was standalone application then I decided to split it as client & server because I need powerful CPU usage and portability at the same time. Now multiple clients can connect to one server.
It was easy when 1 by 1 processing did the job. Now I need to call the same function & scope area again & again at the same time -via client requests-
Please can anyone give me some clue how should I handle these operations, I need to know how can I isolate clients' processes from each other at the server side? My communication is asynchronous, server receives a request and starts a new thread. I think I pass a parameter which one carries the client information, and another parameter as job id -to help client back, client may ask for multiple jobs and some jobs finish quicker than others-
Should I instantiate the class Process on each call? Can I use a static method, etc, any explanation will be of great help!
Below is the part of my code to need modification
class static readonly Data
{
public variable listOfValues[]
}
class Process
{
local variable bestValue
function findBestValue(from, to)
{
...
if(processResult > bestValue) bestValue = processResult
...
}
...
for(i=0;i<10;i++) startThread(findBestValue(i*1000,i*1000+999));
...
}
EDIT: I think I have to instantiate a
new Process class and call the
function for each client and ignore
the same client for same job since job is already running.
Not getting into your application design, since you didn't talk much about it, I think that your problem is ideal for using WCF WebServices. You get client isolation by design because every request will start in it's own thread. You can create WCF host as standalone application/windows service.
You can wrap your communication with WCF service and configure it to be PerCall service (meaning each request will be processed separately from others).
So you'll clean up your buisness logic from syncronization stuff. That's the best way, because managing and creating threads is not difficult to implement, but it is difficult to implement correctly and optimized for resources consumption.