I have a class with an async method:
public static async Task GetData() { ... }
In the app framework I am using I need to start that process and forget about it when the app starts:
protected override void OnStart()
{
await MyService.GetData();
}
I can't make OnStart async. How do I start it in a background task and forget about it?
I can't make OnStart Async. How do I start it in a background task and
forget about it?
Why not? Nothing prevents you from making it async. The async modifier doesn't affect the CLR method signature, i.e., you can override a void method and make it async:
abstract class AppBase
{
protected abstract void OnStart();
}
class App: AppBase
{
public static async Task GetData() { await Task.Delay(1); }
protected override async void OnStart()
{
await GetData();
}
}
This way, at least you'll see an exception if GetData throws, unlike what the other answer suggests.
Make sure you understand how async void methods and Task error handling work in general, this material may be helpful.
Some other problems with Task.Run( () => MyService.GetData() ):
as GetData is already asynchronous, there's very little sense in wrapping it with Task.Run. It's usually only done in a client-side UI app and only if GetData has a long-running synchronous part (before it hits its 1st await). Otherwise, you might as well just call GetData() without Task.Run and without await (which also would be a bad idea: in either case, you'd be doing a fire-and-forget call without observing possible exceptions).
Task.Run will start GetData on a random pool thread without synchronization content, which may be a problem for either a UI app or an ASP.NET app.
If you want to fire this async operation and forget about it all you need to do is invoke the method without awaiting the returned task:
protected override void OnStart()
{
MyService.GetDataAsync();
}
However, since you're not observing the task you would never know if it completed successfully.
You should either keep a reference to the task and await it in a later time:
public Task _dataTask;
protected override void OnStart()
{
_dataTask = MyService.GetDataAsync();
}
public Task AwaitInitializationAsync()
{
return _dataTask;
}
Or add a continuation handling any exceptions:
protected override void OnStart()
{
MyService.GetDataAsync().ContinueWith(t =>
{
try
{
t.Wait();
}
catch (Exception e)
{
// handle exceptions
}
});
}
You shouldn't use Task.Run as Noseratio explained, however using async void is much worse since an exception in an async void method (which isn't a UI event handler) would tear down the entire process*.
You can try to make the method async void while making sure there won't be any exceptions thrown inside it with a try-catch block:
protected override async void OnStart()
{
try
{
await GetData();
}
catch (Exception e)
{
// handle e.
}
}
But I would still recommend against it since even the chance of a complete crash is dangerous.
*You can get around that by registering an even handler for AppDomain.CurrentDomain.UnhandledException but this should be a last resort, not a best practice
Related
I am using log4net (.Net) to write kafka appender and I am running into an issue where I cannot use await ProduceAsync.
Error
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it. ,
StackTrace : at
System.Web.AspNetSynchronizationContext.OperationStarted(at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Create()
Code
public class CustomAppender: AppenderSkeleton
{
private IProducer<Null, string> p;
public override void ActivateOptions()
{
// Setup kafka producer
}
protected override void Append(LoggingEvent loggingEvent)
{
// Get JSON from application
// Add additional data to the json
callBroker(json, topic);
}
private async void callBroker(string json, string topic)
{
var result = await p.ProduceAsync(Topic, new Message<Null, string>{Value=json});
}
}
I can return Task in my callBroker method but then there is no async override for Append method.
So my question is, Can I use Producer.Produce instead of ProduceAsync in a high volume environment? this program will be logging >500 messages/sec, is there a preference on which works better? I also need to handle some exceptions and take some action if it fails for specific error codes.
Sync version
protected override void Append(LoggingEvent loggingEvent)
{
CallBroker(topic, json);
}
private void CallBroker(string topic, string message)
{
producer.Produce(topic, new Message<Null, string> { Value = message });
}
Semi-async version
If you can't change the signature of the Append method
then you can call an async method in blocking mode via the following way:
protected override void Append(LoggingEvent loggingEvent)
{
CallBrokerAsync(topic, json).GetAwaiter().GetResult();
}
private async Task CallBrokerAsync(string topic, string message)
{
await producer.ProduceAsync(topic, new Message<Null, string> { Value = message });
}
Async shines when it is used all the way down (from the top most entry-point through all the layers till the lowest component which calls the async I/O operation)
As always measure, measure and measure to understand how does this change affect your application.
I'm not sure why this service is refusing to stop.
I ran into this when trying to correct a TimeoutException thrown when starting the service. Using:
public void OnStart()
{
_startTask = Task.Run(DoWork, _cancelTokenSource.Token);
}
private void DoWork(){ [listen for things and operate on them] }
public void OnStop()
{
_cancelTokenSource.Cancel();
_startTask.Wait();
}
I understand that implementing a simple timer will solve this, but that's not the point of my question. Why does the use of Task.Run(() => action, _tokenSource.Token) resolve the TimeoutException but causes the service to not respond to control messages?
The issue Observed
After installing and starting the service (it's TopShelf BTW), I'm unable to stop the service by conventional methods.
First Attempt:
All Subsequent Attempts:
Edit: Still no joy
Here is my attempt after following the provided example.
public void Start()
{
var token = _cancelTokenSource.Token;
Task.Factory.StartNew(() => Setup(token), token);
}
public void Stop()
{
_cancelTokenSource.Cancel();
//TearDown(); <-- original implementation of stop
}
private void Setup(CancellationToken token)
{
_mailman.SendServiceStatusNotification(_buildMode, "Started");
... create some needed objects
token.Register(TearDown);
InitializeInboxWatcherProcess(...);
}
private void TearDown()
{
_inboxWatcher.Terminate();
_mailman.SendServiceStatusNotification(_buildMode, "Stopped");
}
private void InitializeInboxWatcherProcess(...)
{
// pre create and initiate stuff
_inboxWatcher = new LocalFileSystemWatcherWrapper(...);
_inboxWatcher.Initiate();
}
public class LocalFileSystemWatcherWrapper : IFileSystemWatcherWrapper
{
// do FileSystemWatcher setup and control stuff
}
This is most likely because you either don't have a cancellation method, or there are subprocesses inside of DoWork() that are still running when you call Cancel(). As #Damien_The_Unbeliever said cancellation is a cooperative task.
When you call _cancelTokenSource.Cancel() if you haven't registered a callback function all that happens is that a boolean value isCancellationRequested is set to true, the DoWork() method is then responsible for seeing this and stopping its execution on its own. There is a flaw here, though, as you can probably tell, that if you have a time consuming loop running in the DoWork() task when Cancel() is called, that loop will have to finish an iteration before it can check the value of isCancellationRequested which can lead to hanging.
The way around this is to insert cancellation callback functions INTO the DoWork() method, see here and then register them to the token, so that when you call the Cancel() method, ALL of the tasks running in the background are stopped without having to wait for them.
Hope this helps!
This question already has answers here:
The calling thread cannot access this object because a different thread owns it.WPF [duplicate]
(6 answers)
Closed 6 years ago.
Im really stuck here... I have a XAML Page UI and want to call an async function everytime the user interacts with the UI.
I use SignalR for networking:
public static class ProtocolClient
{
private static HubConnection hubConnection;
private static IHubProxy protocolHubProxy;
public static async void connect(string server)
{
hubConnection = new HubConnection(server);
protocolHubProxy = hubConnection.CreateHubProxy("ProtocolHub");
protocolHubProxy.On<Body>("BodiesChanged", body =>
//call a callback to return body
);
await hubConnection.Start(); //wait for connection
}
public static async void sendTouch(Touch touch)
{
Body body = await protocolHubProxy.Invoke<Body>("GetBodyForTouch", touch);
//call a callback to return body
}
}
UI:
public sealed partial class MainPage : Page
{
[...]
private void Canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
[...]
switch (ptrPt.PointerDevice.PointerDeviceType)
{
case Windows.Devices.Input.PointerDeviceType.Mouse:
if (ptrPt.Properties.IsLeftButtonPressed)
{
//call sendTouch
}
break;
default:
break;
}
[...]
}
}
I need a callback which can modify the UI. How can I call connect and sendTouch out of the UI and pass them a callback?
You don't need a callback. Just add the code after the await hubConnection.Start(); statement. Your method is 'cut in multiple methods' and will 'continue' after the await comes back. The await works like a blocking statement, but will not freeze the gui.
public static async void connect(string server)
{
hubConnection = new HubConnection(server);
protocolHubProxy = hubConnection.CreateHubProxy("ProtocolHub");
protocolHubProxy.On<Body>("BodiesChanged", body =>
//call a callback to return body
);
await hubConnection.Start(); //wait for connection
// add code here.
}
When handling commands async (from gui events), don't forget to disable controls to prevent executing the command more than ones.
Don't use async void methods. If you don't need to return a value, use async Task - if you do, use async Task<SomeType>.
Then, when you need to call an async method (and by convention, these should be named like ConnectAsync and SendTouchAsync), await it:
await SendTouchAsync(...);
When the asynchronous workflow ends, your continuation will be marshalled back to the UI thread (because you awaited from within a synchronization context), and you can manipulate the UI easily.
await kind of appears to work when you use async void, but the problem is that the caller has no way of tracking the asynchronous workflow - as far as the caller is concerned, the method just ended right then and now, and the code in the caller continues as usual.
Make sure to mark Canvas_PointerPressed as async too - sadly, in this case, it must be async void. Make sure to never call the event handler directly - the UI thread can handle the callbacks correctly, your code can't. If you need the same logic from other methods, just separate it into a proper async Task method and await that from the event handler.
I have an xUnit (2.1.0) test that always hangs/deadlocks. Here the code with the names of classes/methods changed for clarity and confidentiality:
[Fact]
public void DocumentModificationTest()
{
Exception ex = null;
using (TestDependency testDependency = new TestDependency())
{
TestDependencyDocument testDependencyDoc = testDependency.Document;
MockTestDependency fakeDependency = new MockTestDependency();
try
{
DoStuffToTheDocument(testDependencyDoc, "fileName.doc", fakeDependency);
}
catch (Exception e)
{
ex = e;
}
}
Assert.Null(ex);
}
If I set a breakpoint and step over until the assert I can see that ex is null and the test should pass and be done with, but it just hangs and I never see Test Successful on the runner.
Here's what DoStuffToTheDocument looks like:
public static void DoStuffToTheDocument(TestDependencyDocument document, string pFileName, MockTestDependency pContainer)
{
pContainer.CheckInTheDocFirst(async () =>
{
//check some stuff
//test returns early here
//check other stuff(test never gets here)
//await method (thus the async anonymous method)
});
}
And lastly here's what CheckInTheDocFirst looks like:
public void CheckInTheDocFirst(Action pConfirmAction)
{
pConfirmAction(); //since this is a method in a mock class only used for testing we just call the action
}
Any ideas whats happening here? Is there something with my async-await paradigm that is causing this test to hang?
It turns out that this is an issue caused by async void test method support in xUnit: https://github.com/xunit/xunit/issues/866#issuecomment-223477634
While you really should carry async all the way up, sometimes this isn't feasible because of interoperability concerns. You can't always change the signatures of everything you're working with.
One thing to note about your assert, however, is that it will always prove true even if there's an exception thrown in the async void method (the lambda, in this case). This is because exception handling is different for async void:
Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started. Figure 2 illustrates that exceptions thrown from async void methods can’t be caught naturally.
When you have an async function, you should really be async all the way down. Otherwise you run into issues with sync contexts being blocked which will result in lockups.
pContainer.CheckInTheDocFirst should be async and return a Task (since it's taking an async function that returns a Task object).
DoStuffToDocument should be an async function that returns a Task, since it calls an async function.
And finally, the test itself should also be an async method that returns a task.
If you run the async all the way up the stack, I think you'll find things just work.
I'm new to c# async await mechanism. I read some articles about async all the way (http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). I have an example below, could you please let me know if the first Initialize method will cause dead lock and why? Thank you in advance.
public class Test {
public async Task DoSomeWorkAsync() {
await DoSomeWork1Async();
}
// This method is mixed with Wait and async await, will this cause lead lock?
public void Initialize() {
Task.Run(() => DoSomeWorkAsync()).Wait();
}
// This method is following async all the way
public async Task InitializeAsync() {
await DoSomeWorkAsync();
}
}
// Update: Here is the context where two Initialize methods are called
public class TestForm : Form {
// Load Form UI
public async void OnLoad() {
var test = new Test();
test.Initialize();
await test.InitializeAsync();
}
}
No, this will not deadlock because you're blocking on a task that's being executed by a ThreadPool thread with no SynchronizationContext. Since it isn't running on the UI thread there's nothing stopping that task from completing and so there's no deadlock.
If this was your code, it will have deadlocked:
public void Initialize()
{
DoSomeWorkAsync().Wait();
}
This is still not a good reason to block though, you should use async-await all they way up.