Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a simple Async Workflow Activity

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 ...

enter image description here

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.

like image 456
War Avatar asked Nov 07 '22 08:11

War


1 Answers

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)

like image 67
War Avatar answered Nov 15 '22 05:11

War