How to invoke WCF method programmatically from windows service - c#

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.

Related

Transfer data from Windows Service to Console Application repeatedly

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);
}
}
}

Get information about internal state of Windows Service

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

Invoke a method in a Console application that is currently running.

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.

The service myService on local computer stared an then stopped automatically

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.

ASMX Web Service Problem Communicating with Windows Service In a Separate Thread

There is a Windows Service on Windows Server 2003 (Amazon Virtual Machine). Some applications can communicate with it (using pipes, but there is an wrapper to do it). It is tested and it works. Also, there is a Web Service written in C# (ASP.NET) which communicates with mentioned Windows Service. When Web Method is called, it creates an instance of the class and calls a function - the function "connects" to Windows Service and post a job to it. But, if inside Web Method is created a thread and the function which "connects" to Windows Service is called inside a thread - connection fails. Connection to Windows Service uses pipes. Web Service works on IIS7. It is worth to mention that all works on my local machine, either from debugger (local server started by VS 2010) or from IE when I call Web Method on Web Service which works on local IIS7. In local all works - but on Amazon Instance doesn't. I'm not a web programmer, so I think there is some issue with security. Any hint? Thanks.
EDIT: Uwe's comment reminded me - the Web Method at first tries to download some files using http and it saves them to path C:\intetpub\wwwroot\files\". It works if files are downloaded from the web method, but download fails if it is done from another thread created in Web Method. Exception was: Access is denied. So, I changed security settings on mentioned folder and explicitly allowed user created by IIS7 (IIS_IUSRS) to read/write the folder, and now files can be downloaded. It seems that the source of these problems is the same.
EDIT: The solution is moved to an answer on Will's suggestion.
Ok guys, the solution is found and as Will recomends, I'll post it here, as an answer to my own question. So, the solution:
The problem was because the thread created by Web Method has to be impersonated. So, in the caller method I had to something like:
[WebMethod]
public void Fnc()
{
...
...
System.Security.Principal.WindowsIdentity wi = System.Security.Principal.WindowsIdentity.GetCurrent();
System.Threading.Thread postJobThread = new Thread(PostJobThread);
postJobThread.Start(wi);
...
}
...
private void PostJobThread(object ob)
{
System.Security.Principal.WindowsIdentity wi = (System.Security.Principal.WindowsIdentity)ob;
System.Security.Principal.WindowsImpersonationContext ctx = wi.Impersonate();
...
// Do some job which couldn't be done in this thread
...
// OK, job is finished
if(ctx != null)
ctx.Undo();
}
That's all. Thanks to guys who commented my question and I hope it'll be useful for somebody else.

Categories