Creating a simple Async Workflow Activity - c#

I'm trying to get in to workflow foundation but apparently i can't seem to get even the most basic implementation of an async activity working.
Could anyone point me in the right direction with this activity I have put together in order to make an async OData request using HttpClient ...
Firstly I created a base type extending from AsyncCodeActivity ...
public abstract class ODataActivity<TResult> : AsyncCodeActivity<TResult>, IDisposable
{
protected HttpClient Api =
new HttpClient(
new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }
)
{ BaseAddress = new Uri(new Config().ApiRoot) };
bool disposed = false;
public void Dispose()
{
Dispose(disposed);
}
public virtual void Dispose(bool disposed)
{
if (!disposed)
{
Api.Dispose();
Api = null;
}
}
}
Next I inherit that to provide my implementation ...
public class ODataFetchActivity<TResult> : ODataActivity<TResult>
{
public string Query { get; set; }
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var task = Api.GetAsync(Query)
.ContinueWith(t => t.Result.Content.ReadAsAsync<TResult>())
.ContinueWith(t => callback(t));
context.UserState = task;
return task;
}
protected override TResult EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
var response = ((Task<TResult>)result).Result;
context.SetValue(Result, response);
return response;
}
}
... the idea being that this activity can do only get requests, i could then implement a post, put and delete to get full crud in the same manner on top of my base type above.
The problem comes when i add this to a workflow and try to execute the flow using a re-hosted designer in a new wpf app resulting in the following exception ...
Edit:
So I did a little bit more tinkering and have something that appears to not complain but i'm not convinced this is a "good" way to handle this as Task implements IAsyncResult directly and it feels like i'm jumping through a bunch of hoops I perhaps don't need to.
public class ODataFetchActivity<TResult> : ODataActivity<TResult>
{
public string Query { get; set; }
Func<TResult> work;
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
work = () => Api.Get<TResult>(Query).Result;
context.UserState = work;
return work.BeginInvoke(callback, state);
}
protected override TResult EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
TResult response = work.EndInvoke(result);
Result.Set(context, response);
return response;
}
}
This appears to compile and run but i can't help but feel like there's a cleaner way to handle this.

Hmm apparently this works fine ...
public class ODataFetchActivity<TResult> : ODataActivity<TResult>
{
public string Query { get; set; }
Func<TResult> work;
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
work = () => Api.Get<TResult>(Query).Result;
context.UserState = work;
return work.BeginInvoke(callback, state);
}
protected override TResult EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
TResult response = work.EndInvoke(result);
Result.Set(context, response);
return response;
}
}
I was getting some odd behavior from the designer re-hosting where it would run the previous version until a save made (no idea why)

Related

How to make async call in the client Interceptor method AsyncUnaryCall

I try to implement some caching functionality for the grpc client call.
There is a custom interceptor which overrides the method AsyncUnaryCall for handling client calls. But it doesn't compile as AsyncUnaryCall returns its own type instead of async Task so it doesn't allow it to make awaitable calls.
internal class MyCacheInterceptor : Interceptor
{
private readonly IMyCacheService _cacheService;
public MyCacheInterceptor(IMyCacheService cacheService)
{
_cacheService = cacheService;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var key = GetCacheKey(request, context);
var cacheValue = await _cacheService.GetCacheAsync<TResponse>(key);
if (cacheValue != null)
{
var test = new AsyncUnaryCall<TResponse>(
Task.FromResult(cacheValue),
null!,
null!,
null!,
null!);
}
else
{
return base.AsyncUnaryCall(request, context, continuation);
}
}
}
I found a similar question here https://github.com/grpc/grpc/issues/21489 and ASPNET CORE GRPC async interceptor method
They use
var ctn = continuation(request, context);
but calling the continuation delegate actually starts grpc request to the server.
So are there some workarounds on how can I achieve what I need?
OK; this is untested - I cannot emphasize quite how untested this is! but:
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation) where TRequest : class where TResponse : class
{
var obj = new MyStateObj<TRequest, TResponse>(_cacheService, request, context, continuation);
return new AsyncUnaryCall<TResponse>(obj.Response,
static s => ((MyStateObj<TRequest, TResponse>)s).Headers,
static s => ((MyStateObj<TRequest, TResponse>)s).Status,
static s => ((MyStateObj<TRequest, TResponse>)s).Trailers,
static s => ((MyStateObj<TRequest, TResponse>)s).Dispose(),
obj);
}
class MyStateObj<TRequest, TResponse>
where TRequest : class
where TResponse: class
{
private readonly TaskCompletionSource<TResponse> response = new();
private readonly TaskCompletionSource<Metadata> headers = new();
private AsyncUnaryCall<TResponse>? call;
public Status Status { get; private set; }
public Metadata Trailers { get; private set; } = Metadata.Empty;
public void Dispose() => call?.Dispose();
public Task<TResponse> Response => response.Task;
public Task<Metadata> Headers => headers.Task;
public MyStateObj(IMyCacheService cacheService,
TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
_ = Task.Run(async () =>
{
try
{
var key = GetCacheKey(request, context);
var cacheValue = await cacheService.GetCacheAsync<TResponse>(key);
if (cacheValue is not null)
{
Status = Status.DefaultSuccess;
headers.TrySetResult(Metadata.Empty);
response.TrySetResult(cacheValue);
}
else
{
call = continuation(request, context);
headers.TrySetResult(await call.ResponseHeadersAsync);
var result = await call.ResponseAsync;
Status = call.GetStatus();
Trailers = call.GetTrailers();
response.TrySetResult(result);
}
}
catch (Exception ex)
{
if (ex is RpcException rpc)
{
Status = rpc.Status;
Trailers = rpc.Trailers;
}
else
{
Status = new Status(StatusCode.Internal, ex.Message);
}
headers.TrySetException(ex);
response.TrySetException(ex);
}
});
}
}
What it does is:
create a custom state object that mimics the internal state of an async unary call
begins an async task execution that invokes your cache, setting the local state if successful, otherwise deferring to the downstream continuation and using that to set the local state
as a side note: if possible, context.Options.CancellationToken should be used as a cancellation for GetCacheAsync.
If desirable, it would also be possible to start the GetCacheAsync call before the Task.Run, allowing you to test .IsCompletedSuccessfully, and in that scenario avoid the Task.Run altogether in the fully synchronous case.
That would look like:
var key = GetCacheKey(request, context);
var pending = cacheService.GetCacheAsync<TResponse>(key);
if (pending.IsCompletedSuccessfully)
{
Status = Status.DefaultSuccess;
headers.TrySetResult(Metadata.Empty);
response.TrySetResult(pending.Result);
return; // all completed synchronously
}
_ = Task.Run(async () =>
{
try
{
var cacheValue = await pending;
// ...
I aslo found the next solution, which seems to be worked. But i am not sure about posisbe issues with passing some arguments as null! into AsyncUnaryCallContinuation.
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var cachKey = GetCacheKey(request, context);
AsyncUnaryCallContinuation<TRequest, TResponse> myContinuation =
(req, resp) =>
{
return new AsyncUnaryCall<TResponse>(
MyCacheHandle(cachKey, request, context, continuation),
null!,
null!,
null!,
() => { });
};
return base.AsyncUnaryCall(request, context, myContinuation);
}
private async Task<TResponse> MyCacheHandle<TRequest, TResponse>(string cachKey,
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
where TRequest : class where TResponse : class
{
try
{
if (!string.IsNullOrEmpty(cachKey))
{
var value = await _cacheService.GetCacheAsync<TResponse>(cachKey);
if (value != null)
{
return value;
}
}
var con = continuation(request, context);
return await con.ResponseAsync;
}
catch (Exception ex)
{
throw new InvalidOperationException("Custom error", ex);
}
}

How can I listen in real-time for webhooks in asp.net webforms?

I'm trying to capture the webhooks from the site https://www.unbounce.com in my asp.net web forms application.
I've created HttpAsyncHandler in WebHookHandler.cs
public class WebHookHandler:IHttpAsyncHandler
{
public WebHookHandler()
{
//
// TODO: Add constructor logic here
//
}
public bool IsReusable { get { return false; } }
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n");
AsynchOperation asynch = new AsynchOperation(cb, context, extraData);
asynch.StartAsyncWork();
return asynch;
}
public void EndProcessRequest(IAsyncResult result)
{
}
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException();
}
}
class AsynchOperation : IAsyncResult
{
private bool _completed;
private object _state;
private AsyncCallback _callback;
private HttpContext _context;
bool IAsyncResult.IsCompleted { get { return _completed; } }
WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
object IAsyncResult.AsyncState { get { return _state; } }
bool IAsyncResult.CompletedSynchronously { get { return false; } }
public AsynchOperation(AsyncCallback callback, HttpContext context, object state)
{
_callback = callback;
_context = context;
_state = state;
_completed = false;
}
public void StartAsyncWork()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
}
private void StartAsyncTask(object workItemState)
{
_context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n");
_context.Response.Write("Hello World from Async Handler!\r\n");
using (var reader = new StreamReader(_context.Request.InputStream))
{
string postData = reader.ReadToEnd();
_context.Response.Write(postData);
}
_completed = true;
_callback(this);
}
}
and register my handler and add the map in web.config
<add verb="*" path="webhook.handler" name="WebHookAsyncHandler" type="WebHookHandler"/>
This all is actually taken from msdn (no reputation, sorry)
Next, the other site (unbounce.com) POST something like this:
data.json: {"time_submitted":["04:59 PM UTC"],"page_uuid":["3282389-f13a-44b0-9a49-6321b515d43"],"email":["test#test.com"],"page_name":["Test name"],"date_submitted":["2017-07-17"],"name":["tester"],"ip_address":["80.80.80.80"],"page_url":["http://somepage.url"],"variant":["a"]}
everytime the user presses the button. The POST url is: example.com/webhook.handler
But I don't get the posted data. The output is:
Begin IsThreadPoolThread is True
Completion IsThreadPoolThread is True
Hello World from Async Handler!
I tried also use _context.Request and _context.Request.Form before StreamReader, but they was NULL everytime.
I think, I have some global misunderstading of how these things work. Can you please help me to display the data from the POST request to my site on the page?
Well, it turned out, that everything was ok in my listing.
You just need to set up a good testing enviroment to catch these POSTs, or better, to do them yourself.

Shared resource and async Web API call

I have a simple Web API method that looks like this:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
TaskManager.Run is decalared like this:
public async Task Run(int id)
I was expecting it to return "Task was started" message immediately after TaskManager.Run(taskId) But the request continues to run synchronously.
But if to replace the call TaskManager.Run(taskId) with:
Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(100)));
Then it runs asynchronously.
So I believe this is something to do with the resources shared by TaskManager and main thread. Can a shared resource lock the execution?
I'm using Castle Windsor. One WindsorContainer container is declared in Web API project.
TaskManager utilizes BaseTaskRunner class inside of it. One more WindsorContainer is declared in BaseTaskRunner.
Web API's container uses LifeStyle.PerWebRequest for all components. BaseTaskRunner's container uses LifeStyle.Singleton (not sure if it's correct LifeStyle). Could the call be locked for example by DdContext or other classes declared in both of the containers?
UPD:
I don't want to wait the TaskManager.Run to complete. But what happens is that return statement still waits for the TaskManager.Run to complete (even without await statement on TaskManager.Run).
In other words it does not matter how I call the TaskManager.Run:
TaskManager.Run(taskId);
or
await TaskManager.Run(taskId);
It waits for TaskManager.Run to complete in both cases.
Here is the code of TaskManager:
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type, byte[] data = null, object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public async Task Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
Run(task, removeOnComplete);
}
public async Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public async Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
And some other classes:
public class SpreadsheetImportTaskRunner : BaseTaskRunner
{
public IForecastSpreadsheetManager SpreadsheetManager { get; set; }
protected override void Execute()
{
SpreadsheetManager.ImportActuals(Task.Data);
}
protected override void Initialize()
{
base.Initialize();
SpreadsheetManager = _container.Resolve<IForecastSpreadsheetManager>();
}
}
BaseTaskRunner:
public class BaseTaskRunner
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
protected IWindsorContainer _container = new WindsorContainer();
protected BackgroundTask Task { get; set; }
public async Task Run(BackgroundTask task)
{
Initialize();
Task = task;
try
{
Execute();
}
catch (Exception ex)
{
SetError(ex.ToString());
}
}
protected virtual void Execute()
{
}
protected virtual void Initialize()
{
_container.Install(new TaskRunnerComponentsInstaller());
TaskRepository = _container.Resolve<IRepository<BackgroundTask>>();
}
}
I still believe this is something to do with the WindsorContainer and common classes which are resolved in several different threads.
The issue is that you're not using await on the Task being returned from the invocation of the TaskManager.Run function. Consider the below:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
await TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
Now it will work asynchronously as you'd expect. The await sets a continuation marker in the async state-machine, instructing it to return to this portion of the method upon completion of the asynchronous operation defined in the TaskManager.Run.
UPDATE
You are missing lots of await statements, and there are times where you need to not mark methods as async. It appears as though there are some mis-understandings as it pertains to these keywords. Here is what your TaskManager class should look like.
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type,
byte[] data = null,
object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public ask Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
return Run(task, removeOnComplete);
}
public Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
return tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
return new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
}
Ideally, if the method is marked as a return type of Task and the method doesn't need to unwind any tasks within its execution it can simply return the Task functionality for its implementation. For example, notice how dramatically my TaskManager class differs from yours -- I'm only marking methods as async that need to actually await. These two keywords should be married, if a method uses async there should be an await. But only use await if the method needs to unwind and use the asynchronous operation.

Pattern for calling WCF service using async/await

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.

Checking that CancellationTokenSource.Cancel() was invoked with Moq

I have a conditional statement which should looks as follows:
//...
if(_view.VerifyData != true)
{
//...
}
else
{
_view.PermanentCancellation.Cancel();
}
where PermanentCancellation is of type CancellationTokenSource.
Im wondering how i should set this up in my mock of _view. All attempts thus far have failed :( and i cant find an example on google.
Any pointers would be appreciated.
Because CancellationTokenSource.Cancel is not virtual you cannot mock it with moq.
You have two options:
Create a wrapper interface:
public interface ICancellationTokenSource
{
void Cancel();
}
and an implementation which delegates to the wrapped CancellationTokenSource
public class CancellationTokenSourceWrapper : ICancellationTokenSource
{
private readonly CancellationTokenSource source;
public CancellationTokenSourceWrapper(CancellationTokenSource source)
{
this.source = source;
}
public void Cancel()
{
source.Cancel();
}
}
And use the ICancellationTokenSource as PermanentCancellation then you can create an Mock<ICancellationTokenSource> in your tests:
// arrange
var mockCancellationTokenSource = new Mock<ICancellationTokenSource>();
viewMock.SetupGet(m => m.PermanentCancellation)
.Returns(mockCancellationTokenSource.Object)
// act
// do something
// assert
mockCancellationTokenSource.Verify(m => m.Cancel());
And use the CancellationTokenSourceWrapper in your production code.
Or use a mocking framework which supports mocking non virtual members like:
Microsoft Fakes
Typemock isolator (commercial)
JustMock (commercial)
I went a step further and made a factory to create a CancellationTokenManager class that implements the interface. This was because my method has to take CancellationToken and I wanted granular control over .IsCancellationRequested():
My CancellationTokenManagerFactory:
public interface ICancellationTokenManagerFactory
{
ICancellationTokenManager CreateManager(CancellationToken token);
}
public class CancellationTokenManagerFactory : ICancellationTokenManagerFactory
{
public ICancellationTokenManager CreateManager(CancellationToken token)
{
return new CancellationTokenManager(token);
}
}
and the manager:
public interface ICancellationTokenManager
{
bool IsCancellationRequested { get; }
CancellationToken CancellationToken { get; }
}
public class CancellationTokenManager : ICancellationTokenManager
{
private readonly CancellationToken _token;
public CancellationTokenManager(CancellationToken token)
{
_token = token;
}
public bool IsCancellationRequested
{
get
{
return _token.IsCancellationRequested;
}
}
public CancellationToken CancellationToken => _token;
}
Then in a class utilizing:
public class MyService
{
private readonly ICancellationTokenManagerFactory _factory = factory;
public MyService(ICancellationTokenManagerFactory factory)
{
_factory = factory;
}
public void StartAsync(CancellationToken token)
{
manager = _factory.CreateManager(token);
//check if cancelled
if (!manager.IsCancellationRequested())
}
// do some work
}
}
}
Now if I check cancellation is requested more than once i can mock with different responses each time. Additionally, any interfaces like IHostService can still be utilized because CancellationToken is passed in although it doesn't necessarily matter what is in that token.

Categories