I need to publish some data to the service from the C# web application. The data itself is collected when user uses the application (a kind of usage statistics). I don't want to send data to the service during each user's request, I would rather collect the data in the app and send then all the data in a single request in a separate thread, that does not serve the users requests (I mean user does not have to wait for the request to be processed by the service). For this purpose I need a kind of JS's setInterval
analog - the launch of the function each X seconds to flush all collected data to the service.
I found out that Timer
class provides somewhat similar (Elapsed
event). However, this allows to run the method only once, but that's not a big issue. The main difficulty with it is that it requires the signature
void MethodName(object e, ElapsedEventArgs args)
while I would like to launch the async method, that will call the web-service (input parameters are not important):
async Task MethodName(object e, ElapsedEventArgs args)
Could anyone advise how to solve the described task? Any tips appreciated.
If a method is declared async, make sure there is an await! If your code does not have an await in its body, the compiler will generate a warning but the state machine will be created nevertheless, adding unnecessary overhead for an operation that will actually never yield.
The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.
The await operator suspends the evaluation of the enclosing async method until the asynchronous operation completes. When the asynchronous operation finishes, the await operator returns the result of the operation, if any. If the async method does not contain an await operator, the method executes synchronously.
The async
equivalent is a while
loop with Task.Delay
(which internally uses a System.Threading.Timer
):
public async Task PeriodicFooAsync(TimeSpan interval, CancellationToken cancellationToken) { while (true) { await FooAsync(); await Task.Delay(interval, cancellationToken) } }
It's important to pass a CancellationToken
so you can stop that operation when you want (e.g. when you shut down your application).
Now, while this is relevant for .Net in general, in ASP.Net it's dangerous to do any kind of fire and forget. There are several solution for this (like HangFire), some are documented in Fire and Forget on ASP.NET by Stephen Cleary others in How to run Background Tasks in ASP.NET by Scott Hanselman
The simple way of doing this is using Tasks and a simple loop:
public async Task StartTimer(CancellationToken cancellationToken) { await Task.Run(async () => { while (true) { DoSomething(); await Task.Delay(10000, cancellationToken); if (cancellationToken.IsCancellationRequested) break; } }); }
When you want to stop the thread just abort the token:
cancellationToken.Cancel();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With