How do I use "StartService" Task with ThreadStart? - c#

How do I use "StartService" Task with ThreadStart?
Is it possible?
public partial class MyService : ServiceBase
{
public MyService()
{
InitializeComponent();
LocalInit();
}
internal void LocalInit()
{
//place here any local checks
}
protected override void OnStart(string[] args)
{
if (Something.ConfigOK())
{
ThreadStart threadDelegate = Something.StartService; // Expected a method with void StartService signature
var newThread = new Thread(threadDelegate);
newThread.Start();
}
else
{
//log error
throw new Exception("MyService : Config failed");
}
}
}
public static partial class Something
{
public static async Task StartService()
{
await DoJob();
}
}
Errors
Error CS0407 'Task Something.StartService()' has the wrong return type
Expected a method with void StartService signature

Have you tried this?
protected override void OnStart(string[] args)
{
if (Something.ConfigOK())
{
Something.StartService();
}
else
{
//log error
throw new Exception("MyService : Config failed");
}
}
If DoJob os truly asynchronous or:
protected override void OnStart(string[] args)
{
if (Something.ConfigOK())
{
Task.Run(Something.StartService);
}
else
{
//log error
throw new Exception("MyService : Config failed");
}
}
if it isn't (blocking).
There's no need to explicitly create a thread.
Beware of exception handling!
But, since you mention ASP.NET Core (???) I would recomend using a Worker template.

It is possible, but I would suggest you to go with Background tasks with hosted services.
Here is some implementation
Or use hangfire queues.
As I mentioned, this is a suggestion not a answer for your question.

Related

Building Windows Service in C# with periodic task [duplicate]

This question already has answers here:
Better way to constantly run function periodically in C#
(3 answers)
Closed 2 years ago.
Id like to build a windows Service in C#.
This service needs to be run periodically like every 10s.
Questions:
What is the difference between Timers.timer and Threading.timer?
How can I call CheckingThings with parameters?
If i run this code, it does invoke CheckingThings more than once every second like declared in here:
_timer = new Timer(new TimerCallback(CheckingThings), autoEvent, 5000, 1000);
Here is what i've got so far:
public partial class WindowsService1 : ServiceBase
{
// Logging
private static Serilog.Core.Logger _logEvent;
public WindowsService1()
{
InitializeComponent();
}
public void OnDebug() {
OnStart(null);
}
protected override void OnStart(string[] args)
{
//Logging
try {
_logEvent = new LoggerConfiguration()
.WriteTo.File(AppDomain.CurrentDomain.BaseDirectory + #"Logs\Logfile.txt", rollingInterval: RollingInterval.Month)
.CreateLogger();
}
catch (Exception e)
{
_logEvent.Error("The logging service is not working as expected: {errorMsg}", e);
}
try
{
// initializing some data here
var autoEvent = new AutoResetEvent(true);
while (true)
{
_timer = new Timer(new TimerCallback(CheckingThings), autoEvent, 5000, 1000);
}
}
catch (Exception e) {
_logEvent.Error("An error occured while initializing service: {0}", e);
}
}
private static void CheckingThings(object stateInfo)
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
//These things needs to run periodically every 10s
}
protected override void OnStop()
{
_logEvent.Information("Stopping Service ...");
}
}
Here's a skeleton for a service class that does something every minute, using a System.Timers.Timer:
public partial class XService : ServiceBase
{
private Timer _minute = new Timer(60000);
public XService()
{
InitializeComponent();
_minute.Elapsed += Minute_Elapsed;
}
//this is async because my 'stuff' is async
private async void Minute_Elapsed(object sender, ElapsedEventArgs e)
{
_minute.Stop();
try
{
//stuff
}
catch (Exception ex)
{
//log ?
}
finally
{
_minute.Start();
}
}
protected override void OnStart(string[] args)
{
_minute.Start(); //this or..
Minute_Elapsed(null, null); //..this, if you want to do the things as soon as the service starts (otherwise the first tick will be a minute after start is called
}
...
I typically stop my timers while I do my thing - no point starting a job that takes 10 minutes and then another one a minute later, hence the stop/try/finally/start pattern
Edit:
Here's the tail part of the class and how it's started/launched both in debug (inside visual studio) and in release (as an installed windows service):
//just an adapter method so we can call OnStart like the service manager does, in a debugging context
public void PubOnStop()
{
OnStop();
}
}// end of XService class
static void Main(string[] args)
{
#if DEBUG
new XService().PubStart(args);
Thread.Sleep(Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new XService()
};
ServiceBase.Run(ServicesToRun);
#endif
}

Suggested pattern for gracefully restart cancelled async Tasks on non UI application

I have a console app that instantiates a WeatherClientManager class.
The main thread in the console app requests current weather status in the WeatherClientManager class, but the WeatherClientManager class continuously receives data from a server.
In code:
public static void Main(string [])
{
Program p = new Program();
Task.Run(()=>p.RunLoop());
}
class Program{
WeatherClientManager wcM;
public void RunLoop()
{
wcM = new WeatherClientManager ();
await wcM.InitiateConnection().ConfigureAwait(false);
}
}
class WeatherClientManager
{
public async Task<bool> InitiateConnection()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync()
CancellationTokenSource cts = new CancellationTokenSource();
if(tcpClient.Connected)
{
Task.Run(()=>ReceiveTask(cts.Token));
Task.Run(()=>SendKeepAlive(cts.Token));
return true;
}
return false;
}
private void ReceiveTask(CancellationToken t)
{
try{
networkStream.Receive(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
private void SendKeepAlive(CancellationToken t)
{
while(!t.IsCancellationRequested)
{
try{
networkStream.Write(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
}
private void Stop(Exception e )
{
log.Error(e);
e.Cancel();
}
}
One of many crap ideas I have is:
Task.Run( () =>
{
while(true)
{
var t1 = Task.Run(()=>ReceiveTask(cts.Token));
var t2= Task.Run(()=>SendKeepAlive(cts.Token));
try{
Tasks.WhenAny(); // should block
}
catch(Exception e)
{
}
finally{
Cleanup();
InitiateConnections();
}
}
}
But I hate the idea of spinning a task to control two sub tasks. My problem is where and how to re-initiate the connection. Any ideas?
EDIT:
I've updated the code such that WeatherClientManager has a OnDisconnectDetected event. So the Program.cs class subscribes like so:
weatherServerManager.OnDisconnectDetected += HandleDisconnectDetection
public async void HandleDisconnectDetection()
{
wsM = new WeatherClientManager ();
wsM.InitiateConnection().ConfigureAwait(false);
}
private void SendKeepAlive(CancellationToken t)
{
while (...)
{
try{}
catch(Exception e)
{
OnDisconnectDetected?.Invoke();
}
}
}
When the handler is invoked by the WeatherClientManager it creates a new task that should continue in a different context. The KeepAlive task should exit then.
Still feels hacky but ideas welcome!
As a general rule, I prefer composition of methods over raising events. In particular, avoid the Task.Run-based fire-and-forget.
In the case of asynchronous sockets, I think it makes sense to give each socket a main loop:
class WeatherClientManager
{
public async Task MainLoop()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync();
CancellationTokenSource cts = new CancellationTokenSource();
var receiveTask = Task.Run(()=>ReceiveTask(cts.Token));
var keepaliveTask = Task.Run(()=>SendKeepAlive(cts.Token));
await Task.WhenAll(receiveTask, keepaliveTask);
}
}
These can then be composed into the main program's main loop:
class Program
{
public async Task RunLoop()
{
while (true)
{
wcM = new WeatherClientManager();
await wcM.MainLoop();
}
}
}
which in turn is composed into Main:
public static void Main(string [])
{
Program p = new Program();
p.RunLoop().GetAwaiter().GetResult();
}
By avoiding fire-and-forget, you're ensuring that your code will always observe all exceptions. Ignoring tasks is occasionally okay but usually a mistake.

Catching exceptions from async methods (in a Caliburn.Micro context with MEF loaded assemblies)

I have a Caliburn.Micro application that is set up to use MEF.
In the ViewModel that is first loaded, I loop through classes (interfaces) from various assemblies that have been loaded by MEF.
In one of these classes there is a method defined as an async task:
private async Task SomeAsyncMethod()
If this method throws an exception it is never caught by the override of OnUnhandledException in the bootstrapper, or anywhere else.
How do I define a global exception handler to catch this exception?
AppBootstrapper.cs
Implemented as described here: https://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper
Plus addition of the folder containing the additional assemblies to be loaded to the Configure override, and adding OnUnhandledException
protected override void Configure()
{
AggregateCatalog aggregateCatalog = new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());
aggregateCatalog.Catalogs.Add(new DirectoryCatalog(ConfigurationManager.AppSettings["ExternalComponents"]));
_container = new CompositionContainer(aggregateCatalog);
CompositionBatch batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(_container);
_container.Compose(batch);
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
protected override void OnUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
// Exceptions from async methods are not caught here
MyLogger.Error(e.Exception, "Unhandled exception");
e.Handled = true;
}
Main view model
public class MainViewModel : IShell
{
[ImportMany]
private IEnumerable<IMyMefClass> _myMefClasses;
protected override void OnViewLoaded(object view)
{
foreach (IMyMefClass instance in _myMefClasses)
{
instance.Start();
}
}
}
MEF loaded class with async method
[Export(typeof(IMyMefClass))]
public class MyMefClassImplementation : IMyMefClass
{
public void Start()
{
SomeAsyncMethod();
}
private async Task SomeAsyncMethod()
{
throw new Exception("This is never caught");
}
}
The question is still, as above, how do I define a global exception handler to catch this exception?
Another solution, juste rewrite your OnViewLoaded method:
protected override void OnViewLoaded(object view)
{
var runningTasks = _myMefClasses.Select(m=>m.Start()).ToArray();
try
{
Task.WaitAll(runningTasks);
}
catch(AggregateException ex)
{
//Any exception raised by a task will be in ex.InnerExceptions
}
}
This solution also has the advantage of letting all tasks run in parallel.
Most simple solution:
public class MyMefClassImplementation : IMyMefClass
{
public void Start()
{
try
{
await SomeAsyncMethod();
} catch(Exception ex) {
throw ex
}
}
// ...
}

Self-install of WInService

I've googled this one
but when i'm trying to apply it i get an error. So install/uninstall works fine, but service itself just doesn't start and after timeout it says that service doesn't respond. I don't know why. When i'm attaching to process it even doesn't enter into Main() method, static constructors and so on. I've used this addon for attach.
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += OnException;
if (Environment.UserInteractive)
{
AskUserForInstall();
}
else
{
ServiceBase.Run(new NotificatorService());
}
}
Service is also very simple:
using System.ServiceProcess;
using System.Windows;
namespace AZNotificator
{
public partial class NotificatorService : ServiceBase
{
static NotificatorService()
{
int x = 5;
}
public NotificatorService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
MessageBox.Show("Hello");
}
protected override void OnStop()
{
}
}
}
You can not call MessageBox.Show("Hello"); from the windows service since the service does not have the GUI.
If you want to do some interaction from the windows service have a look at this article
http://msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx
So remove MessageBox.Show("Hello"); from your OnStart method and your service should start just fine.

Windows Service + read from database

I am new To windows service. I need a windows service that reads an entry from a table from database. I have a CONSOLE APP where I add new project WINDOWS SERVICE. I already have a method that access the database, and other methods. I can put a thread on start that reads the database. Where do I put the thread? ( how can I do that). Where on WINDOWS SERVICE I add those methods? I have the Windows Service like this:
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
do
{
thread.start();
bool variab = readFromDatabase (Database table);
}
}
protected override void OnStop()
{
}
I suggest that you create a class in which you do everything you need and create in in the service:
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
YourClass cl = new YourClass();
cl.DoWhatYouNeed(...);
}
protected override void OnStop()
{
}
This gives you opportunity to run and test your class separate from service, maybe during debug release.
With windows services usually a method is created to execute the main loop of the service, in a separated thread. Otherwise the service could become unresponsive. For example, you can have a method called MainLoop to execute the service logic. Use the OnStart method only to do the initializing tasks, such as read configuration values or start the threads of the service. And use the OnStop to executing cleaning tasks, stopping threads, etc...
Thread _workerThread;
bool _shouldStop;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try{
_workerThread = new Thread(new ThreadStart(MainLoop));
_shouldStop = false;
_workerThread.Start();
}
catch{}
}
private void MainLoop()
{
while (!_shouldStop)
{
try{
//your logic here
}
catch{}
}
}
protected override void OnStop()
{
_shouldStop = true;
}
You must put your code or class, which contain data access logic in OnStart method

Categories

Resources