I have custom control and I have interface this control exposes to it's users.
public interface ILookupDataProvider
{
string IdColumnName { get; }
IEnumerable<IDataColumn> Metadata { get; set; }
void GetDataAsync(string parameters,
Action<IEnumerable<object>> onSuccess, Action<Exception> onError);
}
So, it's my attempt to expose async operation in GetDataAsync
But I don't know how to implement this method in my class that implements interface. I understand this portion as I have method which will execute and then onCompletion, onSucess or onError delegate will be called.
Can somebody help with syntax on how to write those?
EDIT:
It's 4.0 and I can't use await commands
EDIT 2:
I use DevForce framework to load data, but for the sake of this sample - let's do WCF service for example. How would I wrap WCF service call in my interface implementation?
Also, do you think it's OK to create interface like this to present async operation? Would you do it differently with event for example?
The basic idea here is that the query will occur an a background thread. Once your operation is complete you would use the onSuccess and onError callbacks in order to report the new values. For example
void GetDataAsync(
string parameters,
Action<IEnumerable<object>> onSuccess,
Action<Exception> onError) {
WaitCallback doWork = delegate {
try {
IEnumerable<object> enumerable = GetTheData(parameters);
onSuccess(enumerable);
} catch (Exception ex) {
onError(ex);
}
};
ThreadPool.QueueUserWorkItem(doWork, null);
}
You really don't want to use this pattern:
void GetDataAsync(string parameters,
Action<IEnumerable<object>> onSuccess, Action<Exception> onError);
Instead, you want to use this:
Task GetDataAsync(string parameters);
In returning a Task, you are returning an instance which represents the asynchronous unit of work. From there, the consumer of the API can choose to call ContinueWith and decide what to do when it succeeds, or if there is an error.
However, there is a design flaw in your example. In a method named GetDataAsync, I'd expect data to be returned. That's not a problem, you can just change the signature to:
Task<MyData> GetDataAsync(string parameters);
This now returns a Task<T> which you can use the Result property of to get the result (it will block if the task isn't done), or you can use the ContinueWith method again to process the data when the async operation is done.
Additionally, you can take a CancellationToken structure instance of a parameter to determine if you should cancel your operation:
Task<MyData> GetDataAsync(string parameters,
CancellationToken cancellationToken);
Again, ContinueWith will allow you to indicate the action to take on cancellation.
Note that this is the way how methods using await and async in the Async CTP are currently being modeled; they are returning Task or Task<T>; doing the same in your code will allow you to be ready when these language features are baked in.
To use tasks you can use it like this. The only tricky thing to remember is to execute the callback in your UI thread which is achieved with TaskScheduler.FromCurrentSynchronizationContext() so you can update your UI or display a messagebox if something went wrong.
Due to the event driven nature of this stuff it can happen that if you hammer the button which does start the WCF calls that you get the results not back in the order you did send the requests. You can prevent this by storing the started task and cancel the last started task if you want to start a new operation or you can simply ignore the subsequent requests while a task is running.
private void button1_Click(object sender, EventArgs e)
{
GetDataAsync("www.data.com").ContinueWith(result =>
{
if (result.Exception != null)
{
MessageBox.Show(this, "Error: {0}" + result.Exception, "Error");
}
else
{
foreach (var obj in result.Result)
{
textBox1.Text += obj.ToString();
}
}
},
TaskScheduler.FromCurrentSynchronizationContext()
);
}
Task<IEnumerable<object>> GetDataAsync(string parameters)
{
return Task<IEnumerable<object>>.Factory.StartNew(() =>
{
Thread.Sleep(500);
// throw new ArgumentException("uups");
// make wcf call here
return new object[] { "First", "second" };
});
}
Related
I have the following method that uses Kafka to produce data into a topic:
public void Send(
ProducerMessage<TKey, TValue> producerMessage,
string topic,
Action<McFlowProducerResult<TKey, TValue>> callback = default)
{
try
{
var kafkaProducerMessage = new Message<string, string>();
// DeliveryHanlder logic is skipped?
_producer.Produce(
topic,
kafkaProducerMessage,
deliveryReport => DeliveryHandler(deliveryReport)); // TODO: How can I ensure the DeliveryHandler logic is executed without using async await Task?
}
catch (Exception ex)
{
// Some exception logic
}
}
The DeliveryHandler logic is as follows:
// TODO: Execution never makes it into this function
private async Task DeliveryHandler(DeliveryReport<string, string> deliveryReport)
{
var producerResult = new ProducerResult<string, string>(deliveryReport);
if (!deliveryReport.Error.IsError)
{
_logger.LogError("Message Sent successfully to DLQ TOPIC");
return;
}
_logger.LogError("Unable to send the message to DLQ TOPIC: {0}. Error Reason :{1}",
deliveryReport.Topic, deliveryReport.Error.Reason);
if (deliveryReport.Error.Code == ErrorCode.NetworkException)
{
_logger.LogError("Sending message to DynamoDb");
await _fatalErrorHandler.HandleError(producerResult);
}
}
And I have the following unit test:
[Fact]
public void ValidateDeliveryHandlerIsInvoked()
{
var producerMessage = new ProducerMessage<string, string>(
"aKey",
"aValue",
new Headers(),
Timestamp.Default,
0
);
ProducerResult<string, string> callbackResult = null;
_mcFlowDlqProducer.Send(producerMessage, _topicName,
(mcFlowProducerResult) =>
{
callbackResult = mcFlowProducerResult;
});
Assert.NotEmpty(callbackResult.Topic);
}
}
Kafka's Send() method receives 3 parameters: the topic to produce to, the kafkaProducerMessage which is the data to be sent, and an optional Action<DeliveryReport<TKey, TValue>> deliveryHandler which allows the user to retrieve the results of a produce operation.
My problem is with that 3rd parameter -- the DeliveryHandler (which is an async method). When I run my above unit test, execution never makes it to the DeliveryHandler because the call is not awaited.
I cannot modify my void Send(...) method's signature because I need to have a Synchronous implementation of this method; so I cannot replace the void keyword with async Task.
How can I ensure that execution enters the DeliveryHandler method so that the DeliveryHandler logic gets executed without using async Task?
I've tried modifying the call to the DeliveryHandler to:
DeliveryHandler(deliveryReport).GetAwaiter().GetResult()
But my debugger tells me that execution still never enters the DeliveryHandler block.
Try adding GetAwaiter().GetResult() to the end, as in:
_producer.Produce(
topic,
kafkaProducerMessage,
deliveryReport => DeliveryHandler(deliveryReport).GetAwaiter().GetResult());
I believe the best solution would be to create an overload for Send:
public Task SendAsync(
ProducerMessage<TKey, TValue> producerMessage,
string topic,
Func<McFlowProducerResult<TKey, TValue>, Task> callback = default)
and then you can call SendAsync when you have an asynchronous callback.
Let's say I've created a library with the following async method:
public async Task<string> MyAsyncMethod()
{
// Do stuff
return someString;
}
Now let's say I want the app developer to be able to call this method in a typical fire-and-forget fashion, but then consume an event with the return data when the method completes.
If I were to do this manually, it might look something like this:
public async Task<string> MyAsyncMethod()
{
// Do stuff
// Fire the success event
MyEvent?.Invoke(this, new MyEventArgs { Result = someString });
return someString;
}
...
// Use this callback method to consume the event
public void C_MyAsyncMethodHasCompleted(object sender, MyEventArgs e)
{
Console.WriteLine("Async method has completed with return value: " + e.Result);
}
Here's my question: Is it a waste of time to do it like this? I.e. is there some simpler, built-in thing with C# and/or .NET that already does this?
I mainly just want to make sure I'm not reinventing the wheel with this approach.
I want the app developer to be able to call this method in a typical fire-and-forget fashion, but then consume an event with the return data when the method completes.
I think you might be over-complicating things. I think you can ignore this requirement and just let the consumer deal with it.
In it's simplest form, let's say the consumer wants to start this method, go do something else while waiting, then come back to the result later. They can do something like this:
var myTask = MyAsyncMethod();
// The method starts running and returns a Task<string> when it hits the first await
// (when it starts waiting for whatever I/O request)
DoOtherStuff();
//Now I'm ready for the result, so I await:
var theString = await myTask;
DoSomethingWith(theString);
Likewise, they could store a reference to the Task<string> however they want (pass it to another method, etc.) and only await it when they're ready to use the result.
Or they can use ContinueWith as Theodor suggests (but that has some caveats, like how exceptions are handled). Either way, you, as the author of this library, don't need to worry about it.
Maybe you are searching for the ContinueWith method? The caller can create an "event" by chaining a continuation to the task:
Task<string> task = MyAsyncMethod();
_ = task.ContinueWith(_ => { /* Event handler */ }, TaskScheduler.Default);
I have a service I need to connect to that passes data back through an action like this:
public Guid UpdateEntities<T>(Action<EntitiesChangedResponse<T>> onResponse, IEnumerable<T> entities)
{
//Get some data
onResponse.Invoke(response);
{
Existing code would call the service as follows:
Guid requestId = _productService.UpdateEntities<Product>(x => OnEntitiesUpdated(x), new List<Product> { updateProduct1, updateProduct2 });
And the callback would do something with the result at some point in the future:
private void OnEntitiesUpdated<T>(EntitiesChangedResponse<T> response)
{
//Do something with the result
}
I'm try to integrate it with a task based signal R hub so need to return the operation as a typed task, but I can't for the life of me figure out how to achieve this (I'm quite new to tasks so please tell me if this is daft).
It would look something like this:
public Task<EntitiesChangedResponse<Product>> UpdateProducts(List<Product> products)
{
//Somehow wrap this in a task
Task<EntitiesChangedResponse<Product>> result = New Task<EntitiesChangedResponse<Product>>( call the product service );
return result;
}
Any help appreciated. It is hurting my head.
To make a bridge between "callback" API and task based API you can use TaskCompletionSource
public Task<EntitiesChangedResponse<Product>> UpdateProducts(List<Product> products)
{
var tcs = new TaskCompletionSource<EntitiesChangedResponse<Product>>();
_productService.UpdateEntities<Product>(response => tcs.SetResult(response), new List<Product> { updateProduct1, updateProduct2 });
return tcs.Task;
}
Let's have a look at the following method:
public Task<EntitiesChangedResponse<T>> UpdateEntities<T>(IEnumerable<T> entities)
{
var updateTask = Task.Run(()=>
{
//return data from this lambda expression
});
return updateTask;
}
This starts and returns a task which does your work.
(If you really need the GUID you can return a Tuple or any DTO containing both).
You now have a couple of options to consume this task, here's one:
private Task async UpdateEntitiesAsync<T>(IEnumerable<T> entities)
{
try
{
EntitiesChangedResponse<T> response = await UpdateEntities(entities);
//asynchronous callback implementation code can go here
}
catch(AggregateException ex)
{
//handle a thrown exception
}
}
Do note:
1)The execution continues past the 'await' statement once the task completes and will execute the following LOC.
2) if the task faults (throws an exception) the LOC past the await block will not execute and the catch clause will execute instead.
3) Calling the UpdateEntitiesAsync method does not block the calling thread. the execution immediately returns to the caller once the await statement is hit.
4) You can await the task returned from the async method as well since it (implicitly) returns a task which finishes once this method executes in full, making this method awaitable in itself, if such a need arises.
Alternatively, you can have this method return void, if you do not really care about when it completes.
5) If you do not catch the exception in this method, know that the task returned from the async method will fault, and must be handled somewhere up the invocation chain.
You can do this by either awaiting the task, accessing the Exception property, or invoking the Wait method of the task.
6) The Async postfix in the method's name is merely a naming convention, applied so that client code is aware of the method's asynchronous nature.
I have an async method which returns no data:
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
I'm calling this from another method which returns some data:
public string GetStringData()
{
MyAsyncMethod(); // this generates a warning and swallows exceptions
return "hello world";
}
Calling MyAsyncMethod() without awaiting it causes a "Because this call is not awaited, the current method continues to run before the call is completed" warning in visual studio. On the page for that warning it states:
You should consider suppressing the warning only if you're sure that you don't want to wait for the asynchronous call to complete and that the called method won't raise any exceptions.
I'm sure I don't want to wait for the call to complete; I don't need to or have the time to. But the call might raise exceptions.
I've stumbled into this problem a few times and I'm sure it's a common problem which must have a common solution.
How do I safely call an async method without awaiting the result?
Update:
For people suggesting that I just await the result, this is code that is responding to a web request on our web service (ASP.NET Web API). Awaiting in a UI context keeps the UI thread free, but awaiting in a web request call will wait for the Task to finish before responding to the request, thereby increasing response times with no reason.
If you want to get the exception "asynchronously", you could do:
MyAsyncMethod().
ContinueWith(t => Console.WriteLine(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
This will allow you to deal with an exception on a thread other than the "main" thread. This means you don't have to "wait" for the call to MyAsyncMethod() from the thread that calls MyAsyncMethod; but, still allows you to do something with an exception--but only if an exception occurs.
Update:
technically, you could do something similar with await:
try
{
await MyAsyncMethod().ConfigureAwait(false);
}
catch (Exception ex)
{
Trace.WriteLine(ex);
}
...which would be useful if you needed to specifically use try/catch (or using) but I find the ContinueWith to be a little more explicit because you have to know what ConfigureAwait(false) means.
You should first consider making GetStringData an async method and have it await the task returned from MyAsyncMethod.
If you're absolutely sure that you don't need to handle exceptions from MyAsyncMethod or know when it completes, then you can do this:
public string GetStringData()
{
var _ = MyAsyncMethod();
return "hello world";
}
BTW, this is not a "common problem". It's very rare to want to execute some code and not care whether it completes and not care whether it completes successfully.
Update:
Since you're on ASP.NET and wanting to return early, you may find my blog post on the subject useful. However, ASP.NET was not designed for this, and there's no guarantee that your code will run after the response is returned. ASP.NET will do its best to let it run, but it can't guarantee it.
So, this is a fine solution for something simple like tossing an event into a log where it doesn't really matter if you lose a few here and there. It's not a good solution for any kind of business-critical operations. In those situations, you must adopt a more complex architecture, with a persistent way to save the operations (e.g., Azure Queues, MSMQ) and a separate background process (e.g., Azure Worker Role, Win32 Service) to process them.
The answer by Peter Ritchie was what I wanted, and Stephen Cleary's article about returning early in ASP.NET was very helpful.
As a more general problem however (not specific to an ASP.NET context) the following Console application demonstrates the usage and behavior of Peter's answer using Task.ContinueWith(...)
static void Main(string[] args)
{
try
{
// output "hello world" as method returns early
Console.WriteLine(GetStringData());
}
catch
{
// Exception is NOT caught here
}
Console.ReadLine();
}
public static string GetStringData()
{
MyAsyncMethod().ContinueWith(OnMyAsyncMethodFailed, TaskContinuationOptions.OnlyOnFaulted);
return "hello world";
}
public static async Task MyAsyncMethod()
{
await Task.Run(() => { throw new Exception("thrown on background thread"); });
}
public static void OnMyAsyncMethodFailed(Task task)
{
Exception ex = task.Exception;
// Deal with exceptions here however you want
}
GetStringData() returns early without awaiting MyAsyncMethod() and exceptions thrown in MyAsyncMethod() are dealt with in OnMyAsyncMethodFailed(Task task) and not in the try/catch around GetStringData()
I end up with this solution :
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
public string GetStringData()
{
// Run async, no warning, exception are catched
RunAsync(MyAsyncMethod());
return "hello world";
}
private void RunAsync(Task task)
{
task.ContinueWith(t =>
{
ILog log = ServiceLocator.Current.GetInstance<ILog>();
log.Error("Unexpected Error", t.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
This is called fire and forget, and there is an extension for that.
Consumes a task and doesn't do anything with it. Useful for fire-and-forget calls to async methods within async methods.
Install nuget package.
Use:
MyAsyncMethod().Forget();
EDIT: There is another way I've been rather using lately:
_ = MyAsyncMethod();
Not the best practice, you should try avoiding this.
However, just to address "Call an async method in C# without await", you can execute the async method inside a Task.Run. This approach will wait until MyAsyncMethod finish.
public string GetStringData()
{
Task.Run(()=> MyAsyncMethod()).Result;
return "hello world";
}
await asynchronously unwraps the Result of your task, whereas just using Result would block until the task had completed.
If you want to wrap it in a helper class:
public static class AsyncHelper
{
public static void Sync(Func<Task> func) => Task.Run(func).ConfigureAwait(false);
public static T Sync<T>(Func<Task<T>> func) => Task.Run(func).Result;
}
and call like
public string GetStringData()
{
AsyncHelper.Sync(() => MyAsyncMethod());
return "hello world";
}
I'm late to the party here, but there's an awesome library I've been using which I haven't seen referenced in the other answers
https://github.com/brminnick/AsyncAwaitBestPractices
If you need to "Fire And Forget" you call the extension method on the task.
Passing the action onException to the call ensures that you get the best of both worlds - no need to await execution and slow your users down, whilst retaining the ability to handle the exception in a graceful manner.
In your example you would use it like this:
public string GetStringData()
{
MyAsyncMethod().SafeFireAndForget(onException: (exception) =>
{
//DO STUFF WITH THE EXCEPTION
});
return "hello world";
}
It also gives awaitable AsyncCommands implementing ICommand out the box which is great for my MVVM Xamarin solution
Typically async method returns Task class. If you use Wait() method or Result property and code throws exception - exception type gets wrapped up into AggregateException - then you need to query Exception.InnerException to locate correct exception.
But it's also possible to use .GetAwaiter().GetResult() instead -
it will also wait async task, but will not wrap exception.
So here is short example:
public async Task MyMethodAsync()
{
}
public string GetStringData()
{
MyMethodAsync().GetAwaiter().GetResult();
return "test";
}
You might want also to be able to return some parameter from async function - that can be achieved by providing extra Action<return type> into async function, for example like this:
public string GetStringData()
{
return MyMethodWithReturnParameterAsync().GetAwaiter().GetResult();
}
public async Task<String> MyMethodWithReturnParameterAsync()
{
return "test";
}
Please note that async methods typically have ASync suffix naming, just to be able to avoid collision between sync functions with same name. (E.g. FileStream.ReadAsync) - I have updated function names to follow this recommendation.
I guess the question arises, why would you need to do this? The reason for async in C# 5.0 is so you can await a result. This method is not actually asynchronous, but simply called at a time so as not to interfere too much with the current thread.
Perhaps it may be better to start a thread and leave it to finish on its own.
On technologies with message loops (not sure if ASP is one of them), you can block the loop and process messages until the task is over, and use ContinueWith to unblock the code:
public void WaitForTask(Task task)
{
DispatcherFrame frame = new DispatcherFrame();
task.ContinueWith(t => frame.Continue = false));
Dispatcher.PushFrame(frame);
}
This approach is similar to blocking on ShowDialog and still keeping the UI responsive.
Maybe I'm too naive but, couldn't you create an event that is raised when GetStringData() is called and attach an EventHandler that calls and awaits the async method?
Something like:
public event EventHandler FireAsync;
public string GetStringData()
{
FireAsync?.Invoke(this, EventArgs.Empty);
return "hello world";
}
public async void HandleFireAsync(object sender, EventArgs e)
{
await MyAsyncMethod();
}
And somewhere in the code attach and detach from the event:
FireAsync += HandleFireAsync;
(...)
FireAsync -= HandleFireAsync;
Not sure if this might be anti-pattern somehow (if it is please let me know), but it catches the Exceptions and returns quickly from GetStringData().
The solution is start the HttpClient into another execution task without sincronization context:
var submit = httpClient.PostAsync(uri, new StringContent(body, Encoding.UTF8,"application/json"));
var t = Task.Run(() => submit.ConfigureAwait(false));
await t.ConfigureAwait(false);
It is straightforward, just call asyncMethod().Result to call without await. Below is the sample code and here is the fiddle
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var asyncDemo = new AsyncDemo();
asyncDemo.TestMethod1Void().Wait();
var result = asyncDemo.TestMethod1().Result;
Console.WriteLine(result);
}
}
public class AsyncDemo {
public async Task<string> TestMethod1()
{
Thread.Sleep(1000);
return "From Async Method";
}
public async Task TestMethod1Void()
{
Thread.Sleep(1000);
Console.WriteLine("Async Void Method");
}
}
I've been writing Windows Phone 8 code that calls a SOAP web service backend. From what I've read, the typical pattern is this:
var client = new KitchenPCSoapClient();
client.LogonCompleted += client_LogonCompleted;
client.LogonAsync(username, password);
To me, this just seems counter intuitive. If I call LogonAsync multiple times with the same client, I don't necessarily want it to use the same LogonCompleted callback every time.
What I'd like is a pattern more like JavaScript, where you pass in a reference to the callback function. More like:
var client = new KitchenPCSoapClient();
client.LogonAsync(username, password, client_LogonCompleted);
Is there a way to implement such a pattern, or should I just force myself to get used to setting the LogonCompleted property before I call LogonAsync, or set the userState property if I want to differentiate between different contexts?
You can make use of Dispatcher and call the function on UI side for this ...
I am doing like this
callback function
private void AddPricesHandler(CompletedEventArgs response, Exception e)
{
//your code gose here
}
Call proxy calss function
Proxy.AddData(AddPricesHandler, request);
proxy class calling webservice
public void AddData(Action<CompletedEventArgs, Exception> callback, IPVWorkflowService.CreateEditDeletePriceSourceRequest request)
{
_workflowProxy.CreateEditDeletePriceSourceAsync(request, callback);
_workflowProxy.CreateEditDeletePriceSourceCompleted+=new EventHandler<CreateEditDeletePriceSourceCompletedEventArgs>(_workflowProxy_CreateEditDeletePriceSourceCompleted);
}
completer function use dispatcher to call callback function
void _workflowProxy_CreateEditDeletePriceSourceCompleted(object sender, CreateEditDeletePriceSourceCompletedEventArgs e)
{
try
{
this.dispatcher.BeginInvoke((Action)(() =>
{
(e.UserState as Action<CompletedEventArgs, Exception>)(e, null);
}));
}
catch (Exception ex)
{
this.dispatcher.BeginInvoke((Action)(() =>
{
(e.UserState as Action<CompletedEventArgs, Exception>)(e, ex);
}));
}
finally
{
_workflowProxy.CreateEditDeletePriceSourceCompleted -= _workflowProxy_CreateEditDeletePriceSourceCompleted;
_workflowProxy = null;
}
}
The beauty of Async/Await is that you don't have to write callbacks, you just write code that looks like synchronous, but in the background it's executed asynchronously:
var client = new KitchenPCSoapClient();
await client.LogonAsync(username, password);
// you get here after the async logon is completed
// do stuff after logon
But if you really want to use callbacks, you can just use the method ContinueWith on the Task object, that is returned from asynchronous method:
var client = new KitchenPCSoapClient();
Task task = client.LogonAsync(username, password);
// this method is called when async execution of task is finished
task.ContinueWith(client_LogonCompleted);