Instantiate and Call WCF service Asynchronously - c#

I have a helper method I am using to instantiate a WCF service and perform an action. This is working great for synchronous calls and has really cut down on the code in my main class. However, I am trying to implement this same method on an asynchronous call to the service and am having trouble with the syntax.
This is the helper method I am using:
public static void Use(Action<T> action)
{
ChannelFactory<T> Factory = new ChannelFactory<T>("*");
ClientCredentials Credentials = new ClientCredentials();
Credentials.UserName.UserName = USER_NAME;
Credentials.UserName.Password = PASSWORD;
Factory.Endpoint.EndpointBehaviors.Remove(typeof(ClientCredentials));
Factory.Endpoint.EndpointBehaviors.Add(Credentials);
T Client = Factory.CreateChannel();
bool Success = false;
try
{
action(Client);
((IClientChannel)Client).Close();
Factory.Close();
Success = true;
}
catch (CommunicationException cex)
{
Log.Error(cex.Message, cex);
}
catch (TimeoutException tex)
{
Log.Error(tex.Message, tex);
}
finally
{
if (!Success)
{
((IClientChannel)Client).Abort();
Factory.Abort();
}
}
}
This is the synchronous call I am making to the helper method from a timer elapsed event:
async void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
Service<IVehicleService>.Use(client =>
{
Vehicles = client.GetAllVehicles(new GetAllVehiclesRequest()).vehicleList;
});
await UpdateVehicleStatuses();
}
This is where the GetVehicleStatus method is called:
private async Task UpdateVehicleStatuses()
{
// Can the call to GetVehicleStatus be turned into a lambda expression utilizing the helper method?
IEnumerable<Task<VehicleStatus>> StatusQuery = from s in Vehicles
select GetVehicleStatus(s.ClientVehicleId);
List<Task<VehicleStatus>> StatusTasks = StatusQuery.ToList();
...
}
This is the current body of the GetVehicleStatus method:
private async Task<VehicleStatus> GetVehicleStatus(string clientVehicleID)
{
// Can this method be modified to use the helper method?
GetStatusResponse Status = await VehicleClient.GetStatusByClientIdAsync(clientVehicleID);
return Status.vehicleStatus;
}
I would like to apply the same principal from the synchronous call to the asynchronous call so that I don't have to initialize the service in the main class and can encapsulate all of the error handling there. I am having trouble with the syntax when attempting to turn the GetVehicleStatus method into a lambda expression in the UpdateVehicleStatuses method. I have also tried to modify the GetVehicleStatus method to utilize the helper method with no luck. What am I missing?
Thanks!

You'll need an asynchronous version of your helper method:
public static async Task UseAsync(Func<T, Task> action)
{
...
try
{
await action(Client);
...
}
Furthermore, if you need to support return values, then you'll need another overload:
public static async Task<TResult> UseAsync(Func<TClient, Task<TResult>> action)
{
...
TResult result;
try
{
result = await action(Client);
...
return result;
}
Then you can use it as such:
private async Task<VehicleStatus> GetVehicleStatusAsync(string clientVehicleID)
{
GetStatusResponse Status = await UseAsync(client => client.GetStatusByClientIdAsync(clientVehicleID));
return Status.vehicleStatus;
}

Related

Race condition with async/await, how to resolve

I have a problem with async/await in C#, i need it to get some object called Trades, after i get it, it needs to SAVE it. Problem is, with async/await, it is doing the SAVE first, and then go and get my trade objects. How do i ensure i get the objects first, and then does the saving.... here is my code...
private async void OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
public async void OnSignalReceived()
{
// THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
OnRefresh();
}
});
// SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
await OnSaveTrades();
}
public async Task<int> OnSaveTrades()
{
foreach (var trade in mmTrades)
{
await ExchangeServiceInstance.OnInsertDoneTrade(trade);
}
return mmTrades.Count;
}
Any ideas guys? Thanks!
The problem is your OnRefresh method. Because the return type is void the method is not awaited [Check out this answer]. In addition you dont even try to await for the method inside your delegate
Changing the method to the following:
private async Task OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
And await this method inside your delegate, should solve your problem:
public async void OnSignalReceived()
{
// THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
await OnRefresh();
}
});
// SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
await OnSaveTrades();
}
The use of (Action)async is basically the same as async void, and async void is almost always a mistake. Specifically, the consumer cannot know the outcome (unless it faults synchronously). The dispatcher here isn't really thinking of async.
If we assume that you must use the dispatcher here, perhaps a workaround might be to use something like a SemaphoreSlim (or maybe a TaskCompletionSource<something>) that you signal at the end of your async work (even in the exception case), and then await that; untested, but:
var tcs = new TaskCompletionSource<bool>();
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
try {
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
OnRefresh();
}
tcs.TrySetResult(true);
} catch (Exception ex) {
tcs.TrySetException(ex);
}
});
await tcs.Task; // ensure the async work is complete
await OnSaveTrades();
First of all, you are using the async void pattern a lot. This is really bad practice for a number of reasons. You should stop doing that.
The problem here is that OnRefresh is again an async void method that can't be awaited but should be:
private async Task OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
In your OnSignalReceived method change the call to OnRefresh(); to await OnRefresh();

Encapsulate async method in Func<T>

First, i hope the title is okay.
I have a Grpc Client with the well known greeter service and try to encapsulate the SayHelloAsync call in a Func.
But the => operator is redlined because he can not convert the expression he say.
It works if i remove any async/await.
Its probably because SayHelloAsync returns AsyncUnaryCall(which have an awaiter) instead of Task but at the end its
not a Grpc issue i guess, its just my missunderstanding.
Here is my try:
static async Task Main()
{
var client = CreateGreeterClient();
await UnsafeTask<Service.HelloReply>(async () =>
{
var result = await client.SayHelloAsync(new Service.HelloRequest { Name = greeter.Name });
return Task<Service.HelloReply>.FromResult(result);
});
Console.ReadKey();
}
static async Task<T> UnsafeTask<T>(Func<AsyncUnaryCall<T>> method) where T:class
{
try
{
return await method();
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
return null;
}
}
Any tip would be greatful.

Do Multi delegate Async Actions Only work with Begin Invoke

I'm trying to understand async actions and I'm a bit confused.
Actions are just glorified Delegates. Given the Actions
Action act = null;
act += () => { Console.WriteLine("Sync"); };
act += async () => { await File.AppendAllLinesAsync("C:/Test.Txt",
new[] { "Async File Operation" });
};
How can we invoke this async seeing as one of the delegates is async and the other is not. I've seen some extension methods in other SO answers simplified for the example would look like so:
public static void InvokeAsync(this Action action, AsyncCallback ar, object userObject = null)
{
var listeners = action.GetInvocationList();
foreach (var t in listeners)
{
var handler = (Action)t;
handler.BeginInvoke(ar, userObject);
}
}
I'm concerned if this even works because it looks like it invokes your callback for each listener which doesn't make sense.
I've only been using async with the more friendly version async/await so I do not understand this syntax as much. (I'm assuming the callback would be everything after the await and the userObject is equivalent to the dreadful SyncronizationContext that causes deadlocks if when calling sync without ConfigureAwait(false), but that is just a guess)
This is syntax inconvenient so I would perfer to use async await syntax, since async/await is called using duck-typing. I've read a blog about using async with delegates which for the example
public static class DelegateExtensions
{
public static TaskAwaiter GetAwaiter(this Action action)
{
Task task = new Task(action);
task.Start();
return task.GetAwaiter();
}
}
This too concerns me for a few reason, this looks much like an anti pattern.
Isn't this just creating a task which will run my action synchronous on a seperate thread? I also don't see this run through the invocation list.
Are either of these methods proper for invoking run delegates asynchronously?
Is there a way I can invoke an async delegate with the await syntax while still fully leveraging async?
What is the proper way to invoke async delegates with multiple functions in the invocation list?
I think Eric Lippert's comment have clarified the situation more than I could ever.
Overall, if you need to act on the return type of a method, you shouldn't use multicast delegates. If you still have to, at least use a Func<Task> signature, then you can iterate on each individual delegate using GetInvocationList, as explained here.
But would it be really impossible to work your way out of a multicast delegate with async void method?
It turns out that you can be notified of beginning and end of async void methods by using a custom synchronization context and overriding the OperationStarted and OperationCompleted methods. We can also override the Post method to set the synchronization context of child operations, to capture subsequent async void calls.
Piecing it together, you could come with something like:
class Program
{
static async Task Main(string[] args)
{
Action act = null;
act += () => { Console.WriteLine("Sync"); };
act += async () =>
{
Callback();
await Task.Delay(1000);
Console.WriteLine("Async");
};
await AwaitAction(act);
Console.WriteLine("Done");
Console.ReadLine();
}
static async void Callback()
{
await Task.Delay(2000);
Console.WriteLine("Async2");
}
static Task AwaitAction(Action action)
{
var delegates = action.GetInvocationList();
var oldSynchronizationContext = SynchronizationContext.Current;
var asyncVoidSynchronizationContext = new AsyncVoidSynchronizationContext();
try
{
SynchronizationContext.SetSynchronizationContext(asyncVoidSynchronizationContext);
var tasks = new Task[delegates.Length];
for (int i = 0; i < delegates.Length; i++)
{
((Action)delegates[i]).Invoke();
tasks[i] = asyncVoidSynchronizationContext.GetTaskForLastOperation();
}
return Task.WhenAll(tasks);
}
finally
{
SynchronizationContext.SetSynchronizationContext(oldSynchronizationContext);
}
}
}
public class AsyncVoidSynchronizationContext : SynchronizationContext
{
private TaskCompletionSource<object> _tcs;
private Task _latestTask;
private int _operationCount;
public Task GetTaskForLastOperation()
{
if (_latestTask != null)
{
var task = _latestTask;
_latestTask = null;
return task;
}
return Task.CompletedTask;
}
public override void Post(SendOrPostCallback d, object state)
{
Task.Run(() =>
{
SynchronizationContext.SetSynchronizationContext(this);
d(state);
});
}
public override void OperationStarted()
{
if (Interlocked.Increment(ref _operationCount) == 1)
{
// First operation
_tcs = new TaskCompletionSource<object>();
_latestTask = _tcs.Task;
}
base.OperationStarted();
}
public override void OperationCompleted()
{
if (Interlocked.Decrement(ref _operationCount) == 0)
{
// Last operation
_tcs.TrySetResult(null);
}
base.OperationCompleted();
}
}
The output would be:
Sync
Async
Async2
Done
Of course, this code is provided just for recreational purpose. There's plenty of limitations, such as the fact the fact that it wouldn't work as-is if you're already using a synchronization context (such as the WPF one). I'm also certain that it has a few subtle bugs and concurrency issues here and there.

await operator not stopping continuation of other method calls

I have three methods that look like below
private async Task checkPhotoLibraryAccess()
{
PHPhotoLibrary.RequestAuthorization(status =>
{
switch (status)
{
//stuff here
}
}
}
private async Task checkDeviceAuthorizationStatus()
{
var status = AVCaptureDevice.GetAuthorizationStatus(AVMediaType.Video);
switch (status)
{
//stuff here
}
}
private void displayAppBar()
{
AppBar.IsVisible = true;
}
I would like the execution of the first two methods to complete before calling the third. I have researched the issue and have found ways of doing so using the await operator and Wait() method. However my implementations has not worked. Here is my code below.
Attempt 1
private async void MyMethod()
{
await checkPhotoLibraryAccess();
await checkDeviceAuthorizationStatus();
displayAppBar(); //THIS IS CALLED BEFORE COMPLETION OF TWO ABOVE
}
Attempt 2
private async void MyMethod()
{
checkPhotoLibraryAccess().Wait();
checkDeviceAuthorizationStatus().Wait();
displayAppBar(); //SAME ISSUE
}
Any suggestions on how to get this to work?
To get a third method to be executed based on the completion of two other methods you use the WhenAll method of the Task class.
var t1 = CheckPhotoLibraryAccess();
var t2 = CheckDeviceAuthorization();
await Task.WhenAll(t1, t2).ContinueWith(t => DisplayAppBar());
#Yacoub Massad and #SLaks reminded me that in order for await to work on a method call, the method needs to contain an await operator.
So I changed my PhotoLibraryAccess method to contain an await operator and placed its method call right before the DisplayAppBar call.
private async Task checkPhotoLibraryAccess()
{
var status = await PHPhotoLibrary.RequestAuthorizationAsync();
//stuff here
}
And then ...
private async void MyMethod()
{
checkDeviceAuthorizationStatus(); //Removed async Task stuff
await checkPhotoLibraryAccess();
displayButtons(); //IT WORKS
}

Convert Action<T> callback to an await

I have a method that takes a Action<String>. When the method finishes its processing it calls the Action<String> with the return value.
MethodWithCallback((finalResponse)=> {
Console.WriteLine(finalResponse);
});
I want to use this in a web.api async controller. How do I wrap this method so I can await for this method to complete in an async manner. I cannot modify the method itself, it is in a legacy code base.
What I would like to be able to do is this
String returnValue = await MyWrapperMethodThatCallsMethodWithCallback();
You can leverage the TaskCompletionSource class and solve the problem in a generic way:
Task<T> AsAsync<T>(Action<Action<T>> target) {
var tcs = new TaskCompletionSource<T>();
try {
target(t => tcs.SetResult(t));
} catch (Exception ex) {
tcs.SetException(ex);
}
return tcs.Task;
}
That way you don't have to modify your MethodWhitCallback:
var result = await AsAsync<string>(MethodWithCallback);
Console.WriteLine(result);

Categories