Getting a Service to Run Inside of an Azure Worker Role - c#

I have a windows service that I need to migrate to onto Azure as a Worker Role. Everything builds fine in my Azure solution. However, when I upload everything only the web role starts. The worker role instance gets stuck cycling between the following two statuses without ever starting.
Waiting for the role to start...
Stabilizing role...
Since the instance is failing to start I suspect my problem lies somewhere in my WorkerRole.cs code. Below you'll find that code. I've also included the code for the service in case it's relevant to the question. What did I do wrong?
This is my WorkerRole.cs file:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using System.ServiceProcess;
namespace SBMWorker
{
public class WorkerRole : RoleEntryPoint
{
public override void Run()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
//Thread.Sleep(Timeout.Infinite);
}
}
}
This is my Service1.cs code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using Lesnikowski.Mail;
namespace SBMWorker
{
public partial class Service1 : ServiceBase
{
private System.Timers.Timer mainTimer;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
// config the timer interval
mainTimer = new System.Timers.Timer(foo.Framework.Configuration.SecondsToWaitBeforeCheckingForEmailsToProcess * 1000);
// handling
mainTimer.Elapsed += new System.Timers.ElapsedEventHandler(mainTimer_Elapsed);
// startup the timer.
mainTimer.Start();
// log that we started
foo.Framework.Log.Add(foo.Framework.Log.Types.info, "SERVICE STARTED");
}
catch (Exception ex)
{
try
{
foo.Framework.Log.Add(ex, true);
}
catch{throw;}
// make sure the throw this so the service show as stopped ... we dont want this service just hanging here like
// its running, but really just doing nothing at all
throw;
}
}
protected override void OnStop()
{
if (mainTimer != null)
{
mainTimer.Stop();
mainTimer = null;
}
// log that we stopped
foo.Framework.Log.Add(foo.Framework.Log.Types.info, "SERVICE STOPPED");
}
void mainTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
mainTimer.Stop();
bool runCode = true;
if (runCode)
{
try
{
// call processing
foo.Framework.EmailPackageUpdating.ProcessEmails();
}
catch(Exception ex)
{
try
{
// handle error
foo.Framework.Log.Add(ex, false);
}
catch { throw; }
}
}
mainTimer.Start();
}
}
}

I think the root of your problem is that you basically can't install a service programmatically in Azure roles. You need to use a .cmd startup script and the InstallUtil to properly install the service then you can start it from the script or from your code (think from the script is often preferred for order-of-execution reasons).
Here's a blog post on how to do it: http://blogs.msdn.com/b/golive/archive/2011/02/11/installing-a-windows-service-in-a-worker-role.aspx
Here's another blog post that takes a little different approach (creating a .Net app that executes the installation, but again as part of the startup script): http://www.bondigeek.com/blog/2011/03/25/runninginstalling-a-windows-service-in-an-azure-web-role/
Hope that helps

Related

SynchronizationContext is null in OnStart method of WindowsService

I am trying to create a background Task for my windows service (it is already installed via InstallUtil.exe) and use SynchronizationContext to send some messages to the main Service thread.
Unfortunately SynchronizationContext.Current is always null on service start.
I've saw some questions around the topic and hints on why SynchronizationContext is null in various scenarios (e.g. in Winforms, WPF apps) but no clue about the Windows services.
How can I resolve this issue?
Below the code:
using Lextm.SharpSnmpLib.Messaging;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SnmpTrapListenerService
{
public partial class SnmpTrapListenerService : ServiceBase
{
public Listener Listener { get; set; }
public CancellationTokenSource CancellationTokenSource { get; set; }
public Task PulseTask { get; set; }
public SynchronizationContext SyncContext { get; set; }
public SnmpTrapListenerService()
{
//Debugging windows service.
Debugger.Launch();
InitializeComponent();
Debug.WriteLine($"Main service threadId: {Thread.CurrentThread.ManagedThreadId}");
}
protected override void OnStart(string[] args)
{
try
{
CancellationTokenSource = new CancellationTokenSource();
SyncContext = SynchronizationContext.Current; //Here I'm getting always null.
PulseTask = new Task(x =>
{
Debug.WriteLine($"Pulse task threadId: {Thread.CurrentThread.ManagedThreadId}");
while (true)
{
var context = (SynchronizationContext)x;
context.Post(new SendOrPostCallback(y => DoSomethingOnServiceMainThread()), null);
Debug.WriteLine($"Alive at {DateTime.Now.ToLongTimeString()}");
Thread.Sleep(5000);
}
}, SyncContext, CancellationTokenSource.Token);
PulseTask.Start();
Listener = new Listener();
Listener.AddBinding(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 162)); //IP address of listener system
Listener.MessageReceived += Listener_MessageReceived;
Listener.StartAsync();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
Debug.WriteLine("Service started");
}
private static void Listener_MessageReceived(object sender, MessageReceivedEventArgs e)
{
File.AppendAllText("servicelog.log", "Version :" + e.Message.Version + "\n");
File.AppendAllText("servicelog.log", "Version :" + e.Message.Scope.Pdu.Variables[4].Data.ToString() + "\n");
}
protected override void OnStop()
{
CancellationTokenSource.Cancel();
Listener.Stop();
Debug.WriteLine("Service stopped");
}
private void DoSomethingOnServiceMainThread()
{
//Some work that needs to be done one Service main thread.
}
}
}
Console and Service applications do not have a default SynchronizationContext. This is because there is no "UI" thread that is pumping messages constantly while the application runs.
The question is why do you need a synchronization context?

Windows Service (in C#) that can call a Python script that runs infinitely?

From what I understand, when you run a Windows Service, it calls 'onStart()' and will say that the service is 'starting' in the task manager until the 'onStart()' method runs through completely, to which it then says "running". I would like to create a thread to start a Bluetooth Advertising Script (written in Python3) that will advertise continuously whenever it is not connected to a device. When I try to create a thread and run the script, the service usually just displays "starting' in the task manager and never actually says "running", because the thread that I call within 'onStart()' to initiate the script never finishes I guess. Is there a way to get the service to start, only starting the thread after it as finished executing the 'onStart()'?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Timers;
using System.Threading;
using System.Security.Permissions;
namespace WindowsService1
{
//--------------------------------------------------------------------------------------------------------------------------------------------------
public partial class Service1 : ServiceBase
{
//-------------------------------------------------------------------------
public Service1() { InitializeComponent(); }
//-------------------------------------------------------------------------
private Boolean _started;
public event System.EventHandler serviceChanged;
Service1 serv = new Service1();
static ThreadStart start = new ThreadStart(Adv_Py_Script);
Thread Adv_Py_ScriptThread = new Thread(start);
//Start_Adv s = new Start_Adv();
//Thread thread1 = new Thread(new ThreadStart(s.Adv_Py_Script));
//-------------------------------------------------------------------------
protected override void OnStart(string[] args)
{
isStarted = true;
Thread.Sleep(5000);
}
//-------------------------------------------------------------------------
protected virtual void onServiceChanged() { serviceChanged?.Invoke(this, EventArgs.Empty); }
//-------------------------------------------------------------------------
public Boolean isStarted
{
get { return _started; }
set
{
_started = value;
onServiceChanged();
}
}
//-------------------------------------------------------------------------
protected override void OnStop()
{
isStarted = false;
serv.killPyThread(Adv_Py_ScriptThread);
base.OnStop();
// wait for threads to stop
Adv_Py_ScriptThread.Join(60);
try
{
string error = "";
// Messaging.SMS.SendSMSTextAsync("5555555555", "Messaging Service stopped on " + System.Net.Dns.GetHostName(), ref error);
}
catch
{
// yes eat exception if text failed
}
}
//-------------------------------------------------------------------------
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
public void killPyThread(Thread thread)
{
thread.Interrupt();
thread.Abort();
}
//-------------------------------------------------------------------------
private static void Adv_Py_Script()
{
string fileName = #"C:\Users\bakere1\A19149\Projects\BLE_Advertiser.py";
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"C:\Python36_64\python.exe", fileName)
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
p.Start();
}
}
While there might be other problems, the first one is that the Local Service account that your service (probably) runs as doesn't have permissions to the location C:\Users\bakere1\A19149\Projects\
If you change the "Run As" account to something with permissions, you'll get farther. I'm not a big python geek, but if your py app requires any sort of user I/O it will fail, since there is no console session assigned to it.
Also, if you have roaming profiles, the service gets started at before the user folder is available, so it will hang or fail.

How to start a process/application on windows connection change event using C#

I can detect the network connection change event while running a C# code, how would I register an exe when Windows detects this event. What all details would I need. Below is how I am using this :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.NetworkInformation;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
testing t = new testing();
Console.Read();
}
}
public class testing{
public testing()
{
NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
}
void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
if (e.IsAvailable)
{
Console.WriteLine("network is available");
}
}
}
}
What you could maybe do is in your method that is triggered to start a new process and execute your exe

What's wrong my windows service on windows 2012?

I have written multiple windows services in one exe & created setup/deployment package to install on destination server (windows 2012). I can see all services in Services & able to start them but it is not performing required action..Weird!!
Program.cs
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new service1(),
new service2(),
new service3()
};
ServiceBase.Run(ServicesToRun);
service1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Configuration;
using System.Net;
using System.Xml;
using System.IO;
namespace MyService
{
partial class service1: ServiceBase
{
public service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
StreamWriter str = new StreamWriter("D:\\temp\\Text1.txt", true);
str.WriteLine("text");
str.Close();
try
{
//more functionality
EventLog.WriteEntry("done", "done desc", EventLogEntryType.Information);
}
}
catch (Exception ex)
{
EventLog.WriteEntry("Error", ex.Message, EventLogEntryType.Error);
}
}
protected override void OnStop()
{
base.OnStop();
}
}
}
When I start service1 manually, it doesn't perform any action..Neither I see text file getting created nor any error/info in event log. What's wrong? Am I missing something wrong???
Appreciate for help!

Windows Service Issue in C#

I have designed a window service in which I called RunProgram Method from OnStart().. But when I install its pakage it is not showing in service console.... Any suggestions are most welcome....
protected override void OnStart(string[] args)
{
base.OnStart(args);
rd = new Thread(new ThreadStart(RunProgram));
rd.Start();
}
my Installer class is as follows....
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Management;
using System.ServiceProcess;
using System.Linq;
namespace WindowsService1
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
}
public System.ServiceProcess.ServiceController serviceController = new ServiceController();
private void ProjectInstaller_Committed(object sender, InstallEventArgs e)
{
serviceController.ServiceName = "MyTestingService";
ConnectionOptions coOptions = new ConnectionOptions();
coOptions.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope mgmtScope = new System.Management.ManagementScope(#"root\CIMV2", coOptions);
mgmtScope.Connect();
ManagementObject wmiService;
wmiService = new ManagementObject("Win32_Service.Name='" + this.serviceController.ServiceName + "'");
ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
InParam["DesktopInteract"] = true;
ManagementBaseObject OutParam = wmiService.InvokeMethod("Change", InParam, null);
this.serviceController.Start();
}
}
}
My Service Class is as follows....
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.IO;
using System.Web;
using System.Threading;
namespace WindowsService1
{
public partial class MyTestingService : ServiceBase
{
public MyTestingService()
{
InitializeComponent();
}
System.Threading.Thread rd;
protected override void OnStart(string[] args)
{
base.OnStart(args);
rd = new Thread(new ThreadStart(RunProgram));
rd.Start();
}
protected override void OnStop()
{
}
public void RunProgram()
{
//My Code to do here
}
}
}
Have you any logging file? Maybe there is some error in your webservice. You can debug your webservice too.
static void Main()
{
#if (!DEBUG)
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new Service1Component() };
ServiceBase.Run(ServicesToRun);
#else
Service1Component s = new Service1Component();
s.RunProgram();
#endif
}
P.s. s.RunProgram() is your method that you can use it for debug.
have you tried this?
http://msdn.microsoft.com/en-us/library/zt39148a.aspx
I remember that in old services prior to .NET you shoud also register the service installing it
The installer had a specific key, smth like "autoregister"
Once you have your service built, you have to run the following command from a Visual Studio Command Propt:
installutil [/u[ninstall]] [options] assembly [[options] assembly] ...
Full info here
Please cross check whether you have done the following steps:
1.After creating the windows service project go to the service class's design view(just double click the service1.cs class).
2.In the design view right click and select Add Installer. This will create an Installer class named ProjectInstaller.cs. With out ProjectInstaller.cs or any error in configuring ProjectInstaller.cs may result in non-showing of the service in service console.
3.Go to the design view of ProjectInstaller.cs you will find two installers there->
a.**ServiceInstaller1**
b.**ServiceProcessInstaller1**
4.Right click ServiceInstaller1 and go to the properties tab
a.Edit the ServiceName with the name you want to
see your service in the service console.
b.Change the **StartType** to **Automatic**.
5.Right click ServiceProcessInstaller1 and go to the properties tab
a.Change the account to **LocalService**
6. Save and try it.
Hope this will help you........

Categories