WCF Library with threads in a Windows Service - c#

This is my first WCF Library and I created it within a Windows Service, which I can access just fine and process through it, but unlike a normal library, I can't seem to access any of it's method classes outside of the Web Interface. The WCF Library has some threading within it that stays up until it needs to shutdown and I need the ability to tell this library the service is shutting down and it needs to close out the threads within itself gracefully. I'm guess I'm missing something simple, but maybe I can capture the Close() being called from within the WCF Library?
ServiceHost oServiceHost = new ServiceHost(typeof(WCFListener.MyClass));
oServiceHost.Open();
//wait until shutdown is called.
while (!_shutDownEvent.WaitOne(Timeout.Infinite));
//HERE I NEED TO TELL THE LIBRARY TO STOP ANY THREADS OR
//WITHIN THE WCF CAPTURE CLOSE() WAS CALLED.
if (oServiceHost != null)
{
//close out the WCF Listener service.
oServiceHost.Close();
oServiceHost = null;
}
I know how to launch the WCF Library as it's working and processing, but there are threads that are created within the WCF Libray and stay OPEN in the WCF Library. I need the WCF Library to start closing threads property when Windows tells my Windows Service it needs to stop. serviceHost.Close() doesn't kill the threads that have been created nor do I want it to. This is causing the Windows service to freeze waiting for the threads to stop.. I'm trying to figure out how I can tell the WCF Library this as it doesn't have a interface like an object. I'm sure this is simple and I'm overthinking it.

It is a little hard to understand what your problem actually is, but generally, you would proceed as follows:
Update I have assumed hypothetical MyLibraryClass.Initialize() and MyLibraryClass.Shutdown() methods, that your library provides, below.
So, your library would provide something like this:
public static class MyLibraryClass
{
public static void Initialize(ServiceHost serviceHost)
{
serviceHost.Closed += (...) {
// Cleanup when host closes.
Shutdown();
}
}
public static void Shutdown()
{
// Cleanup. E.g. stop threads, etc.
}
}
If that is not correct, you need to provide more source/context in your question about what you can do or can't do. In general, it is always a good idea to not have explicit active components in a library (like threads, etc.); if required to do so, than you should provide an "initialize" and/or "shutdown" method for the users of your library.
public class MyService : ServiceBase
{
private ServiceHost serviceHost;
protected override void OnStart(string[] args)
{
serviceHost = /* new, etc. */
// Somehow pass the serviceHost reference to your library,
// then subscribe to `Closed`, e.g.
MyLibraryClass.Initialize(serviceHost);
serviceHost.Open();
}
protected override void OnShutdown()
{
serviceHost.Close();
// Do additional cleanup, e.g. stopping your "library threads"
// Alternative to the event-approach in "OnStart", simply call
MyLibraryClass.Shutdown();
}
}
That is, you would open your host when the service starts, and close it when the service ends. There should be no reason to do any extra "waiting", etc. on a service shutdown.
The Windows Service Control Manager will call (via P/Invoke, etc.) the OnStart and OnShutdown methods when it starts / stops the service.
The important thing is, that you do your actual work in a background thread, i.e. exit the OnStart and OnShutdown methods as quick as possible - that is a trait that you get for free with ServiceHost in this case.

Related

Creating new AppDomain calling method in same class as the AppDomain in made

I want to start below potentially long running thread in it's own AppDomain to prevent the webserver from aborting it during recycling. It compiles fine, however during runtime I get this cryptic error
Type is not resolved for member 'MyCore.MyWebService,MyCore,
Version=5.0.0.0, Culture=neutral, PublicKeyToken=null'.
How do I find out what member is not resolved?
Are there any better ways running a long standing thread in a MVC business service layer, that does not get aborted by the server recycling mechanism?
Here is the code:
namespace MyCore
{
[Serializable]
public class MyWebService : IMyWebService
{
AppDomain domain = AppDomain.CreateDomain("Domain");
Thread.CurrentThread.Name = "MVCThread";
domain.SetData("lDatabaseID", lDatabaseID);
domain.DoCallBack(() =>
{
long lID = Convert.ToInt64(AppDomain.CurrentDomain.GetData("lDatabaseID"));
Thread thread = new Thread(
(() =>
{
PopulateTables(lID );
}));
thread.Name = "DomThread";
thread.Start();
});
}
}
IIS is heavily optimised to respond very quickly to hundreds of small simultaneous requests and just isn't the right tool for what you're attempting. You can try to work around that but in the long term you'll be better off building a tool that is designed for long-running tasks. You've then got a pre-packaged solution the next time this problem arises.
The basic idea is to create an external application that does your background processing with some way to pass tasks to it and get results back. I like using the database to communicate as most web applications that need baground processing already use a database. Add a 'tasks' table with {status, startedDateTime, finishedDateTime, parameters, etc}, then write an external application that will periodically look for a new task, complete it and update the database. Your web site can poll the database for status or your application could make an AJAX call to notify the web site when a job has completed (a small iframe in the web site header that shows waiting / completed tasks can be useful if someone will be waiting for the job to complete and is easy to do).
EDIT: Before you do the above review HangFire (which works inside IIS, as a Windows Service or as a console app). Same principles, but a pre-packaged solution. Note that I haven't implemented this yet but it looks good.
Although it's a bit of work to set up, handing this task off to a Windows Service is a good approach if you might have multiple tasks and need them responded to quickly. There are a lot of tutorials on the web that will help you create a Windows Service, such as http://www.codeproject.com/Articles/106742/Creating-a-simple-Windows-Service but you'll have to build a simple task executor on top of that so if that's the way you want to go I'd look for a pre-built task engine (I couldn't find one quickly but I'm probably using the wrong search phrase).
But that's overkill if turn-around time isn't important and a better approach for you might be to create a small console application that will be started every five minutes by task scheduler. It would connect to the database, execute any waiting tasks then shut down again. This is easier to debug and install than a Windows service and achieves the same goal of moving the task execution out of IIS.
Remember that you still have to detect and handle Windows shutdown so that you don't get half-finished orphaned jobs - at the very least just tag that task as aborted and exit cleanly.
Alright after having mucked with Hangfire, I finally got it to work in .Net 4.0 and MVC 3. Had to install Common.Logging.Core 2.2.0, since the NuGet installed the wrong version (3.3.0)
In my Initial controller I added the following
namespace Core.Controllers
{
...
public void Configuration(IAppBuilder app)
{
app.UseHangfire(config =>
{
config.UseSqlServerStorage(ConnectionString.GetTVConnectionString());
config.UseServer();
});
}
...
}
ConnectionString.GetTVConnectionString() gets the connection string from the config file.
Up top I added the following
[assembly: OwinStartup(typeof(Core.Controllers.BaseController))]
In the code that starts the background thread I added the following, passing in a long instead of the class and having the job load the POCO class from the db.
BackgroundJob.Enqueue(() => PopulateTables(lDatabaseID, JobCancellationToken.Null));
The Enqueue() function returns a job id, that later can be used to cancel the job if needed, through the BackgroundJob.Delete(jobid) function.
In the job method I then have this
while (idxMin < max)
{
try
{
cancellationToken.ThrowIfCancellationRequested();
....
}
catch (JobAbortedException jobEx)
{
....
}
}
It's important to use dependency injection, so my class had a parameter less constructor added that re-reads the connection string rather than have it passed in.
public MyWebService ()
: this(ConnectionString.GetTVConnectionString())
{
}
public MyWebService (string sConnStr)
{
msConnStr = sConnStr;
}
After that it seems to run pretty well. A number of tables are added to the database specified in the connection string. So far it seems like the jobs survive recycling on the webserver.

Restarting a service after a fatal crash

I have several services that run correctly 99.9% of the time. However, they work with network and database and occasionally an error that I have not anticipated makes it into the code and causes the service to crash. In this instance, restarting the service usually fixes the problem.
My service creates a new thread where the main code is run. I have added error handling to the service class that catches and logs any unhandled exceptions from this thread. What I am wondering is if I can call OnStop and then OnStart from the service class to restart my service?
The code that I am using is in located in the same class as OnStart and OnStop. I have posted it below:
private void ExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{
log.Append("Fatal Exception:\n" + args.ExceptionObject);
eventLog.WriteEntry(log.ToString());
log = new StringBuilder();
OnStop();
if (numberOfCrashes++ < 10)
{
Thread.Sleep(60000);
OnStart(null);
log.Append("The service has been restarted " + numberOfCrashes + " times.");
eventLog.WriteEntry(log.ToString());
log = new StringBuilder();
}
}
What I am wondering is if I can call OnStop and then OnStart from the
service class to restart my service?
This will depend on how you've implemented your OnStart and OnStop logic.
For example, if your OnStart is able to determine if the working thead is already started and, if so, it stops and starts it again, then yes, you may be able to simulate a service restart by directly calling these methods.
Thus, your actual code on OnStart and OnStop is the right answer to your question, and it's up to you to refactor it to cover your requirement of programatically-restarting your service without restarting the service at the operating system level.

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.

Restart a WCF service hosted by a C# console application

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.

.net windows service as a state server

i'd like to create a windows service that would be accessible via WCF from a web application.
The workflow would be:
Windows Service starts and would hold a default value in memory.
A web app would connect the windows service via wcf and take the value and after some processing set the value back in the memory.
In a while would happend the same as in point 2., and so on,so on
This value would be hold only in memory.
The point is I dont know where put the variable that would be hold in the memory of the windows service.There is a Service class wich is instancied in a Program class wich is static class. So whats the best place to put a variable that would be hold in the memory as long as the service is running ?
And second question,is it correct to reference the exe of the windows service in a DLL ??
There is a service class for every windows service that also contains the start and stop methods. However, for your service, I'd simply create a singleton class that is accessed from the class that handles the WCF client requests.
There's no need to reference the exe of the service (and I strongly recommend you not to do that), as when you're using WCF you'll insert a service reference into your client project and just need two methods to get and set the data.
I suggest: Design your operation and data contracts for the service and then create the service reference within your client project. That'll make things clear.
If you don't know what I'm talking about, I recommend googleing for WCF samples.
EDIT
You write in the comment that you created a service class with a private field. I suppose you didn't actually do what I suggested :-) I said: Create a singleton class that is accessed by the class that handles the get/set requests.
public class ValueHolder
{
private static ValueHolder m_singleton = null;
private int m_someValue;
private ValueHolder()
{
m_someValue = 0;
}
public static ValueHolder Instance
{
get
{
if (m_singleton = null)
m_singleton = new ValueHolder();
return m_singleton;
}
}
public int SomeValue
{
get { return m_someValue; }
set { m_someValue = value; }
}
}
So now you have a window service class that you use to host a WCF service. The WCF service contains methods to get/set the value from ValueHolder.Instance.SomeValue. These methods are exposed to the client using the data contract.
Start your service and add a service reference to the client using the respective option in Visual Studio (not a reference to the DLL, but a service reference!!). The client now accesses the get/set methods of the service.
Job done, where's my money? :-D
It almost sounds like a separate service might be a little overkill for what you're after - maybe you should take a look at Inter-Process shared memory.
Take a look at #3 in this article.
http://www.codeproject.com/KB/threads/csthreadmsg.aspx

Categories

Resources