Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explain why "using" won't work in service?

Tags:

c#

using

signalr

So I was stuck on this problem for about a week. I was trying to run a project to recieve a TCP connection and start a SignalR Hub as a Service. Both worked perfectly running the project as a .exe file. The TCP part would work perfectly, however I was having problems with the SignalR side.

The reason ended up being the using statement.

Before

using (WebApp.Start<SignalrStartup>(url))
{
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine("Server running on {0}", url); // was url
    Console.WriteLine("ID\tMessage");
    Console.ReadLine();
}

After

WebApp.Start<SignalrStartup>(url);

I had tried running the the code with the Console.WriteLine() commented out, as I thought it might be throwing an exception as the is no console to output to once run as a service. This also didn't work, but also wouldn't work as a .exe file either as it needed the Console.ReadLine() to keep the console open, sort of how you need it to keep HelloWorld.cs open. Once the using wrapper was removed along with the console, it would then work in both the .exe and the service.

I have read that the using statement kills objects in it once you leave the wrapper. But I don't understand how the After bit of code keeps the .exe code open once running. Is there any point in using using or have I been using it wrong?

Edit

protected override void OnStart(string[] args)
{
    Task.Factory
        .StartNew(() => StartTCP())
        .ContinueWith(t => StartSignalR());
}

The call is being made from the StartSignalR() method.

like image 952
Tomaltach Avatar asked Dec 23 '15 07:12

Tomaltach


People also ask

How do you tell a customer you will no longer serve them?

Stay calm, rational and polite. Give reasons for terminating the relationship, but keep emotion and name-calling out of the conversation. Follow-up with a phone call. You can start the process with an email, but you should follow-up with a phone call to talk your client through the process and answer any questions.


2 Answers

What's Going Wrong With Your Service?

The problem you're having is that your Console.ReadLine does a blocking wait for standard input. That will block forever on a windows service and cause the service control manager to time out the service start after 30 seconds. This question has more information about what's going on.

If you remove the entire contents of the using statement, and the statement itself as you have done the server that was started by WebApp.Start will continue on in the background after your service Start method completes. This is the correct behaviour of a service.

What you're effectively doing here is to leak the asynchronous workers that WebApp.Start created. This means that they're still running after the service start completes to listen for requests.

You should probably keep track of the IDisposable that WebApp.Start returns though, and dispose it in the Stop method.

What About using?

A using statement makes sure a resource is always disposed when control leaves the using statement's block. This can be either due to an exception being thrown or because the block completes successfully and control moves on to the next part of the program.

using statements are used when you know that nothing wants to access the resource after the block has completed. This is usually the case when you're dealing with methods that return an IDisposable to you. In your case however you don't want to call dispose because you want the threads that WebApp.Start created to continue after the service has started.

like image 137
Will Avatar answered Oct 02 '22 17:10

Will


Webapp.Start<> starts worker threads. These threads keeps your exe running, even after the code in your HelloWorld.cs has finished executing. Your exe will not shut down until all worker threads have been stopped.

When you add your "using"-statement, the framework will call Dispose on your SignalR application. This call will stop all the work threads, and your exe will terminate.

The Readline() statement stops the app from reaching the end of the using statement. This means the dispose method is not called until you press enter.

So, for an exe you normally want to use ReadLine the way you do. For a service you want to store a reference to your IDisposable, and call dispose on it in you Stop() method.

like image 42
Mikael Nitell Avatar answered Oct 02 '22 17:10

Mikael Nitell