Restart a WCF service hosted by a C# console application - c#

I have a WCF service that is hosted on a c# console application. Is there a way to restart this service, preferably by calling an endpoint in the service itself (ex. myService.Restart()).
Thanks

I have to do something similar when I perform an automatic update of a remote WCF service. In your Restart() method, close the host:
try
{
host.Description.Endpoints.Where(x => !x.Address.ToString().EndsWith("MEX")).ForEach(endpoint => _log.InfoFormat("Closing {0}", endpoint.Address));
host.Close(TimeSpan.FromSeconds(5));
}
catch (Exception)
{
host.Abort();
}
I wait for my update to apply, and then after a success or failure, I re-open the host using the same code I used to start it in the first place.
If you just wanted to restart immediately, you could just call host.Open(), or you could set up a timer to call it, etc.
try
{
host.Open();
host.Description.Endpoints.Where(x => !x.Address.ToString().EndsWith("MEX")).ForEach(endpoint => _log.InfoFormat("Host opened at: {0}", endpoint.Address));
}
catch (Exception ex)
{
_log.Error("Unable to open host.", ex);
}

To answer my question, I have solved the problem by doing the following:
Separating the code that loads the DLL files from the WCF service code into another class library project
Create an interface with the same method signatures as the ones that load DLL files in the new project (this interface is used by both projects now)
In the web service, load the other project in a new application domain. This way the DLL files are locked by the new application domain not the default.
If I want to update my nunit DLL files now, all I have to do is unload the application domain from the web service, update the files and finally create a new application domain.
AppDomain remoteDomain = AppDomain.CreateDomain("New Domain");
IClass1 class1 = (IClass1)remoteDomain.CreateInstanceFromAndUnwrap(
"Test1.dll", "Test1.Class1");
Note: IClass1 is the common interface between the projects.

you definitely are not going to be able to 'restart' a faulted service from calling that same service itself. In theory you could host 2 services in the same process. put the one you want to be 'restartable' in a public static variable and restart it within the other service. The problem would be restarting the restarter service if it faults... :) and you definitely want 'administrator-like' restrictions on your restarter service so unauthorized users can't do it.

It's a bit kludgy, but I suppose you could expose a callback on your service that the host could attach to and take appropriate action when it's triggered. That would give your host the ability to decide what a "restart" really means and how it needs to be executed. More importantly, it lets your decide whether it should do something extreme like spawn off a watcher process and then off itself or gracefully trash and reinstantiate your service (preferable).
Mmmmmm... kludge....

You cannot ask a service to restart itself. Consider a windows service (a service hosted in windows provided container) which has a RESTART functionality. Here RESTART functionality is provided not by the service but by the container. The container controls how to stop the service and start it.
Similarly in your case, you should try to look out for options if your container can provide the functionality you need. Since you want to control it remotely, the container should also be available remotely, which cannot be possible if the container is a console application. Instead it has to be another web service or web application.

Related

WCF service hosted in Windows service - not working

I've created the WCF service and some simple WPF application consuming it. When I'm running the project from within Visual Studio, the WCF Test Client opens and the application works just fine, method defined in service work.
But I need to host this WCF service in a Windows Service. I've followed this, installed the services using Installutil.exe and the ran the service. Everything went fine, it's working.
Yet, when I'm trying to open the executable file with WPF application directly from the debug folder of the app, I'm getting this error:
zad8. has stopped working
After choosing the option to debug it with new instance of VS I get
XamlParseException occured in PresentationFramework.dll
The stack trace shows something like:
connection can't be started, because the target computer is actively refusing it
Do you have any idea what could go wrong?
Fortunately, I've managed to come up with solution. I think I should post it, maybe one day it will help somebody:)
I actually did two mistakes, but one of them was unfortunately caused by the mentioned tutorial (here) in connection with my temporary blackout.
In step 5, point 8 of this tutorial, there's an example of overriding OnStart() method:
protected override void OnStart(string[] args)
{
if (myServiceHost != null)
{
myServiceHost.Close();
}
myServiceHost = new ServiceHost(typeof(Service1));
myServiceHost.Open();
}
Beware, that Service1 is ambiguous in this context, because it's name of the Windows Service project class as well as the name of WCF Service class. It should be written with fully qualified name (here it is WcfServiceLibrary1.Service1). In my case, the service name was different, and I just put the Service1 in there in a hurry. Anyway..
In case, someone has it all behind and still encounters the same problem (with app stopped working), I think that you should try open the project in Visual Studio and try to debug the client consuming application as a new instance (right click on the project-> Debug -> Start as new instance...).
It might seem trivial, but when u hit F5 or Ctrl+F5 then even if u have only those project set as startup project, VS will host it's client anyway. In my case it did matter, because I needed to use isolation storage file. And as it was kept on the service side, then I had this file created in IIS server created by VS. Somehow, my method of creating such file had set FileMode.Open() and it was causing the crush, because in Windows Service it didn't exist and the new one couldn't be created and that was neccessary to run it correctly.
What's more it just showed me that this question couldn't be answered properly, cause the data I've provided was not enough and it was delicate.
Cheers:)

Windows Service - WCF Service Design

I have a Windows Service that hosts a WCF service and I am successfully able to connect to it using WCFTestClient and a Custom Client. The windows service is based upon what used to be an exe, but since the program will be used for a long running process on a server, the service is a better route. The problem is that I cannot access static variables in the application from the WCF service.
In the .exe (I switched this to a .dll which is the server application) I use a global class implemented as such:
public static class Globals
{
....
}
This holds references to the major parts of the program so that if any part needs to reference another I can use the syntax Globals.JobManager.RunJob().
The problem that I am encountering is that the WCF service is not able to reference Globals at run-time. One example of where I need this to be done is in the GetJob method:
public class ConsoleConnection : IConsoleConnection
{
public string[] RetrieveJobList()
{
string[] jobs = Globals.JobManager.GetAllJobNames().ToArray();
return jobs;
}
}
This method returns null when tested in WCFTestClient and throws an exception in the created client.
I believe this issue to be caused by the way the Windows Service, WCF Service, and the application DLL are initiated. The current method is such:
public class ETLWindowsService : ServiceBase
{
....
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
Globals.InitializeGlobals();
serviceHost = new ServiceHost(typeof(ConsoleConnection));
serviceHost.Open();
}
....
}
Here the Windows Service starts, Calls the Globals.InitializeGlobals() that creates all the necessary parts of the application, then starts the WCF service (If this is the wrong way to do this, let me know. I'm piecing this together as I go). I'm assuming that these actions are being done in the wrong order and that is the cause of the problems.
Do I need to have the Windows Service create the WCF Service which in turn creates the application (this doesnt make sense to me), or do I have the Windows Service create the application which then creates the WCF Service? Or is there a third option that I am missing?
The application is in a .dll with the WCF in a separate .dll
I totally agree with Andy H.
If I review this kind of code, I won't try to make the stuff work with the global static variable (even if in the end this is probably possible). A static global class is smelly. First of all, I will figure out to make it work without it.
There are several solution: dependency injection, messaging communication, event driven...
To help you: a long running process in a web service is very common, youy have a good description
here. But in any case, it never uses a static class to synchronize the jobs :)
Improve your design, and you will see that your current problem won't exist at all.

Access Azure Service config from C# program called by a startup script

I have a C# console app called during the startup of a WebRole to perform customized instrumentation. I'd like for this program to be able to read the latest values from Service Config and act accordingly.
I've setup the startup script that calls my .EXE to run in elevated mode. I've added a reference to Azure's ServiceRuntime to the console app, however I'm getting the following error: role discovery data is unavailable
If you've put calling this executable as a start-up task in the .csdef, then the information you're asking for may not be available as the role has not yet been set up (see lifecycle of Web/Worker role).
This could also be the problem if you're calling the executable within OnStart in WebRole.cs - as IISConfigurator is called asynchronously with OnStart.
For the startup task, one work around for this is detailed at http://mvolo.com/configure-iis-websites-windows-azure-startup-tasks-appcmd/ (although it deals with changing IIS configuration).
For the WebRole issue, you could overload Run() and call your executable from there - possibly with retries like:
while (!RoleEnvironment.IsAvailable) {
Thread.Sleep(1000);
}
RunExecutable();

Recycle App Pool on IIS6 using C#

I'm attempting to recycle an app pool on IIS6 programmatically through a web application. I have searched all over the net and found a bunch of solutions (Most involving impersonation) but none of them seem to work. The most common error I get is E_ACCESSDENIED despite entering a valid username and password. Can anybody point me in the right direction?
The solution I use for this sort of thing (Where you're trying to run a process from ASP.NET that needs administrative privileges) is the following:
Write whatever you need done as a Self hosted WCF service. Preferably an Http REST Service, so it's easy to call (even using just a browser for testing)
Make sure you service is run using an administrator account. You can use the task scheduler to make sure the service is running at all times as well as run using an Administrator account.
Execute methods on the service from your ASP.NET application using a WCF Client
And it works all the time no matter what "process" I'm trying to run from within an ASP.NET application.
Now as far are the details (code) is concerned let me know if you need help. The code below
is the code you'd have in a console application in order to make it a self hosted WCF Service.
In this case it's an Http service listening on port 7654.
static void Main(string[] args)
{
var webServiceHhost = new WebServiceHost(typeof(AppCmdService), new Uri("http://localhost:7654"));
ServiceEndpoint ep = webServiceHhost.AddServiceEndpoint(typeof(AppCmdService), new WebHttpBinding(), "");
var serviceDebugBehavior = webServiceHhost.Description.Behaviors.Find<ServiceDebugBehavior>();
serviceDebugBehavior.HttpHelpPageEnabled = false;
webServiceHhost.Open();
Console.WriteLine("Service is running");
Console.WriteLine("Press enter to quit ");
Console.ReadLine();
webServiceHhost.Close();
}
AppCmdService is a WCF Service class that looks like this (in my case). In your case you probably don't need a response from your service. In my case I'm getting a Json response. The actual implementation of what it is you're trying to do will be different obviously. But I'm assuming you already have that piece worked out. So simply call a method of that class from here.
[ServiceContract]
public class AppCmdService
{
[WebGet(UriTemplate = "/GetCurrentExcutingRequests/?", ResponseFormat= WebMessageFormat.Json)]
[OperationContract]
public IEnumerable<ExecutingRequestJson> GetCurrentExcutingRequests()
{
return CurrentExecutingRequestJsonProvider.GetCurrentExecutingRequests("localhost");
}
}
On your ASP.NET side, you don't really need a WCF client. All you need is a way to make an http call to the service. So you can simply use HttpWebRequest to make the call out to your service, which in turn execute your process.
Hope all of this makes sense?
Maybe this SO question helps you. There are several solutions (also for IIS6):
Restarting (Recycling) an Application Pool
IMHO the best you could do is to decide to go with a concrete approach an then when you run into an exception, to ask a concrete question with the source code of your approach. Otherwise it's just very vage to answer your question.

What is the accepted pattern for an application that can be run as a service or as a console application

I have a project that is deployed to production as a windows service. However for local development purposes it would be useful to run it as a console application. At the moment I have a class Called ReportingHost that provides my core functionality, And a class called ReportingServiceHost that inherits from ServiceBase and allows me to run the application as a service. There is also a program class with a main method that calls ServiceBase.Run on my ReportingServiceHost.
I think I need to write a ReportingConsoleHost class that allows me to run the functionality in a console. Then I need to modify my Main to react to a command line switch and choose one or the other. These are the two bits I am having trouble with.
I have had a look at this and attempted to use that code but my app exits immediately, it doesn't show a console window and it doesn't wait for Enter before closing.
Part of the problem is that I dont have a deep understanding of how these things work. a definitive pattern for splitting my functionality, my two different ways of running that functionality, and a main method that chooses one of these ways based on a command line argument is what I am hoping to achieve.
I suspect your test project was configured as a windows exe, not a console exe. With a windows exe Console.ReadLine will return immediately.
To have a console exe that works both as a service and at the command line, start it as a service project (in Visual Studio) - and add a check on Environment.UserInteractive - i.e.
static void Main() {
if(Environment.UserInteractive) {
// code that starts the listener and waits on ReadLine
} else {
// run the service code that the VS template injected
}
}
You can of course also use a command line switch. I have example on microsoft.public.dotnet.languages.csharp that acts as:
an installer / uninstaller
a service
a console-mode app
depending on the switches
I have done this before by implementing a normal Windows Service (by deriving from ServiceBase), but putting a check in the main method to check for a command line argument.
If the args contain /console, start the console version, otherwise start the service.
Something like this:
internal class MyService : ServiceBase
{
internal static void Main(string[] args)
{
if (args.Length == 0)
{
// run as a service....
ServiceBase[] servicesToRun = new ServiceBase[] {new MyService()};
Run(servicesToRun);
}
else
{
// run as a console application....
}
}
}
My advise? Put all your logic for your service in a separate assembly. (A class library or DLL.) Then create one project as service which references your class library and puts the code to use as services. Create a second console project which also references your class library but which will make it available as a console application.
You would end up with three different projects in your solution but it does allow you to keep things separate. Actually, this would make it possible to extend your service in several other shapes too. You could, for example, create a 4th project as a web service and thus call your service from a web browser on a client system. Because the software logic is separated from the usage logic, you gain lots of control over it.
Be aware that a service will possibly run with more limitations than a console application. In general, services don't have network access by default, don't have a monitor assigned to them to display error messages and in general run with a limited user account or system account. Your service might work as a console yet fail as a service because of this.
There are already two good answers above - but I thought I'd post a link to Brian Noyes' Debuggable Self-Host Windows Service Project blog post - it talks about WCF but should apply to any 'Windows Service'.
The best thing is the sample code - if you can't figure out where the above examples 'fit', grab the complete project and see how it works. Thanks Brian!

Categories

Resources