I have a topshelf windows service where I want to do some checking (i.e. if an xml file exists) and if the check fails I need the windows service to stop.
So I tried doing the check in the Start() method and then raise an exception:
public void Start()
{
if (!File.Exists(_xmlFile) throw new FileNotFoundException();
// Do some work here if xml file exists.
}
However, the windows service stays around as a process after the exception which I then have to kill manually in the task manager.
Is there a way to not run the service if certain conditions (i.e. file not found) hold?
You could use the HostControl object and modify your method like this:
public bool Start(HostControl hostControl)
{
if (!File.Exists(_xmlFile)
{
hostControl.Stop();
return true;
}
// Do some work here if xml file exists.
...
}
And you will need to pass the HostControl in to the Start method like this:
HostFactory.Run(conf =>
{
conf.Service<YourService>(svcConf =>
{
svcConf.WhenStarted((service, hostControl) =>
{
return service.Start(hostControl);
}
}
}
Each of the WhenXxx methods can also take an argument of the HostControl interface, which can be used to request the service be stopped, request additional start/stop time, etc.
In such case, change signature of start() to be bool start(HostControl hc). Retain reference to this HostControl in the service as follow:
public bool Start(HostControl hc)
{
hostControl = hc;
Restart();
return true;
}
Now when you want to stop the service use following call:
hostControl.Stop();
I was curious about this from the point of view of a best practice or recommendation in Topshelf's documentation, but couldn't find anything. I did, however, find two separate comments from phatboyg...
Best comment... how to stop service on exception, via this issue (I cut out some of the detail):
If your service's Start method throws an exception, the service will fail to start.
Once the service is running, if an unhandled exception is thrown, the service will stop, and report it as a crash to the service control manager.
If you need to Stop your service programatically, use the HostControl method Stop.
So I think the easiest answer is to throw an exception.
You were doing that, and you mention "the windows service stays around as a process after the exception". That seems like an unrelated bug somewhere in your code, or perhaps you somehow had multple instances running? I've been testing these scenarios this morning and have not seen my service running after throwing an Exception in the start method.
Also, relevant to checking before HostFactory.Run, mentioned in the accepted answer, via https://groups.google.com/forum/embed/#!topic/topshelf-discuss/nX97k3yOhJU:
"Your application should do nothing more than configure NLog/Log4Net before calling the HostFactory.Run() method."
I just ran into this issue and all the above answers seem to be over complicating things. All you need to do is use the WhenStarted overload that accepts a Func<T,HostControl,bool> and return false if your internal service bootstrap failed. I don't think hostControl.Stop() needs to be called explicitly.
//Here is bit from inside the .Service<T>() call
s.WhenStarted((YourService svc, HostControl hc) => svc.Start());
//And the svc.Start method would look something like this:
class YourService
{
public bool Start() {
//return true if all is well
//or false if you want service startup to be halted
}
}
I've "borrowed" the sample code for the functional setup of topshelf to demonstrate a point:
HostFactory.Run(x => //1
{
x.Service<TownCrier>(s => //2
{
s.ConstructUsing(name=> new TownCrier()); //3
s.WhenStarted(tc => tc.Start()); //4
s.WhenStopped(tc => tc.Stop()); //5
});
x.RunAsLocalSystem(); //6
x.SetDescription("Sample Topshelf Host"); //7
x.SetDisplayName("Stuff"); //8
x.SetServiceName("stuff"); //9
});
You're going to have to place your file system check BEFORE the above code runs. Let's think about this a second. The point of having a service is to make sure it RUNS and KEEPS RUNNING. You're attempting to subvert a basic principle of having service applications in the first place. Instead of trying to stop the service because of the missing file, figure out some way to alert your support staff and NOT do whatever depends on that missing file.
When you catch the exception you can use ServiceBase.Stop() Method to stop the service by itself.
try
{
// Your Code
}
catch (Exception ex)
{
// The code for stopping service
}
Also you can have multi catch blocks in some cases:
try
{
// Your Code
}
catch (IndexOutOfRengeException ex)
{
// The code for stopping service
}
catch (FileNotFoundException exc)
{
// The code for stopping service
}
Read more about ServiceBase.Stop()
Related
Based off the sample at this question which deals with passing custom parameters to Topshelf, I now want to be able to cleanly exit out of the Topshelf HostFactory.
I have the following code, and it does work, but when it "returns", the console displays an ugly error stating Topshelf.HostFactory Error: 0 : An exception occurred creating the host... The service was not properly configured... ServiceBuilderFactory must not be null
What should I uses instead of return to simply tell Topshelf to exit and not do anything?
string foo = null;
HostFactory.Run(x =>
{
x.AddCommandLineDefinition("foo", f => { foo = f; });
x.ApplyCommandLine();
if (!string.IsNullOrEmpty(foo))
{
Console.WriteLine("A value for Foo was received... exiting.");
return;
}
x.Service<MyService>(s =>
{
s.ConstructUsing(() => new MyService());
s.WhenStarted(z => z.Start());
s.WhenStopped(z => z.Stop());
});
x.StartAutomatically();
});
In this case, you should not be calling .ApplyCommandLine() in your code, that's automatically handled by Topshelf. And it's important to recognize that you're configuring the host at this point, and should not be throwing an exception.
The best place for your command-line value check is in the ConstructUsing() method, where you can verify the command-line arguments are present. If your conditions are not satisfied, throw an exception and the service will fail to start.
If you do it anywhere else, the command-line options for install/uninstall/etc. will not work without that command-line parameter specified.
We have interceptors on data-changing methods that flush changes to the database after the methods have run. In case of a deadlock, we would like to rerun the methods.
In this simplified example I catch SqlExceptions and in case of a deadlock I try calling Proceed() again.
try {
invocation.Proceed();
if (!isReadOnly) {
log.Trace("Flushing the unit of work.");
session.Flush();
}
} catch (GenericADOException ex) {
var sqle = ADOExceptionHelper.ExtractDbException(ex) as SqlException;
if (sqle != null) {
if (sqle.Number == deadlockVictim) {
invocation.Proceed();
}
}
This fails due to Castle noticing that I'm trying to call Proceed() a second time and throws an exception starting with:
This is a DynamicProxy2 error: invocation.Proceed() has been called
more times than expected.
How can I call Proceed again after catching the exception?
It is not possible without a ugly hack that resets the interceptor count of your interceptor chain, but if you really need to you must:
get into the IInterception class and change the currentInterceptorIndex (it changed name since the article was published) to -1, in whichever way you want. The article author uses an extension method
call the proceed method again after solving whichever problem in your DB
This is really really really not recommended; you should at least setup some kind of upper limit to the call loop of the method to avoid some case where your DB call never gets out of the proceed-reset-proceed flow
I thought this approach would be safe, in that it wouldn't allow exceptions to propagate. A colleague of mine suggested that the exceptions may need to be observed on the main thread, and should thus be passed up to the main thread. Is that the answer? Can you see how an exception could leak through this?
private static void InvokeProcessHandlers<T>(List<T> processHandlers, Action<T> action)
{
// Loop through process handlers asynchronously, giving them each their own chance to do their thing.
Task.Factory.StartNew(() =>
{
foreach (T handler in processHandlers)
{
try
{
action.Invoke(handler);
}
catch (Exception ex)
{
try
{
EventLog.WriteEntry(ResourceCommon.LogSource,
String.Format(CultureInfo.CurrentCulture, "An error occurred in a pre- or post-process interception handler: {0}", ex.ToString()),
EventLogEntryType.Error);
}
catch (Exception)
{
// Eat it. Nothing else we can do. Something is seriously broken.
}
continue; // Don't let one handler failure stop the rest from processing.
}
}
});
}
By the way, a stack trace is indeed showing that an exception is leaking from this method.
The exception is AccessViolation, and I believe it has to do with the code that calls this method:
InvokeProcessHandlers<IInterceptionPostProcessHandler>(InterceptionPostProcessHandlers, handler => handler.Process(methodCallMessage, methodReturnMessage));
The getter for InterceptionPostProcessHandlers contains this:
_interceptionPreprocessHandlers = ReflectionUtility.GetObjectsForAnInterface<IInterceptionPreprocessHandler>(Assembly.GetExecutingAssembly());
Just make sure to check parameter for null references before you iterate
other than that there is nothing wrong as log writing is not something to stop the execution, but i would recommend to make it more clean and maintainable by encapsulating the logging into a mothod like:
bool Logger.TryLog(params);
and inside this method do the try with a catch that returns false and if you want to handle it in client code do it and if you dont never mind just call the logger in a clean encapsulated way
A colleague of mine suggested that the exceptions may need to be
observed on the main thread, and should thus be passed up to the main
thread.
How can it be "passed up to the main thread"? The main thread is away and doing its own thing.
The best you can do is to make it configurable and accept an ExceptionHandler delegate that is called.
I'm developing a .Net Webform application, with heavy use of web services to communicate with an outside-server database.
So, I'm trying to find the best way to deal with disconnections and failures when calling a WS method.
For now, I've made a proxy function -kind of a layer- for every WS method I call, that repeats the specific WS call in a loop until it cames out successfully.
For Both Sync and Async calls, I've solved my problem, but I added an annoying extra layer to my WebService layer, with extra maintenance, and a lot of redundant code.
I refuse to believe there's not an existing solution for this standard situation, but can't find it anywhere.
Any Ideas?
Following, an example of my extra layer (Sync):
public static int WsMethod(string param1, int param2)
{
while(true)
{
try
{
return new Webpoint().WsMethod(param1, param2);
}
catch (Exception)
{
Thread.Sleep(new TimeSpan(0, 0, sleep_seconds));
}
}
}
And Async:
public static void WsMethodAsync(string param1, int param2, WsMethodCompletedEventHandler handler)
{
while (true)
{
try
{
var server = new Webpoint();
server.WsMethodAsyncCompleted += delegate(object sender, WsMethodAsyncCompletedEventArgs args)
{
if (args.Error != null)
{
Thread.Sleep(new TimeSpan(0, 0, sleep_seconds));
this.WsMethodAsync(param1, param2, handler);
}
else
{
handler(sender, args);
}
};
server.WsMethodAsyncAsync(param1, param2);
return;
}
catch (Exception)
{
Thread.Sleep(new TimeSpan(0, 0, sleep_seconds));
}
}
}
I would not recommend this pattern. If there is some problem with the parameters on your call this will run forever.
Normaly I would catch the few expected exceptions (CommunicationException, SocketException, whatever you need) and return some status-code for this (Ok, or NoNetwork, or whatever).
Or wrap up all expected exceptions into a MyCommunicationException and throw this (to hide implementation details from the caller and make exception-handling easier for it)
But give the control back to the caller and let the caller decide how to go on. Don't catch the other unexpected exceptions or rethrow them.
The caller can then decide to try time and again or 3-times or whatever.
If something were genuinely wrong with the service, or the connection thereto, or the request being made, then this would repeat indefinitely without ever telling you what's wrong.
What are the implications of the service call failing? How often does it really fail? And, most importantly, for what reason does it fail? If the reason is something that can be fixed, it should be fixed. Not worked around.
As a simple example, if this back-end service call is something initiated by a user of the website (say, they're trying to fetch some data to edit) then if the call fails you just present an error to the user. Something like:
"I'm sorry, but that data is not available at this time. The support team has been notified of this problem. Please try your request again. If the problem persists, contact the help desk at 800-555-1234."
Now, this shouldn't just be a single generic error to show the user no matter what happens. The code needs to be robust enough to discern one kind of error from another. If the service is unreachable, this error applies. If the service is saying that the request is invalid, then there's something wrong either with that the user is doing or what your code is doing, and that needs to be fixed. Etc.
How you deal with the errors and maintain a usable application is ultimately up to you and the business overall. But I honestly can't recommend the approach you outline on the question. That approach doesn't solve anything, it just ignores the problem until it gets worse. You need to determine the root cause of the errors and address that, not ignore them.
Also, any time an error is suppressed/ignored, a kitten dies.
I have the following problem, basically i have a WCF service which operates fine in small tests. However when i attempt a batch/load test i get an InvalidOperationException with the message when the open() method is called on the proxy class:
"The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be modified while it is in the Opened state."
I have searched google, but cannot find anyone else really quoting this exception message.
I guess some further info on the service may be necessary for a diagnosis - when the service receives data through one of it's exposed methods, it basically performs some processing and routes the data to a service associated with the data (different data will result in different routing). To ensure that the service runs as quickly as possible, each cycle of receiving, processing and routing of the data is handled by a seperate thread in the threadpool. could this be a problem arising from one thread calling proxyClass.Open() whilst another is already using it? would a lock block eliminate this problem, if indeed this is the problem?
thanks guys, - ive been workikng on this project for too long, and finally want to see the back of it - but this appears to be the last stumbling block, so any help much appreciated :-)
=========================================================================
thanks for highlighting that i shouldn't be using the using construct for WCF proxy classes. However the MSDN article isn't the most clearly written piece of literature ever, so one quick question: should i be using a proxy as such:
try
{
client = new proxy.DataConnectorServiceClient();
client.Open();
//do work
client.Close();
}
.................. //catch more specific exceptions
catch(Exception e)
{
client.Abort();
}
How are you using proxy? Creating new proxy object for each call. Add some code regarding how you use proxy.
Desired way of using proxy is for each call you create new proxy and dispose it once completed. You are calling proxy.open() for opened proxy that is wrong. It should be just called once.
Try using something like below in finally, as wcf does not dispose failed proxy and it piles up. Not sure it would help but give it a shot.
if (proxy.State == CommunicationState.Faulted)
{
proxy.Abort();
}
else
{
try
{
proxy.Close();
}
catch
{
proxy.Abort();
}
}
Why to do this?
http://msdn.microsoft.com/en-us/library/aa355056.aspx
Code you posted above would work but you will alway be eating exception. So handle wcf related exception in seperate catch and your generic catch with Excelion would abort then throw exception.
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
Also if you still want to use convenience of using statement then you can override dispose method in your proxy and dispose with abort method in case of wcf error.
And do not need to call .Open() as it will open when required with first call.
I'm assuming you're using .NET 3.5 or later. In .NET 3.5, the WCF ClientBase'1 class (base class for generated client proxies) was updated to use cached ChannelFactories/Channels. Consequently, unless you're using one of the Client use/creation strategies which disables caching (Client constructor that takes in a Binding object, or accessing one of a few certain properties before the backing channel is created), even though you're creating a new Client instance, it could very well still be using the same channel. In other words, before calling .Open(), always ensure you're checking the .Created status.
It definitely sounds like you've called Open() multiple times on the same object.
we hit the same roadblock as you sometime ago.
The issue with the using statement , is that if you get to a faulted state, it will still try to close at the end of the block. Another consideration, which was critical for us, is the cost of creating the proxy everytime.
We learned a lot from those blog posts:
http://blogs.msdn.com/wenlong/archive/2007/10/26/best-practice-always-open-wcf-client-proxy-explicitly-when-it-is-shared.aspx
and
http://blogs.msdn.com/wenlong/archive/2007/10/27/performance-improvement-of-wcf-client-proxy-creation-and-best-practices.aspx
Hopefuly it will help you as well.
Cheers, Wagner.