anit
anit

Reputation: 1606

Uploading to azure asynchronously directly from a stream

I want to upload to my azure local development account directly using a stream. I have created a class for azure blob storage.

public class AzureBlob
{
    delegate void UploadFinished(IAsyncResult result);
    public void uploadFile()
    {
        //Initial configuration
        CloudStorage account = CloudStorageAccount.DevelopmentStorageAccount;
        CloudBlobClient client = account.CreateBlobClient();
        CloudBlobContainer container = client.GetContainerReference("myfiles");
        Stream stream = new MemoryStream();

        //Upload to azure
        CloudBlob blob = container.GetBlobReference("sample.txt");
        UploadFinished uploadFinished = delegate(IAsyncResult result)
        {
            Console.WriteLine("Upload finished {0} {1}", result.IsCompleted, stream.Position);
        };
        blob.BeginUploadFromStream(stream, new AsyncCallback(uploadFinished));

        //Write to stream
        for(int i=0;i<100;i++)
        {
            for(int j=0;j<50;j++)
            {
                stream.WriteByte(65);
            }
        }
        stream.Close();


    }
}

The first problem that i face is i get the file in the storage but it contains no data. Even if i use EndOfUploadStream method in the callback (which according to some stackoverflow answer is a solution). Secondly, i put the break point inside the callback and i found that the callback gets executed once, before i close the stream, and the program keeps updating the stream. At this point the stream position is around 913(mostly random). Please help me in uploading the blob directly through the stream asynchronously.

Upvotes: 2

Views: 4035

Answers (2)

viperguynaz
viperguynaz

Reputation: 12174

great answer from smarx! Also, move stream.Close() into the callback.

delegate void BeginUploadFinished(IAsyncResult result);
public void UploadFile()
{
    //Initial configuration
    var account = CloudStorageAccount.DevelopmentStorageAccount;
    var client = account.CreateCloudBlobClient();
    var container = client.GetContainerReference("myfiles");
    Stream stream = new MemoryStream();
    var state = new Object{};

    //Upload to azure
    var blob = container.GetBlobReference("test.txt");
    BeginUploadFinished beginUploadFinished = delegate(IAsyncResult result)
    {
        blob.EndUploadFromStream(result);
        Trace.WriteLine("EndUploadFromStream", "Information");
        stream.Close();
        stream.Dispose();
    };

    //Write to stream
    Trace.WriteLine("Writing Stream", "Information");
    for (var i = 0; i < 100; i++)
    {
        for (var j = 0; j < 50; j++)
        {
            stream.WriteByte(65);
        }
    }
    stream.Seek(0, SeekOrigin.Begin);

    Trace.WriteLine("BeginUploadFromStream", "Information");
    var _result =  blob.BeginUploadFromStream(stream, new AsyncCallback(beginUploadFinished), state);
    _result.AsyncWaitHandle.WaitOne();
}

Upvotes: 2

user94559
user94559

Reputation: 60153

It looks to me like you have a race condition. You start uploading the stream before you've actually put content into it.

You probably want something like this:

Stream stream = new MemoryStream();

//Write to stream
for(int i=0;i<100;i++)
{
    for(int j=0;j<50;j++)
    {
        stream.WriteByte(65);
    }
}
stream.SetPosition(0); // <-- need to reset stream position to 0 before uploading

//Upload to azure
CloudBlob blob = container.GetBlobReference("sample.txt");
UploadFinished uploadFinished = delegate(IAsyncResult result)
{
    blob.EndUploadFromStream(result); // <-- have to call this in your handler
    Console.WriteLine("Upload finished {0} {1}", result.IsCompleted, stream.Position);
};
blob.BeginUploadFromStream(stream, new AsyncCallback(uploadFinished));

Upvotes: 2

Related Questions