Maybe this is due to my lack of understanding of what happens during compilation when a method is marked async, but why does this method compile?
public async Task<bool> Test()
{
return true;
}
Just looking for an explanation here, so I can better understand what is going on. Is a Task automatically getting wrapped? Why is this method allowed? (it does not adhere to the method signature, which is to return a Task<bool>).
Update:
It appears that this is also applicable for parameters to:
public void Main()
{
Input(Test);
}
public async Task<bool> Test()
{
return true;
}
public void Input(Func<Task<bool>> test)
{
}
where, the Test method returns a Task implicitly.
You can take a look at the decompiled version of your code here
using System;
public class C {
public async System.Threading.Tasks.Task<bool> M() {
return false;
}
}
The method is compiled into a normal async one, with the state machine, it does return a Task<bool> after all.
public class C
{
[CompilerGenerated]
private sealed class <M>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<bool> <>t__builder;
public C <>4__this;
//called when you awaiting the Task
void IAsyncStateMachine.MoveNext()
{
int num = this.<>1__state;
bool result;
try
{
result = false; //the result is set
}
catch (Exception arg_0C_0)
{
Exception exception = arg_0C_0;
this.<>1__state = -2;
this.<>t__builder.SetException(exception);
return;
}
this.<>1__state = -2;
this.<>t__builder.SetResult(result);
}
[DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
}
}
[DebuggerStepThrough, AsyncStateMachine(typeof(C.<M>d__0))]
public Task<bool> M()
{
// the state machine instance created
C.<M>d__0 <M>d__ = new C.<M>d__0();
<M>d__.<>4__this = this;
<M>d__.<>t__builder = AsyncTaskMethodBuilder<bool>.Create();
<M>d__.<>1__state = -1;
AsyncTaskMethodBuilder<bool> <>t__builder = <M>d__.<>t__builder;
<>t__builder.Start<C.<M>d__0>(ref <M>d__);
return <M>d__.<>t__builder.Task;
}
}
BTW, the compiler gives you a warning, because you never await in your method:
warning CS1998: This async method lacks 'await' operators and will run
synchronously. Consider using the 'await' operator to await
non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work
on a background thread.
And you're absolutely right, you may just return a completed task instead:
using System;
using System.Threading.Tasks;
public class C {
public Task<bool> M() {
return Task.FromResult(false); //no need to await here at all
}
}
The other ways to code the method above could be found here.
using System;
using System.Threading.Tasks;
public class C {
public async Task<bool> M() {
return false;
}
public async Task<bool> M2(){
return await Task.FromResult(false);
}
public Task<bool> M3(){
return Task.FromResult(false);
}
}
I hope this will clarify things for you.
Related
Looking for help after searching has not produced a good suggestion.
I always avoid having async void methods in code. I don't use event handlers. Sometimes a vendor or library gives you no choice, and their methods are implemented as async void.
If my method itself returns Task, but i have no choice but to call a 3rd party library method with async void, is there a way to safely wrap their method in such a way that I can keep my code free of the async void dangers, as listed here about terminating my process?
StackOverflow - why is async void bad
An example of my concern is as follows:
3rd party library method looks like this
public async void GetSomethingFromAService()
{
/// their implementation, and somewhere along the way it throws an exception, in this async void method --- yuck for me
}
My method say on a service controller:
public async Task<bool> MyMethod()
{
await ThirdPartyLibrary.GetSomethingFromAService();
return await Task.FromResult(true);
}
My method is fine except the 3rd party library is async void and throws an exception. My app is going to die. I don't want it to because my code is well written an not async void. But I can't control their code. Can i wrap the call to their async void method in such a way to protect my code from dying?
It's tricky and it might not work for all scenarios, but it may be possible to track the life-time of an async void method, by starting its execution on a custom synchronization context. In this case, SynchronizationContext.OperationStarted / SynchronizationContext.OperationCompleted will be called upon start and end of the asynchronous void method, correspondingly.
In case an exception is thrown inside an async void method, it will be caught and re-thrown via SynchronizationContext.Post. Thus, it's also possible to collect all exceptions.
Below is an a complete console app example illustrating this approach, loosely based on Stephen Toub's AsyncPump (warning: only slightly tested):
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncVoidTest
{
class Program
{
static async void GetSomethingFromAService()
{
await Task.Delay(2000);
throw new InvalidOperationException(nameof(GetSomethingFromAService));
}
static async Task<int> MyMethodAsync()
{
// call an ill-designed 3rd party async void method
// and await its completion
var pump = new PumpingContext();
var startingTask = pump.Run(GetSomethingFromAService);
await Task.WhenAll(startingTask, pump.CompletionTask);
return 42;
}
static async Task Main(string[] args)
{
try
{
await MyMethodAsync();
}
catch (Exception ex)
{
// this will catch the exception thrown from GetSomethingFromAService
Console.WriteLine(ex);
}
}
}
/// <summary>
/// PumpingContext, based on Stephen Toub's AsyncPump
/// https://blogs.msdn.com/b/pfxteam/archive/2012/02/02/await-synchronizationcontext-and-console-apps-part-3.aspx
/// https://stackoverflow.com/q/49921403/1768303
/// </summary>
internal class PumpingContext : SynchronizationContext
{
private int _pendingOps = 0;
private readonly BlockingCollection<ValueTuple<SendOrPostCallback, object>> _callbacks =
new BlockingCollection<ValueTuple<SendOrPostCallback, object>>();
private readonly List<Exception> _exceptions = new List<Exception>();
private TaskScheduler TaskScheduler { get; }
public Task CompletionTask { get; }
public PumpingContext(CancellationToken token = default(CancellationToken))
{
var taskSchedulerTcs = new TaskCompletionSource<TaskScheduler>();
this.CompletionTask = Task.Run(() =>
{
SynchronizationContext.SetSynchronizationContext(this);
taskSchedulerTcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext());
try
{
// run a short-lived callback pumping loop on a pool thread
foreach (var callback in _callbacks.GetConsumingEnumerable(token))
{
try
{
callback.Item1.Invoke(callback.Item2);
}
catch (Exception ex)
{
_exceptions.Add(ex);
}
}
}
catch (Exception ex)
{
_exceptions.Add(ex);
}
finally
{
SynchronizationContext.SetSynchronizationContext(null);
}
if (_exceptions.Any())
{
throw new AggregateException(_exceptions);
}
}, token);
this.TaskScheduler = taskSchedulerTcs.Task.GetAwaiter().GetResult();
}
public Task Run(
Action voidFunc,
CancellationToken token = default(CancellationToken))
{
return Task.Factory.StartNew(() =>
{
OperationStarted();
try
{
voidFunc();
}
finally
{
OperationCompleted();
}
}, token, TaskCreationOptions.None, this.TaskScheduler);
}
public Task<TResult> Run<TResult>(
Func<Task<TResult>> taskFunc,
CancellationToken token = default(CancellationToken))
{
return Task.Factory.StartNew<Task<TResult>>(async () =>
{
OperationStarted();
try
{
return await taskFunc();
}
finally
{
OperationCompleted();
}
}, token, TaskCreationOptions.None, this.TaskScheduler).Unwrap();
}
// SynchronizationContext methods
public override SynchronizationContext CreateCopy()
{
return this;
}
public override void OperationStarted()
{
// called when async void method is invoked
Interlocked.Increment(ref _pendingOps);
}
public override void OperationCompleted()
{
// called when async void method completes
if (Interlocked.Decrement(ref _pendingOps) == 0)
{
_callbacks.CompleteAdding();
}
}
public override void Post(SendOrPostCallback d, object state)
{
_callbacks.Add((d, state));
}
public override void Send(SendOrPostCallback d, object state)
{
throw new NotImplementedException(nameof(Send));
}
}
}
I am very new to the async/await usage. I am trying to abstract the asynchrony and await conditionally in the UI. I have an abstract base class:
public abstract class Base
{
public abstract bool IsRunning { get; }
public abstract Task<bool> Run();
}
and from it some derived instances, first one being synchronous:
internal class Derived1 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived1(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return false; }
}
public override Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
return task;
}
}
and a derived class for an asynchronous implementation:
internal class Derived2 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived2(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return task != null && task.Status == TaskStatus.Running; }
}
public override Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
return task;
}
}
Then in the UI, I would like to await on asynchronous task (if user specified so in a run-time config), as follows:
internal class CaseMenuHandler
{
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool ok = true;
if( something_holds ) {
ok = await baseCaseRunner.Run();
}
else {
ok = baseCaseRunner.Run().Result;
}
}
catch (Exception e)
{
LogError(...);
}
}
}
Hope this is clear. Can I do the above, specifically awaiting conditionally inside an if block? Ideally I would like to make the Base class only return bool and not Task<bool> for the Run method, and only have the Derived2 class override to return a Task<bool>, but I am not clear on how to do that. Perhaps I should return the task.Result inside the Run method of Derived2? If there's a better way to this including the abstraction or any other corrections, please let me know. Appreciate any ideas.
EDIT #1
The Run method form for the synchronous implementation in Derived1 has been clarified in the responses below. I am not allowed to change the signature of the DoSomething method though, so given that, my Run method in Derived2 (asynchronous implementation) looks as follows now (thanks to #Stripling's comments):
public override async Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
task.Start();
return await task;
}
EDIT #2:
When I try the above (also tried putting a task.Start() call after the task definition, I get the following error:
Cross-thread operation not valid: Application accessed domain object from a thread other than a legal thread.
Can I do the above, specifically awaiting conditionally inside an if block?
You can, but you shouldn't have to. If you do things right, there's no great advantage to specifically invoking a synchronous task in a blocking fashion: as a general rule, you can just await the Task that's returned, and if it represents a synchronous task then the await will be resolved synchronously with very little overhead.
When I say "if you do things right", here's the right way:
// synchronous
public override Task<bool> Run()
{
var result = DoSomething();
return Task.FromResult(result);
}
// asynchronous
public override async Task<bool> Run()
{
var result = await DoSomethingAsync();
return result;
}
awaiting the result of the first example above will not do any thread-switching or anything like that. awaiting the result of the second might, depending on the implementation of DoSomethingAsync(). There's no particular need for a layer of abstraction: you can always check a Task to whether it's completed or not, and awaiting an already-completed task will always return a value immediately.
I don't see how your synchronous version is synchronous, you still use the Task.Run(, I would have expected
internal class Derived1 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived1(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return false; }
}
public override Task<bool> Run()
{
bool ok = DoSomething();
return Task.FromResult(ok);
}
}
If you do it that way instead of the way you are doing it, your other code just becomes
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool ok = true;
ok = await baseCaseRunner.Run();
}
catch (Exception e)
{
LogError(...);
}
}
}
The asynchronous version will run asynchronously and the synchronous version will run synchronously.
Your "async version" is not really async either, see Stripling's answer for the correct way to do that method.
Then in the UI, I would like to await on asynchronous task (if user specified so in a run-time config)
First off, I just have to say that this is a really bad idea. Some things should be configurable, and some should not. The asynchrony of operations should not be configurable. Period. This is a horrible design, and the first thing I would do is push back hard against ridiculous "requirements" like this. It literally makes the same amount of sense as a configurable flag for whether or not to throw exceptions.
That said, it can be done. It's painful, difficult to maintain, and completely useless at the end of the day. But hey, I assume you're getting paid for this so it's all good, eh?
If you must do this for political reasons (there are absolutely no valid technical reasons), then I recommend you use the Boolean Argument Hack from my article on brownfield async. One problem with just blocking (Result) is that it doesn't work if Run uses await (for reasons described on my blog).
The boolean argument hack simply adds a boolean argument indicating whether the method is expected to complete synchronously or not.
public abstract class Base
{
public abstract Task<bool> RunAsync(bool sync);
}
The semantics here are that if sync is true, then the task returned from RunAsync must already be completed.
Your implementation then looks like:
internal class Derived1 : Base
{
public override async Task<bool> RunAsync(bool sync)
{
IsRunning = true;
try
{
if (sync)
return DoSomething();
return await Task.Run(() => DoSomething());
}
finally
{
IsRunning = false;
}
}
}
And it's called like:
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool sync = !something_holds;
bool ok = await baseCaseRunner.RunAsync(sync);
}
catch (Exception e)
{
LogError(...);
}
}
}
Note that it can always be called with await, but OnRun will actually be synchronous if sync is true. This is due to the "await fast path" - the fact that await first checks whether the task is already complete, and if it is, it continues synchronously (as described in my async intro blog post).
Use Task.FromResult to return a task that contains the result that was computed synchronously, and await.
bool ok = DoSomething();
return Task.FromResult(ok);
As a side note I'd not put synchronous code in a method that was generally intended to be asynchronous (or that is synchronous in other classes/places) and vice versa. I'd use different interfaces/base classes for a synchronous and an asynchronous implementation.
interface IRunnable
{
bool IsRunning;
bool Run();
}
interface IRunnableAsync
{
bool IsRunning;
Task<bool> RunAsync();
}
What I would like to write is the following:
async void Foo()
{
var result = await GetMyTask().IgnoreCancelAndFailure();
ProcessResult(result);
}
Instead of:
void Foo()
{
GetMyTask().ContinueWith(task => ProcessResult(task.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
}
However I don't know how to implement the method IgnoreCancelAndFailure, which would have the following signature:
//On cancel or failure this task should simply stop and never complete.
Task<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
throw new NotImplementedException();
}
If possible, how should I implement IgnoreCancelAndFailure?
You could do something like that, but you need to know what you want the method to return in case of failure, since a return value is expected:
public static async Task<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
try
{
return await task;
}
catch
{
return ???; // whatever you want to return in this case
}
}
If it's a Task with no result, just leave the catch empty (or perhaps log the exception... swallowed exceptions make for hard debugging)
If you just want to execute ProcessResult only when GetMyTask succeeds, you can do this:
async void Foo()
{
try
{
var result = await GetMyTask();
ProcessResult(result);
}
catch(Exception ex)
{
// handle the exception somehow, or ignore it (not recommended)
}
}
You will never be able to stop your code from continuing expect when killing the thread or process. keep in mind that the await task can be considered a function call that will always have to return a value or throw an exception.
The closest way to shorten your code is creating a wrapper function that uses the ProcessResult method as Action argument.
Something like that:
public static async Task IgnoreCancelAndFailure<T>(this Task<T> task, Action<T> resultProcessor)
{
task.ContinueWith(t => resultProcessor(t.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
}
async void Foo()
{
GetMyTask().IgnoreCancelAndFailure(ProcessResult);
}
I think I found the answer. The following seems to do the trick. It uses the awaitable pattern. Could you guys confirm that this isn't evil?
class User
{
async void Foo()
{
var result = await GetMyTask().IgnoreCancelAndFailure();
ProcessResult(result);
}
}
public static class TaskExtenstions
{
public static SilentTask<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
return new SilentTask<T>(task);
}
}
public class SilentTask<T>
{
private readonly Task<T> _inner;
public SilentTask(Task<T> inner)
{
_inner = inner;
}
public SilentAwaiter GetAwaiter()
{
return new SilentAwaiter(_inner);
}
public class SilentAwaiter : INotifyCompletion
{
private readonly TaskAwaiter<T> _inner;
private readonly Task<T> _task;
public SilentAwaiter(Task<T> task)
{
_task = task;
_inner = task.GetAwaiter();
}
public bool IsCompleted
{
get
{
return _task.Status == TaskStatus.RanToCompletion;
}
}
public void OnCompleted(Action continuation)
{
_inner.OnCompleted(() =>
{
if (IsCompleted)
{
continuation();
}
});
}
public T GetResult()
{
return _inner.GetResult();
}
}
}
I generated a proxy with task-based operations.
How should this service be invoked properly (disposing of the ServiceClient and the OperationContext afterwards) using async/await?
My first attempt was:
public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
{
return await helper.Proxy.GetHomeInfoAsync(timestamp);
}
}
Being ServiceHelper a class which creates the ServiceClient and the OperationContextScope and disposes of them afterwards:
try
{
if (_operationContextScope != null)
{
_operationContextScope.Dispose();
}
if (_serviceClient != null)
{
if (_serviceClient.State != CommunicationState.Faulted)
{
_serviceClient.Close();
}
else
{
_serviceClient.Abort();
}
}
}
catch (CommunicationException)
{
_serviceClient.Abort();
}
catch (TimeoutException)
{
_serviceClient.Abort();
}
catch (Exception)
{
_serviceClient.Abort();
throw;
}
finally
{
_operationContextScope = null;
_serviceClient = null;
}
However, this failed miserably when calling two services at the same time with the following error: "This OperationContextScope is being disposed on a different thread than it was created."
MSDN says:
Do not use the asynchronous “await” pattern within a OperationContextScope block. When the continuation occurs, it may run on a different thread and OperationContextScope is thread specific. If you need to call “await” for an async call, use it outside of the OperationContextScope block.
So that's the problem! But, how do we fix it properly?
This guy did just what MSDN says:
private async void DoStuffWithDoc(string docId)
{
var doc = await GetDocumentAsync(docId);
if (doc.YadaYada)
{
// more code here
}
}
public Task<Document> GetDocumentAsync(string docId)
{
var docClient = CreateDocumentServiceClient();
using (new OperationContextScope(docClient.InnerChannel))
{
return docClient.GetDocumentAsync(docId);
}
}
My problem with his code, is that he never calls Close (or Abort) on the ServiceClient.
I also found a way of propagating the OperationContextScope using a custom SynchronizationContext. But, besides the fact that it's a lot of "risky" code, he states that:
It’s worth noting that it does have a few small issues regarding the disposal of operation-context scopes (since they only allow you to dispose them on the calling thread), but this doesn’t seem to be an issue since (at least according to the disassembly), they implement Dispose() but not Finalize().
So, are we out of luck here? Is there a proven pattern for calling WCF services using async/await AND disposing of BOTH the ServiceClient and the OperationContextScope? Maybe someone form Microsoft (perhaps guru Stephen Toub :)) can help.
Thanks!
[UPDATE]
With a lot of help from user Noseratio, I came up with something that works: do not use OperationContextScope. If you are using it for any of these reasons, try to find a workaround that fits your scenario. Otherwise, if you really, really, need OperationContextScope, you'll have to come up with an implementation of a SynchronizationContext that captures it, and that seems very hard (if at all possible - there must be a reason why this isn't the default behavior).
So, the full working code is:
public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
{
return await helper.Proxy.GetHomeInfoAsync(timestamp);
}
}
With ServiceHelper being:
public class ServiceHelper<TServiceClient, TService> : IDisposable
where TServiceClient : ClientBase<TService>, new()
where TService : class
{
protected bool _isInitialized;
protected TServiceClient _serviceClient;
public TServiceClient Proxy
{
get
{
if (!_isInitialized)
{
Initialize();
_isInitialized = true;
}
else if (_serviceClient == null)
{
throw new ObjectDisposedException("ServiceHelper");
}
return _serviceClient;
}
}
protected virtual void Initialize()
{
_serviceClient = new TServiceClient();
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
try
{
if (_serviceClient != null)
{
if (_serviceClient.State != CommunicationState.Faulted)
{
_serviceClient.Close();
}
else
{
_serviceClient.Abort();
}
}
}
catch (CommunicationException)
{
_serviceClient.Abort();
}
catch (TimeoutException)
{
_serviceClient.Abort();
}
catch (Exception)
{
_serviceClient.Abort();
throw;
}
finally
{
_serviceClient = null;
}
}
}
}
Note that the class supports extension; perhaps you need to inherit and provide credentials.
The only possible "gotcha" is that in GetHomeInfoAsync, you can't just return the Task you get from the proxy (which should seem natural, why create a new Task when you already have one). Well, in this case you need to await the proxy Task and then close (or abort) the ServiceClient, otherwise you'll be closing it right away after invoking the service (while bytes are being sent over the wire)!
OK, we have a way to make it work, but it'd be nice to get an answer from an authoritative source, as Noseratio states.
I think a feasible solution might be to use a custom awaiter to flow the new operation context via OperationContext.Current. The implementation of OperationContext itself doesn't appear to require thread affinity. Here is the pattern:
async Task TestAsync()
{
using(var client = new WcfAPM.ServiceClient())
using (var scope = new FlowingOperationContextScope(client.InnerChannel))
{
await client.SomeMethodAsync(1).ContinueOnScope(scope);
await client.AnotherMethodAsync(2).ContinueOnScope(scope);
}
}
Here is the implementation of FlowingOperationContextScope and ContinueOnScope (only slightly tested):
public sealed class FlowingOperationContextScope : IDisposable
{
bool _inflight = false;
bool _disposed;
OperationContext _thisContext = null;
OperationContext _originalContext = null;
public FlowingOperationContextScope(IContextChannel channel):
this(new OperationContext(channel))
{
}
public FlowingOperationContextScope(OperationContext context)
{
_originalContext = OperationContext.Current;
OperationContext.Current = _thisContext = context;
}
public void Dispose()
{
if (!_disposed)
{
if (_inflight || OperationContext.Current != _thisContext)
throw new InvalidOperationException();
_disposed = true;
OperationContext.Current = _originalContext;
_thisContext = null;
_originalContext = null;
}
}
internal void BeforeAwait()
{
if (_inflight)
return;
_inflight = true;
// leave _thisContext as the current context
}
internal void AfterAwait()
{
if (!_inflight)
throw new InvalidOperationException();
_inflight = false;
// ignore the current context, restore _thisContext
OperationContext.Current = _thisContext;
}
}
// ContinueOnScope extension
public static class TaskExt
{
public static SimpleAwaiter<TResult> ContinueOnScope<TResult>(this Task<TResult> #this, FlowingOperationContextScope scope)
{
return new SimpleAwaiter<TResult>(#this, scope.BeforeAwait, scope.AfterAwait);
}
// awaiter
public class SimpleAwaiter<TResult> :
System.Runtime.CompilerServices.INotifyCompletion
{
readonly Task<TResult> _task;
readonly Action _beforeAwait;
readonly Action _afterAwait;
public SimpleAwaiter(Task<TResult> task, Action beforeAwait, Action afterAwait)
{
_task = task;
_beforeAwait = beforeAwait;
_afterAwait = afterAwait;
}
public SimpleAwaiter<TResult> GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get
{
// don't do anything if the task completed synchronously
// (we're on the same thread)
if (_task.IsCompleted)
return true;
_beforeAwait();
return false;
}
}
public TResult GetResult()
{
return _task.Result;
}
// INotifyCompletion
public void OnCompleted(Action continuation)
{
_task.ContinueWith(task =>
{
_afterAwait();
continuation();
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
SynchronizationContext.Current != null ?
TaskScheduler.FromCurrentSynchronizationContext() :
TaskScheduler.Current);
}
}
}
Simple way is to move the await outside the using block
public Task<Document> GetDocumentAsync(string docId)
{
var docClient = CreateDocumentServiceClient();
using (new OperationContextScope(docClient.InnerChannel))
{
var task = docClient.GetDocumentAsync(docId);
}
return await task;
}
I decide to write my own code that helps with this, posting in case this helps anyone. Seems to be a little less to go wrong (unforeseen races etc) vs the SimpleAwaiter implementation above but you be the judge:
public static class WithOperationContextTaskExtensions
{
public static ContinueOnOperationContextAwaiter<TResult> WithOperationContext<TResult>(this Task<TResult> #this, bool configureAwait = true)
{
return new ContinueOnOperationContextAwaiter<TResult>(#this, configureAwait);
}
public static ContinueOnOperationContextAwaiter WithOperationContext(this Task #this, bool configureAwait = true)
{
return new ContinueOnOperationContextAwaiter(#this, configureAwait);
}
public class ContinueOnOperationContextAwaiter : INotifyCompletion
{
private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter _awaiter;
private OperationContext _operationContext;
public ContinueOnOperationContextAwaiter(Task task, bool continueOnCapturedContext = true)
{
if (task == null) throw new ArgumentNullException("task");
_awaiter = task.ConfigureAwait(continueOnCapturedContext).GetAwaiter();
}
public ContinueOnOperationContextAwaiter GetAwaiter() { return this; }
public bool IsCompleted { get { return _awaiter.IsCompleted; } }
public void OnCompleted(Action continuation)
{
_operationContext = OperationContext.Current;
_awaiter.OnCompleted(continuation);
}
public void GetResult()
{
OperationContext.Current = _operationContext;
_awaiter.GetResult();
}
}
public class ContinueOnOperationContextAwaiter<TResult> : INotifyCompletion
{
private readonly ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter _awaiter;
private OperationContext _operationContext;
public ContinueOnOperationContextAwaiter(Task<TResult> task, bool continueOnCapturedContext = true)
{
if (task == null) throw new ArgumentNullException("task");
_awaiter = task.ConfigureAwait(continueOnCapturedContext).GetAwaiter();
}
public ContinueOnOperationContextAwaiter<TResult> GetAwaiter() { return this; }
public bool IsCompleted { get { return _awaiter.IsCompleted; } }
public void OnCompleted(Action continuation)
{
_operationContext = OperationContext.Current;
_awaiter.OnCompleted(continuation);
}
public TResult GetResult()
{
OperationContext.Current = _operationContext;
return _awaiter.GetResult();
}
}
}
Usage (a little manual and nesting is untested...):
/// <summary>
/// Make a call to the service
/// </summary>
/// <param name="action"></param>
/// <param name="endpoint"> </param>
public async Task<ResultCallWrapper<TResult>> CallAsync<TResult>(Func<T, Task<TResult>> action, EndpointAddress endpoint)
{
using (ChannelLifetime<T> channelLifetime = new ChannelLifetime<T>(ConstructChannel(endpoint)))
{
// OperationContextScope doesn't work with async/await
var oldContext = OperationContext.Current;
OperationContext.Current = new OperationContext((IContextChannel)channelLifetime.Channel);
var result = await action(channelLifetime.Channel)
.WithOperationContext(configureAwait: false);
HttpResponseMessageProperty incomingMessageProperty = (HttpResponseMessageProperty)OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name];
string[] keys = incomingMessageProperty.Headers.AllKeys;
var headersOrig = keys.ToDictionary(t => t, t => incomingMessageProperty.Headers[t]);
OperationContext.Current = oldContext;
return new ResultCallWrapper<TResult>(result, new ReadOnlyDictionary<string, string>(headersOrig));
}
}
Async flow is supported from .Net 4.6.2.
We have an ASP.Net WebApi application running on .Net 4.6 where we used the accepted answer. TaskScheduler.FromCurrentSynchronizationContext() caused deadlock issues when the current synchronization context is AspNetSynchronizationContext.
I believe the continuation task was queued after the actual task, causing the actual task is waiting on the continuation whereas the continuation task must run to complete the actual task. i.e. tasks are both waiting on each other.
So I fixed the issue by changing using continuation task to use TaskAwaiter. See: https://blogs.msdn.microsoft.com/lucian/2012/12/11/how-to-write-a-custom-awaiter/
It's been a while on this one, but I'll chime in with my own home-baked solution.
If one doesn't mind doing without OperationContextScope, one might consider something along these lines:
Extension methods
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace Intexx.ServiceModel
{
public static class WcfExtensions
{
[DebuggerStepThrough]
public static void Call<TChannel>(this TChannel Client, Action<TChannel> Method) where TChannel : ICommunicationObject
{
try
{
Method.Invoke(Client);
}
finally
{
Cleanup(Client);
}
}
[DebuggerStepThrough]
public static TResult Call<TChannel, TResult>(this TChannel Client, Func<TChannel, TResult> Method) where TChannel : ICommunicationObject
{
try
{
return Method.Invoke(Client);
}
finally
{
Cleanup(Client);
}
}
[DebuggerStepThrough]
public async static Task CallAsync<TChannel>(this TChannel Client, Func<TChannel, Task> Method) where TChannel : ICommunicationObject
{
try
{
await Method.Invoke(Client);
}
finally
{
Cleanup(Client);
}
}
[DebuggerStepThrough]
public async static Task<TResult> CallAsync<TChannel, TResult>(this TChannel Client, Func<TChannel, Task<TResult>> Method) where TChannel : ICommunicationObject
{
try
{
return await Method.Invoke(Client);
}
finally
{
Cleanup(Client);
}
}
private static void Cleanup<TChannel>(TChannel Client) where TChannel : ICommunicationObject
{
try
{
if (Client.IsNotNull)
{
if (Client.State == CommunicationState.Faulted)
Client.Abort();
else
Client.Close();
}
}
catch (Exception ex)
{
Client.Abort();
if (!ex is CommunicationException && !ex is TimeoutException)
throw new Exception(ex.Message, ex);
}
finally
{
Client = null;
}
}
}
}
Client class
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace Reader
{
public class Client
{
public static CemReaderClient Create()
{
Tuple<Channels.Binding, EndpointAddress, double> oService;
try
{
oService = Main.Services(typeof(ICemReader));
return new CemReaderClient(oService.Item1, oService.Item2);
}
catch (KeyNotFoundException ex)
{
return null;
}
}
}
}
Usage (in VB, as the code wouldn't convert)
Using oReader As Reader.CemReaderClient = Reader.Client.Create
If oReader.IsNotNothing Then
Dim lIsReading = Await oReader.CallAsync(Function(Reader As Reader.CemReaderClient)
Me.ConfigFilePath = If(Me.ConfigFilePath, Reader.GetConfigFilePath)
Me.BackupDrive = If(Me.BackupDrive, Reader.GetBackupDrive)
Me.SerialPort = If(Me.SerialPort, Reader.GetSerialPort)
Me.LogFolder = If(Me.LogFolder, Reader.GetLogFolder)
Return Reader.GetIsReadingAsync
End Function)
End If
End Using
I've had this running reliably in production under frequency loads of around 15 calls/sec on the client side (that's as fast as serial processing would allow). That was on a single thread, though—this hasn't been rigorously tested for thread safety. YMMV.
In my case, I decided to roll the extension methods into their own private NuGet package. The whole construct has turned out to be pretty handy.
This will have to be reevaluated, of course, if OperationContextScope ever ends up being needed.
The bit with the Tuple in the Client class is for Service Discovery support. If anyone would like to see that code as well, give a shout and I'll update my answer.
I am a little bit confused, I found this Blog : Task-based asynchronous operation in WCF
There this is a async wcf communication:
[ServiceContract]
public interface IMessage
{
[OperationContract]
Task<string> GetMessages(string msg);
}
public class MessageService : IMessage
{
async Task<string> IMessage.GetMessages(string msg)
{
var task = Task.Factory.StartNew(() =>
{
Thread.Sleep(10000);
return "Return from Server : " + msg;
});
return await task.ConfigureAwait(false);
}
}
Client:
var client = new Proxy("BasicHttpBinding_IMessage");
var task = Task.Factory.StartNew(() => client.GetMessages("Hello"));
var str = await task;
So is this also a good way??
I ran into the same issue, however it dawned on me that I didn't need to use async/await at all.
Since you are not post processing the result, there is no need to wait for the reply. If you do need to process the result, just use the old fashion TPL continuation.
public Task<MyDomainModel> GetHomeInfoAsync(DateTime timestamp)
{
using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
{
return helper.Proxy.GetHomeInfoAsync(timestamp).ContinueWith(antecedent=>processReplay(antecedent.Result));
}
}
I don't know if this helps, but after seeing this question on my search to answer the same question, I came upon this.
Leading from that, I should think your code should look something like this:
public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
using (var client = CreateDocumentServiceClient())
{
await client.BeginGetHomeInfoAsync(timestamp);
}
}
I realise my answer comes rather late :P but it might help someone else.
I’m currently trying to make my application using some Async methods.
All my IO is done through explicit implementations of an interface and I am a bit confused about how to make the operations async.
As I see things I have two options in the implementation:
interface IIO
{
void DoOperation();
}
OPTION1:
Do an implicit implementation async and await the result in the implicit implementation.
class IOImplementation : IIO
{
async void DoOperation()
{
await Task.Factory.StartNew(() =>
{
//WRITING A FILE OR SOME SUCH THINGAMAGIG
});
}
#region IIO Members
void IIO.DoOperation()
{
DoOperation();
}
#endregion
}
OPTION2:
Do the explicit implementation async and await the task from the implicit implementation.
class IOAsyncImplementation : IIO
{
private Task DoOperationAsync()
{
return new Task(() =>
{
//DO ALL THE HEAVY LIFTING!!!
});
}
#region IIOAsync Members
async void IIO.DoOperation()
{
await DoOperationAsync();
}
#endregion
}
Are one of these implementations better than the other or is there another way to go that I am not thinking of?
Neither of these options is correct. You're trying to implement a synchronous interface asynchronously. Don't do that. The problem is that when DoOperation() returns, the operation won't be complete yet. Worse, if an exception happens during the operation (which is very common with IO operations), the user won't have a chance to deal with that exception.
What you need to do is to modify the interface, so that it is asynchronous:
interface IIO
{
Task DoOperationAsync(); // note: no async here
}
class IOImplementation : IIO
{
public async Task DoOperationAsync()
{
// perform the operation here
}
}
This way, the user will see that the operation is async and they will be able to await it. This also pretty much forces the users of your code to switch to async, but that's unavoidable.
Also, I assume using StartNew() in your implementation is just an example, you shouldn't need that to implement asynchronous IO. (And new Task() is even worse, that won't even work, because you don't Start() the Task.)
Better solution is to introduce another interface for async operations. New interface must inherit from original interface.
Example:
interface IIO
{
void DoOperation();
}
interface IIOAsync : IIO
{
Task DoOperationAsync();
}
class ClsAsync : IIOAsync
{
public void DoOperation()
{
DoOperationAsync().GetAwaiter().GetResult();
}
public async Task DoOperationAsync()
{
//just an async code demo
await Task.Delay(1000);
}
}
class Program
{
static void Main(string[] args)
{
IIOAsync asAsync = new ClsAsync();
IIO asSync = asAsync;
Console.WriteLine(DateTime.Now.Second);
asAsync.DoOperation();
Console.WriteLine("After call to sync func using Async iface: {0}",
DateTime.Now.Second);
asAsync.DoOperationAsync().GetAwaiter().GetResult();
Console.WriteLine("After call to async func using Async iface: {0}",
DateTime.Now.Second);
asSync.DoOperation();
Console.WriteLine("After call to sync func using Sync iface: {0}",
DateTime.Now.Second);
Console.ReadKey(true);
}
}
P.S.
Redesign your async operations so they return Task instead of void, unless you really must return void.
I created a sample app based on Svick's answer and found that calling IOImplementation.DoOperationAsync() without the async keyword does not result in a compiler/Visual Studio warning. This was based on Visual Studio 2019 and .NET Core 3.1.
Sample code below.
public interface ISomething
{
Task DoSomethingAsync();
}
public class Something : ISomething
{
public async Task DoSomethingAsync()
{
await Task.Run(() => Thread.Sleep(2000));
Console.WriteLine("Message from DoSomethingAsync");
throw new Exception("Some exception");
}
}
class Program
{
static void Main(string[] args)
{
ISomething something = new Something();
Console.WriteLine("pre something.DoSomethingAsync() without await");
something.DoSomethingAsync(); // No compiler warning for missing "await" and exception is "swallowed"
Console.WriteLine("post something.DoSomethingAsync() without await");
Thread.Sleep(3000);
// Output:
// pre something.DoSomethingAsync() without await
// post something.DoSomethingAsync() without await
// Message from DoSomethingAsync
}
}
An abstract class can be used instead of an interface (in C# 7.3).
// Like interface
abstract class IIO
{
public virtual async Task<string> DoOperation(string Name)
{
throw new NotImplementedException(); // throwing exception
// return await Task.Run(() => { return ""; }); // or empty do
}
}
// Implementation
class IOImplementation : IIO
{
public override async Task<string> DoOperation(string Name)
{
return await await Task.Run(() =>
{
if(Name == "Spiderman")
return "ok";
return "cancel";
});
}
}