Async method BeginXXX EndXXX where EndXXX does not return result

Answered Async method BeginXXX EndXXX where EndXXX does not return result

  • Sunday, December 23, 2012 4:46 PM
     
      Has Code

    I have an observable that gets a list of WorkflowApplication instances, for each instance, I need to call BeginLoad and corresponding EndLoad. However, EndLoad does not return any value. How can I express this with Rx?

    var instancesObs = instanceStoreObs.Select(_=>FindExistingInstances());
    
    var loadedInstanceObs = instancesObs.Select(instance=>LoadInstance(instance));
    
    ??? LoadInstance(WorklowApplication instance)
    {
      return Observable.FromAsyncPattern<Guid,???>(instance.BeginLoad, instance.EndLoad)(instance.Id);
      
    // declaration of EndLoad is 
    // public void EndLoad([NotNull] IAsyncResult result) 
    
    }

All Replies

  • Sunday, December 23, 2012 5:35 PM
     
      Has Code

    Hi,

    There's no need to specify the generic type arguments, the compiler will infer them for you.  It will choose the following overload:

    http://msdn.microsoft.com/en-us/library/hh229082(v=vs.103).aspx

    public static Func<T1, IObservable<Unit>> FromAsyncPattern<T1>(
    	Func<T1, AsyncCallback, Object, IAsyncResult> begin,
    	Action<IAsyncResult> end
    )

    Note that the return type is IObservable<Unit> Unit is a type that represents void, since the C# compiler disallows explicit use of the System.Void type.

    - Dave


    http://davesexton.com/blog

  • Sunday, December 23, 2012 5:48 PM
     
      Has Code

    I seem to be missing something...

    Try :

    WorkflowApplication app = null; // just dummy
    Progam prog =null; // another dummmy
    
    var obs = Observable.FromAsyncPattern(app.BeginLoad, app.EndLoad)(app.Id, new object[] { app, null, prog }); // gives compiler error
    
    // object array is needed as state
    // app.Id is Guid instance id
    // Program is custum type
    
    class Program
        {
            public string Key { get; set; }
            public int InstancesCount { get; set; }
            public Activity Activity { get; set; }
        }

  • Sunday, December 23, 2012 10:09 PM
     
     

    Hi,

    It looks like you changed the number of arguments from your original post.

    Please post the exact signatures of your BeginLoad and EndLoad methods.

    - Dave


    http://davesexton.com/blog

  • Monday, December 24, 2012 12:48 AM
     
      Has Code

    It is the BeginLoad operation from the WorkflowApplication class from Windows Workflow Foundation

    public IAsyncResult BeginLoad( Guid instanceId, AsyncCallback callback, Object state )

    From the System.Activities.WorkflowApplication class :

    http://msdn.microsoft.com/en-us/library/ee473629(v=vs.100).aspx

    I'm trying to convert the WorkflowApplicationManager.Cs from
    WF_WCF_Sameplers\WF\Basic\Execution\ControllingWorkflowApplications\CS\ControllingWorkflowApplications
    (http://msdn.microsoft.com/en-us/library/dd764467(v=vs.100).aspx)

    using RX.

    • Edited by rekna Monday, December 24, 2012 12:56 AM updated signature and context
    •  
  • Monday, December 24, 2012 8:00 AM
     
     Answered Has Code

    Hi,

    I see, so the object array in your second example wasn't intended to be another implementation-specific argument for the BeginLoad method, it was intended to be the standard state parameter?

    Take a look at every overload of FromAsyncPattern.  I find it easiest to use IntelliSense to show the list of choices and then use the up or down arrows to scroll through them.  There are 30 overloads in total.  Do any of them have a state parameter?

    Note that I was wrong about the compiler inferring the correct overload.  For some reason it's unable to, so you must explicitly specify the type parameter for Guid.  Though you don't need to specify a type for the return value because it's implicitly Unit.  In other words, you want to use the overload of FromAsyncPattern that I noted in my original reply, which has a single generic type parameter.

    For example:

    var loadAsync = Observable.FromAsyncPattern<Guid>(obj.BeginLoad, obj.EndLoad);

    - Dave


    http://davesexton.com/blog

    • Marked As Answer by rekna Monday, December 24, 2012 9:43 AM
    • Edited by Dave Sexton Monday, December 24, 2012 11:50 AM FromAsyncPattern, not FromAsync
    •  
  • Monday, December 24, 2012 9:46 AM
     
     
    I know now where my mistake was, so for completeness of the answer: when using Reactive Extensions, there is no need anymore to pass state using the State parameter. I can pass state in a different way, when e.g. subscribing to the observable. 
  • Monday, December 24, 2012 12:07 PM
     
      Has Code

    Hi,

    The state parameter of the APM was typically used to correlate a call to End* with a call to Begin*, which enabled the object exposing this method pair to be stateless and made it easier to support multiple calls to Begin* simultaneously.  It could also be used to pass additional state to the callback, but it's generally better to improve the return type of the End* method rather than overuse an un-typed state object to correlate method calls and also provide out-of-band state.  As an observable, these methods are abstracted away, so there's no longer a need to externally correlate the Begin* and End* calls.

    However, if you were using the state parameter as out-of-band output from the void-returning EndLoad method, then now consider using the Select operator instead:

    var loadAsync = Observable.FromAsyncPattern<Guid>(obj.BeginLoad, obj.EndLoad);
    
    IObservable<Tuple<App, Prog>> whenLoaded = loadAsync(id).Select(_ => Tuple.Create(app, prog));

    - Dave


    http://davesexton.com/blog