Converting ICloudBlob.UploadFromStream to Task.Factory.FromAsync(begin,end,params)

I am trying to convert:

blob.UploadFromStream(stream, null, new BlobRequestOptions { RetryPolicy = new LinearRetry(TimeSpan.FromMilliseconds(100), 3) });

to

                Task uploadStreamTask = Task.Factory.FromAsync(
                    blob.BeginUploadFromStream,
                    blob.EndUploadFromStream,
                    stream,
                    null);

My problem is that above works if it was only the stream paramter that are passed to the beginUploadFromStream. I cant figure out how I make it accept the other parameters as in my first example.

Answers


Your code tries to call an overload of the BeginUploadFromStream-Method that does not take any parameters - but there is no such overload. In order to create a Task-Async-Pattern from asnychronous methods that require parameters use the generic version of the FromAsync<>-Method. You can specify there what parameters the Begin-Method needs.

For the Begin/EndUploadFromStream Method the code would look like this:

Task.Factory.FromAsync<Stream>(blob.BeginUploadFromStream, blob.EndUploadFromStream, stream, null);

But since you need to pass the BlobRequestOptions, too, things get a little more complicated:

The overload of BeginUploadFromStream-Method that accepts a BlobRequestOptions parameter, requires four parameters in total. But there is no overload of the FromAsync<> method that accepts more than three input parameters for the begin method.

This is how you can use the FromAsync<> method though:

  1. Create an extension method for ICloudBlob.BeginUploadFromStream that requires two parameters (the stream and the BlobRequestOptions) and passes them properly to the original Begin-Method

    public static class Extensions
    {
        public static IAsyncResult BeginUploadFromStream(this ICloudBlob blob, Stream source, BlobRequestOptions options, AsyncCallback callback, object state)
        {
            return blob.BeginUploadFromStream(source, 
                                              null, 
                                              options, 
                                              null, 
                                              callback, 
                                              state);
        }
    }
    
  2. Use the Async overload to create the Task

    Task.Factory
        .FromAsync<Stream, BlobRequestOptions>(blob.BeginUploadFromStream,
                                               blob.EndUploadFromStream, 
                                               stream,
                                               options, 
                                               null);
    

If you need to pass all four parameters to the BeginUploadFromStream-Method, let me know. I got an idea of how to solve that issue, too.

Update: Here is a solution for a four-parameterd Begin method. I expected the idea to result in something more generic and use less reflection but for now it only works with a EndMethod that does not have a return value.

public static Task FromAsync<TArg1, TArg2, TArg3, TArg4>(this TaskFactory factory,
                                                         Func<TArg1, TArg2, TArg3, TArg4, AsyncCallback, object, IAsyncResult> beginMethod,
                                                         Action<IAsyncResult> endMethod,
                                                         TArg1 arg1,
                                                         TArg2 arg2,
                                                         TArg3 arg3,
                                                         TArg4 arg4,
                                                         object state,
                                                         TaskCreationOptions creationOptions)
    {
        // create a promise task that will wait until the async stuff is done
        var constructor = typeof(Task).GetConstructor(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, new Type[] { typeof(object), typeof(TaskCreationOptions), typeof(bool) }, null);
        var promise = constructor.Invoke(new object[] { state, creationOptions, true }) as Task;

        // perform the async pattern method
        try
        {
            IAsyncResult asyncResult = beginMethod(arg1, arg2, arg3, arg4, delegate(IAsyncResult iar)
            {
                if (!iar.CompletedSynchronously)
                {
                    // complete the async pattern
                    endMethod(iar);
                    var mFinish = typeof(Task).GetMethod("Finish", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                    mFinish.Invoke(promise, new object[] { true });
                }
            }, state);
            if (asyncResult.CompletedSynchronously)
            {
                // complete the async pattern synchronously
                endMethod(asyncResult);
                var mFinish = typeof(Task).GetMethod("Finish", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                mFinish.Invoke(promise, new object[] { true });
            }
        }
        catch (Exception ex)
        {
        }

        return promise as Task;
    }

Need Your Help

Select XMLNode with XPath

c# xml

I have seen multiple post with this example but for some reason all options I try return an empty XmlNodeList. What am I missing?

MVC 3 + EF 4.1 + POCOs + ViewModel pattern + Controller with scaffolding == confusion!

asp.net-mvc-3 entity-framework-4 razor viewmodel poco

I'm [finally!] tackling MVC (version 3) after years of ASP.NET forms development. I have a strong background in n-tier application architecture, and I'm trying to approach this new project properly...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.