I am trying to call an async method from a normal method. I have the following two issues here:
When I use Task.Run in class A to class B's method, JQuery is not
receiving the call.
I cannot use await because it throws this error:
The await can only be used in an async method
I am not sure what the issue is with respect to the first problem I am having. Secondly, is there a way to use await when calling classB because it seems to work when I made a call from a different method that is async.
public class A :IA
{
public A ()
{
consumer.Received += Received;
}
public void Received(object sender, BasicDeliverEventArgs ea)
{
//get message here and send to classB
Task.Run(() => classB.PingMesssage(Message));
}
}
public class B
{
public async Task PingMesssage(string message)
{
await InvokeClientMethodToAllAsync("callJQueryMethod", "message"); //calling js here
}
}
You can make Received async and await a call to PingMessage:
public async void Received(object sender, BasicDeliverEventArgs ea) {
await classB.PingMessage(message);
}
Related
I have async/awaited methods in my Connected anonymous method implementation and I wonder which one of these is the best to use in my case. I put examples below and added information according to what I know. Are my statements correct? Anything else important that I'm missing?
EventHandler
The only disadvantage to me is that the anonymous method is basically async void. Yes, we can have async calls, but they will be kinda "fire and forget/crash".
public class Test
{
public event EventHandler<ConnectEventArgs>? Connected;
public ValueTask StartAsync()
{
Connected?.Invoke(this, new ConnectEventArgs(...))
}
}
var test = new Test();
test.Connected += async (sender, e) => // private async void OnConnect(object? sender, ConnectEventArgs e) => BAD
{
await SendAsync(); // fire and forget
};
await test.StartAsync();
Func
What I notice is that we can have async calls without having to worry about async void. I think that's the only good way to have async/awaited method calls. Isn't it?
public class Test
{
public event Func<Task>? Connected;
public ValueTask StartAsync()
{
await (Connected?.Invoke() ?? Task.CompletedTask).ConfigureAwait(false);
}
}
var test = new Test();
test.Connected += async () => // private async Task OnConnect()
{
await SendAsync(); // Should be okay?
};
await test.StartAsync();
Action
The only difference between Action and EventHandler that comes into my mind is that we don't pass the sender and we don't have to create EventArgs classes.
public class Test
{
public event Action<bool>? Connected;
public ValueTask StartAsync()
{
Connected?.Invoke(true);
}
}
var test = new Test();
test.Connected += async (boolean) => // private void OnConnect(bool boolean)
{
await SendAsync(); // fire and forget
};
await test.StartAsync();
I'm currently working on a .net 5 Blazor application.
I use events to pass data from one component to another.
Unfortunately my current logic is synchronous - but I would rather use an asynchronous event handler.
Thus, I need to use the following code to handle my event:
Task.Run(async () => await ChangeNumbers());
Is there a possibility to handle events asynchronously without Task.Run?
My State service looks like this:
public class MyComponentState
{
public int MyNumber { get; set; }
// Is there a way to declare this event Action async??
public event Action OnChange;
public void DoStuff(int myNumber)
{
MyNumber = myNumber;
NotifyStateChanged();
}
private void NotifyStateChanged() => OnChange?.Invoke();
}
The component to handle the state looks like this:
public class MyOtherComponentDisplay : ComponentBase, IDisposable
{
[Inject]
public MyComponentState MyComponentState { get; set; }
protected override void OnInitialized()
{
// this should all be handled async... i could use OnInitializedAsync
MyComponentState.OnChange += OnChangeHandler;
}
private void OnChangeHandler()
{
// Is there a way to handle/declare this without Task.Run(async ...) - but async right away??
Task.Run(async () => await ChangeNumbers());
}
private async Task ChangeNumbers()
{
// Some operations with MyComponentState.MyNumber async needed!!!
StateHasChanged();
}
public void Dispose()
{
MyComponentState.OnChange -= OnChangeHandler;
}
}
Is there a way to declare and handle events async?
Do you know how to solve this problem?
The basic adoptation would be an async void handler:
private async void OnChangeHandler()
{
// Is there a way to handle/declare this without Task.Run(async ...)
// - but async right away??
// Task.Run(async () => await ChangeNumbers());
await ChangeNumbers();
await InvokeAsync(StateHasChanged); // probably needed
}
The way you're doing things looks strange to me. That's not how I do events in Blazor. (Maybe you're coming from Web Forms?)
Generally, a custom event is defined like:
MyControl.razor
[Parameter]
public EventCallback<SomeType> EventName{ get; set; }
#code {
someMethod (){
EventName.InvokeAsync(SomeType data);
}
}
And the handler in the consuming control can be async if you want:
MyPage.razor
<MyControl EventName=OnChangeHandler />
#code {
private async Task OnChangeHandler()
{
await ChangeNumbers();
}
}
SendOrPostCallback Represents a method to be called when a message is to be dispatched to a synchronization context. In first case SendOrPostCallback points on async method that i guess should be executed synchronously. What will happen if Delegate will point on async delegate? How behaviour should change?
Before changes:
public class ViewModel
{
public ViewModel()
{
SynchronizationContext.Current.Post(new SendOrPostCallback(SomeMethods), null);
}
private async void SomeMethods(object obj)
{
await Foo(obj);
}
private async Task Foo(object obj)
{
bool Canceled = false;
while (!Canceled)
{
await Task.Delay(3000);
//...
}
}
}
After changes:
public class ViewModelImproved
{
public ViewModelImproved()
{
SynchronizationContext.Current.Post(new SendOrPostCallback(async (obj) => { await SomeMethods(obj); }), null);
}
private async Task SomeMethods(object obj)
{
await Foo(obj);
}
private async Task Foo(object obj)
{
bool Canceled = false;
while (!Canceled)
{
await Task.Delay(3000);
}
//...
}
}
There's no substantial difference. In the first code, there's an async void, and in the second code, there's an async void. In the second code, the async void is hidden within a lambda expression.
Generally, you should avoid async void. In this particular case, it may be OK, since you're dealing with a UI context.
When I call BuildCustomer.StartTask, I then call a method WriteToDatabase. Inside WriteToDatabase, I want to send a status back to the MainForm to write the status to the GUI. When the code reaches that point, my application freezes up and gives no error. I did find out that if I remove task.Wait(), it stops freezing and works. But I think I want the wait in because my BuildCustomer takes a bit of time and writes a lot of updates (including more updates from Common class) to the GUI. Can someone tell me what is wrong or what I should be doing differently? This is a .Net 4 project so I cannot use async, which I've seen other answers for.
public partial class MainForm : Window
{
public MainForm()
{
Common.SendMessage += UpdateStatus;
}
private void Button_Click(object sender, EventArgs e)
{
BuildCustomer.StartTask();
}
private void UpdateStatus(string message)
{
Dispatcher.Invoke(new Action(() =>
{
StatusTextBox.Text = message;
}));
}
}
public class BuildCustomer
{
public static void StartTask()
{
var action = new Action<object>(BuildCustomer);
var task = new Task(() => action(buildDetails));
task.Start();
task.Wait();
}
private void BuildCustomerDetails(object buildDetails)
{
Common.WriteToDatabase();
}
}
public class Common
{
public delegate void MessageLogDelegate(string message);
public static event MessageLogDelegate SendMessage;
public static void WriteToDatabase()
{
SendMessage("Some status message to write back to the GUI");
}
}
You have a deadlock. The StartTask waits on task.Wait() to complete but this occurs (is called on) on the calling thread which is the main UI thread.
The Task being waited eventually reaches UpdateStatus which calls an Invoke on the UI thread as well but this thread is currently waiting on task.Wait() (so it is blocking which results in the UI thread not being available indefinitely).
Try to add async keyword to method signature and use this:
await task;
It cause to does not sleep main thread(UI thread).
How to call an async method into a method that implements an interface when this method is NOT async?
In my ViewModel, I've got an async method that should be executed each time the user navigates into the view.
The fastest (bad) solution I was able to find is this one
public class MyViewModel : INavigationAware
{
//[...]
public async void OnNavigatedTo(NavigationContext navigationContext)
{
await Refresh();
}
public async Task Refresh()
{
await Task.Run(() =>
{
// Asynchronous work
});
/* Actions on Gui Thread */
}
//[...]
}
This should work for this, based on what I can gather from the question. I did a quick test with a project I am working on to see the concept work. The Refresh method should run each time you navigate to the view using this view model.
public class MyViewModel : INavigationAware
{
//[...]
public void OnNavigatedTo(NavigationContext navigationContext)
{
Refresh();
}
public async void Refresh()
{
await Task.Run(() =>
{
// Asynchronous work
}).ContinueWith(t=> /* Actions on Gui Thread */, TaskScheduler.FromCurrentSynchronizationContext());
}
//[...]
}
I removed the async/await on the OnNavigatedTo, and had that call an async Refresh method that returns nothing.