Self-Hosted SignalR service won't work (start) - c#

I have SignalR server as Class Library Project and i referenced it in Console application (to simulate Windows service)
Here is code for SignalR
public void Start()
{
try
{
string url = #"http://*:8081";
using (WebApp.Start<Startup>(url))
{
Logger.Info(string.Format("Server running at {0}", url));
}
}
catch (Exception ex)
{
Logger.Exception(ex, "Signalr start");
}
Run = true;
Logger.Info("Starting Worker");
workerThread = new Thread(() =>
{
Worker();
});
workerThread.Start();
}
And here is Startup class
public class Startup
{
Microsoft.AspNet.SignalR.HubConfiguration hubconfiguration = null;
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
hubconfiguration = new HubConfiguration();
hubconfiguration.EnableDetailedErrors = true;
app.MapSignalR(hubconfiguration);
}
}
So, it is in one thread, and worker is in another. That seems fine since i did it in other project where it works. Worker thread isn't problem, it's just empty loop, not related to server in any way.
Problem is that server seems to "stop" - when i look with Netstat, nobody is listening on port 8081. There is no exception, it just silently fails.
I referenced Owin.Cors (and Owin.Host.HttpListener) in console project that actually runs this server but as I said, server just stops.
When I try to connect, client says "connection actively refused" and Putty (telnet) also says "can't connect".
Where is the problem? In a nutshell, i have Class Library with SignalR server that is referenced in Console project that runs it but server just wont work.
[edit]
And there is code of Console app that starts service
static void Main(string[] args)
{
ServiceEngine Engine = new ServiceEngine();
Engine.Start();
Console.ReadKey();
Engine.Stop();
}
P.S. Sorry for my bad English.

Well, i solved it. Here was a problem:
public static void Start()
{
try
{
string url = #"http://127.0.0.1:8081";
WebApp.Start<Startup>(url);
Logger.Info(string.Format("Server running at {0}", url));
}
catch (Exception ex)
{
Logger.Exception(ex, "signalr start");
}
Run = true;
Logger.Info("Starting Worker");
workerThread = new Thread(() =>
{
Worker();
});
workerThread.Start();
}
As you can see, using statement was removed and now it works fine! Interesting note - you can also make Singleton implementation of this "Engine", and it will also work.

I got Solution after doing lot of R & D. And Its a Simple change related to Account and Access Rights.
Use LocalSystem Account instead of LocalService Account in Service Installer.
You can do this either from doing below change in design view of your service installer:
Properties of Service Process Installer -> Set Account to LocalSystem.
or by doing below change in in designer.cs file of your service installer:
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;

Related

Handle network issues when wi-fi is switched off

I am testing .NET version of gRPC to understand how to handle network failures. I put the server to one external machine and debugging the client. The server ticks with a message onnce a second and the client just shows it on the console. So when I stop my local Wi-Fi connection for seconds, then gRPC engine automatically recovers and I even get remaining values. However, if I disable Wi-Fi for longer time like a minute, then it just gets stuck. I don't even get any exceptions so that I can just handle this case and recover manually. This scenario works fine when I close the server app manually, then an exception will occur on the client. This is what I have on the client:
static async Task Main(string[] args)
{
try
{
await Subscribe();
}
catch (Exception)
{
Console.WriteLine("Fail");
Thread.Sleep(1000);
await Main(args);
}
Console.ReadLine();
}
private static async Task Subscribe()
{
using var channel = GrpcChannel.ForAddress("http://x.x.x.x:5555");
var client = new Greeter.GreeterClient(channel);
var replies = client.GerReplies(new HelloRequest { Message = "Test" });
while (await replies.ResponseStream.MoveNext(CancellationToken.None))
{
Console.WriteLine(replies.ResponseStream.Current.Message);
}
Console.WriteLine("Completed");
}
This works when the server app stopped but it doesn't work if I just disable loca Wi-Fi connection on the client side. How can I handle such a case and similar ones?
I've managed to solve it by KeepAlivePingDelay setting:
var handler = new SocketsHttpHandler
{
KeepAlivePingDelay = TimeSpan.FromSeconds(5),
KeepAlivePingTimeout = TimeSpan.FromSeconds(5),
};
using var channel = GrpcChannel.ForAddress("http://x.x.x.x:5555", new GrpcChannelOptions
{
HttpHandler = handler
});
This configuration force gRPC fail after 10 seconds in case of no connection.

How to Restart self hosted Signalr

I'm using
WebApp.Start<Startup>(url)
to host Signalr hub in windows service. For some reason my hub doesn't accept connection after 2-3 day of running, How i can detect it's unresponsiveness and restart it?
First of all, you should find a reason why your Windows Service crashes. Write logs for events, use try catch block and write every error to eventlog.
What about control your Windows Service: have a look ServiceController class
Add such like a method:
public void StartService()
{
using (ServiceController service = new ServiceController(serviceName))
{
try
{
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running);
}
catch (Exception ex)
{
throw new Exception($"Can not Start the Windows Service [{serviceName}]", ex);
}
}
}
public void StartOrRestart()
{
if (IsRunningStatus)
RestartService();
else if (IsStoppedStatus)
StartService();
}
UPDATE:
If you have problems only with Hub then try to start it from clients such:
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.you can set the time based your requirement
});
Feel free to add comments with more information from you issue

Get Address Already In Use exception. self hosted wcf service

I found numerous questions about this issue : here, here, here, and here, But could not solve my problem.
Background:
We have an existing unmanaged application that launches a managed winforms application.
There is a shared managed assembly which exposes comvisible objects for the unmanaged app and that assembly launches the managed app.
So the ServiceHost runs on the winforms app and the client on that shared assembly. The setup is similar to this implementation .
The application runs on a approx. 100 pcs, win xp or win 7.
The problem:
once in a few days we get :
System.ServiceModel.AddressAlreadyInUseException when trying to launch the winforms application.
we ran netstat but could not find anything listening on that port.
The only 'solution' is rebooting the pc.
I could not reproduce this problem on my dev machine. but it happens on production environment once in a while.
Code:
Code is being typed hopefully without typos, can not copy paste :
Service config (found in winform appconfig):
<system.ServiceModel>
.
.
<services>
<service name="MyService">
<endpoint address="net.tcp://localhost:4444" binding="netTcpBinding"
contract="IMyService"/>
</service>
</services>
.
.
<\system.ServiceModel>
Service
StartService() is called from mainform_Load
private static void StartService()
{
try
{
_serviceHost = new ServiceHost(typeof(MyService));
_serviceHost.Open();
}
catch(Exception ex)
{
LogError(ex);
ExitApp();
}
}
private static void ExitApp()
{
try
{
_serviceHost.Close();
}
catch(CommunicationException cex)
{
LogError(cex);
_serviceHost.Abort();
}
finally
{
Application.Exit();
}
}
Client
private static void CallMyService()
{
var channelFactory = new ChannelFactory<IMyService>("net.tcp://localhost:4444");
IMyService myChannel= channelFactory.CreateChannel();
bool error = true;
try
{
myChannel.PerformOperation();
((IClientChannel)myChannel).Close();
error = false;
}
finally
{
if (error)
{
((IClientChannel)myChannel).Abort();
}
}
}
I hope i am clear enough, thanks.
We solved this issue back in 2015, i am sharing the answer now:
Since the communication between the processes is on the same machine, we used NetNamedPipeBinding instead of NetTcpBinding and we got no more System.ServiceModel.AddressAlreadyInUseException exceptions.
The setup is like the following (actual code is a bit different):
Service :
private static void StartService()
{
try
{
string address = "net.pipe://localhost/MyApp/NamedPipeBindingHost";
_serviceHost = new ServiceHost(typeof(MyService));
NetNamedPipeBinding b = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
_serviceHost.Open();
b.OpenTimeout = TimeSpan.FromMinutes(2);
b.closeTimeout = TimeSpan.FromMinutes(1);
b.ReceiveTimeout = TimeSpan.FromMinutes(10);
_serviceHost.AddServiceEndpoint(typeOf(IMyService), b, address);
_serviceHost.Open();
}
catch(Exception ex)
{
LogError(ex);
ExitApp();
}
}
private static void ExitApp()
{
try
{
_serviceHost.Close();
}
catch(CommunicationException cex)
{
LogError(cex);
_serviceHost.Abort();
}
finally
{
Application.Exit();
}
}
Client :
private static void CallMyService()
{
string address = "net.pipe://localhost/MyApp/NamedPipeBindingHost";
EndpointAddress ep = new EndpointAddress(adress);
var channelFactory = new ChannelFactory<IMyService>(GetNamedPipeBindings(), ep);
IMyService myChannel= channelFactory.CreateChannel();
bool error = true;
try
{
myChannel.PerformOperation();
((IClientChannel)myChannel).Close();
error = false;
}
finally
{
if (error)
{
((IClientChannel)myChannel).Abort();
}
}
}
private NamedPipeBinding GetNamedPipeBindings()
{
NamedPipeBinding binding = new NamedPipeBinding (NetNamedPipeSecurityMode.None);
binding.OpenTimeout = TimeSpan.FromMinutes(2);
b.closeTimeout = TimeSpan.FromMinutes(1);
b.SendTimeout = TimeSpan.FromMinutes(10);
return binding;
}
Something I noticed that helped in my machine: somehow IIS Express generated multiple addresses with that same port when I was configuring the project, and tried to launch all of them during testing causing this failure.
The error would also appear via a popup from the IIS Express taskbar icon. I navigated to its config file ("User Documents\IISExpress\config\applicationhost.config"), removed all 'site' nodes that contained virtual directory bindings to those addresses, saved and re-tried again and it worked.
Hope this works for you?

Windows Service stuck on "starting" status as local system account

I developed a http server via console application in C# and decided to turn it into a Windows service to be able to initialize it without the need to login the machine.
I followed all the steps in How to create Windows Service and chose the account as "Local System", but when I install in my server machine and push the start button it takes a while and gives the following error:
Erro 1053: The service did not respond to the start or control request in timely fashion.
After that, the service status stays stuck in "starting" and the application don't work and I can't even stop the service anymore.
Trying to work around this problem, I changed it to "Network Service", so it started normally, but the application was not listening in the port I set when I checked in the prompt with the command "netstat -an". But the application listens normally if i run it as a console application.
So I am looking for an answer to one of these two questions:
What should I do to make the service starts properly with a Local System account?
If I decide to use Network service account, what should I care about to guarantee that my service works properly as a server?
When I converted my console application to windows service I simply put my code directly in the OnStart method. However, I realized the OnStart method should start the service, but needs to end some time to the service indeed start. So I created a thread that runs my service and let the OnStart method finish. I tested and the service worked just fine. Here is how it was the code:
protected override void OnStart(string[] args)
{
Listener(); // this method never returns
}
Here is how it worked:
protected override void OnStart(string[] args)
{
Thread t = new Thread(new ThreadStart(Listener));
t.Start();
}
But I still don't understand why the service ran (passed the "starting" status, but didn't work) when I used network service account. If anyone knows, I'll be glad to know the reason.
If you have a service that is not responding or showing pending in Windows services that you are unable to stop, use the following directions to force the service to stop.
Start -> Run or Start -> type services.msc and press Enter
Look for the service and check the Properties and identify its service name
Once found, open a command prompt. Type sc queryex [servicename]
Identify the PID (process ID)
In the same command prompt type taskkill /pid [pid number] /f
Find PID of Service
sc queryex <SERVICE_NAME>
Give result's below
SERVICE_NAME: Foo.Services.Bar TYPE : 10 WIN32_OWN_PROCESS STATE : 2 0 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 PID : 3976 FLAGS :
Now Kill the Service:
taskkill /f /pid 3976
SUCESS: The process with PID 3976 has been terminated.
Check the Windows Application event log, it could contain some entries from your service's auto generated event source (which should have the same name of the service).
For me it was a while loop that looked at an external queue. The while-loop continued running until the queue was empty. Solved it by calling a timer event directly only when Environment.UserInteractive. Therefore the service could be debugged easily but when running as a service it would wait for the timers ElapsedEventHandler event.
Service:
partial class IntegrationService : ServiceBase
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private System.Timers.Timer timer;
public IntegrationService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
// Add code here to start your service.
logger.Info($"Starting IntegrationService");
var updateIntervalString = ConfigurationManager.AppSettings["UpdateInterval"];
var updateInterval = 60000;
Int32.TryParse(updateIntervalString, out updateInterval);
var projectHost = ConfigurationManager.AppSettings["ProjectIntegrationServiceHost"];
var projectIntegrationApiService = new ProjectIntegrationApiService(new Uri(projectHost));
var projectDbContext = new ProjectDbContext();
var projectIntegrationService = new ProjectIntegrationService(projectIntegrationApiService, projectDbContext);
timer = new System.Timers.Timer();
timer.AutoReset = true;
var integrationProcessor = new IntegrationProcessor(updateInterval, projectIntegrationService, timer);
timer.Start();
}
catch (Exception e)
{
logger.Fatal(e);
}
}
protected override void OnStop()
{
try
{
// Add code here to perform any tear-down necessary to stop your service.
timer.Enabled = false;
timer.Dispose();
timer = null;
}
catch (Exception e)
{
logger.Fatal(e);
}
}
}
Processor:
public class IntegrationProcessor
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
private static volatile bool _workerIsRunning;
private int _updateInterval;
private ProjectIntegrationService _projectIntegrationService;
public IntegrationProcessor(int updateInterval, ProjectIntegrationService projectIntegrationService, Timer timer)
{
_updateInterval = updateInterval;
_projectIntegrationService = projectIntegrationService;
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = _updateInterval;
//Don't wait for first elapsed time - Should not be used when running as a service due to that Starting will hang up until the queue is empty
if (Environment.UserInteractive)
{
OnTimedEvent(null, null);
}
_workerIsRunning = false;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
try
{
if (_workerIsRunning == false)
{
_workerIsRunning = true;
ProjectInformationToGet infoToGet = null;
_logger.Info($"Started looking for information to get");
//Run until queue is empty
while ((infoToGet = _projectIntegrationService.GetInformationToGet()) != null)
{
//Set debugger on logger below to control how many cycles the service should run while debugging.
var watch = System.Diagnostics.Stopwatch.StartNew();
_logger.Info($"Started Stopwatch");
_logger.Info($"Found new information, updating values");
_projectIntegrationService.AddOrUpdateNewInformation(infoToGet);
_logger.Info($"Completed updating values");
watch.Stop();
_logger.Info($"Stopwatch stopped. Elapsed seconds: {watch.ElapsedMilliseconds / 1000}. " +
$"Name queue items: {infoToGet.NameQueueItems.Count} " +
$"Case queue items: {infoToGet.CaseQueueItems.Count} " +
$"Fee calculation queue items: {infoToGet.FeeCalculationQueueItems.Count} " +
$"Updated foreign keys: {infoToGet.ShouldUpdateKeys}");
}
_logger.Info($"Nothing more to get from integration service right now");
_workerIsRunning = false;
}
else
{
_logger.Info($"Worker is already running! Will check back again after {_updateInterval / 1000} seconds");
}
}
catch (DbEntityValidationException exception)
{
var newException = new FormattedDbEntityValidationException(exception);
HandelException(newException);
throw newException;
}
catch (Exception exception)
{
HandelException(exception);
//If an exception occurs when running as a service, the service will restart and run again
if (Environment.UserInteractive)
{
throw;
}
}
}
private void HandelException(Exception exception)
{
_logger.Fatal(exception);
_workerIsRunning = false;
}
}
You can try to increase the windows service timeout with a key in the registry
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
"ServicesPipeTimeout"=dword:300000 (300 seconds or 5 minutes)
If it doesn't exists it has to be created.

C# custom service does not start on 2008 Server

I've build a little service (c# ,net 4). After a few tests and tuning on dev environment i've tried it on my own pc. All is working fine.
When I install the service on a windows 2008 R2 server (production environment) it won't start giving me a 1053 error (Service does not start in a timely fashion time)
tTe weird is that I get this error suddenly, as I start the service, just after a second or two.
I've added the option this.RequireMoreTime(120000) to my service, and I've edited the registry key of ServicePipelineMode.
Some more info:
I'm using Log4net to log events in the Application log.
I use a custom source (created using a powershell command)
The service is set to run under Network Service Account, Starting it with an administrative account get same results
I've put every part under Try - catch using log.error(exception.tostring()) but nothing is logged in event log.
I've read lot of posts on the web bbut nothing helps me to fix.
Dev and server has the same framework:
Any help would be appreciated.
Many thanks in advance.
Edit:
I've tried to add a try-catch on program.cs, the start point of my project:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
try
{
if (!EventLog.SourceExists("CheckMail"))
{
EventLog.CreateEventSource("CheckMail", "Application");
EventLog.WriteEntry("EventSystem", "EventSource created");
}
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new CheckMailSvc() };
ServiceBase.Run(ServicesToRun);
}
catch (Exception ex)
{
string message = string.Format("Error starting Service {0}", ex.ToString());
EventLog.WriteEntry("CheckMail", message, EventLogEntryType.Warning, 666);
}
}
}
nothing is trapped (neither rhe EventSource create event or an exception)
All other code is in try-catch, using log4net to log events (and in dev environment it works fine).
Thanks for your suggestions.
My OnStart is this:
protected override void OnStart(string[] args)
{
try
{
this.RequestAdditionalTime(30000);
ServiceStart = DateTime.Now;
XmlConfigurator.Configure();
log4net.ThreadContext.Properties["EventID"] = 666;
log.Info("Service Started");
StringBuilder sb = new StringBuilder();
sb.AppendLine("Service Configuration:");
log.Info(sb.ToString());
Timer t = new Timer(new TimerCallback(SendMail));
t.Change(TimeSpan.Zero, TimeSpan.FromMinutes(every));
}
catch (Exception ex)
{
log.ErrorFormat("Error starting service: {0}", ex.ToString());
}
}
As you can see nothing strange happens, and I should see a starting message in Application log.

Categories

Resources