3

I am trying to upload a file to Azure blob storage in Asp .Net Core. Everything seems to be working but no file is uploaded. Here is my code snippet:

        var blobReference = GetBlobReference();
        rawData.Position = 0;

        //  var result = blobReference.UploadFromStreamAsync(rawData);
        var result = blobReference.UploadFromFileAsync("C:\\users\\tjaartb\\Downloads\\DebitOrderMandate.pdf");
        result.GetAwaiter().GetResult();
        var blobPath = blobReference.Uri.ToString();

What's happening?

The debugger steps over the result.GetAwaiter().GetResult() with no exceptions occurring. Checking the result Task variable after the GetResult() call shows that the task state is RanToCompletion and the exception property is blank. My blob container is created successfully in earlier code indicating that the connection to blob storage is successful. GetResult() finishes instantly, so it seems like nothing is happening.

Things I've checked

  • rawData is a MemoryStream that is populated with file data. Using the commented line to try and upload via a stream is not successful either.
  • The connection to Azure is working.
  • The file path exists.
  • There are no exceptions thrown.
  • The only thing in my debug window output is Started Thread <ThreadNumber>
  • Putting an invalid path in the call to blobReference.UploadFromFileAsync() throws a FileNotFoundException as expected.
  • I've tried downgrading my project to netcoreapp2.0 from netcoreapp2.1 with no success.
6
  • 1
    Why don't you just await the method call? I can't tell why it is not working with an awaiter in that case but I used netcoreapp2.1 and for me it worked with awaiting the method call. Commented Sep 3, 2018 at 7:02
  • It might be an async await deadlock. Could you try changing your code to use async all the way? ASP.NET Core supports async almost everywhere. Then you code becomes await blobReference.UploadFromFileAsync("C:\\users\\tjaartb\\Downloads\\DebitOrderMandate.pdf"); Commented Sep 3, 2018 at 7:06
  • The interface I am implementing in that method is part of a larger ecosystem that doesn't have async signatures. It would require a lot of effort to refactor it. But I'll give it a try and see. Commented Sep 3, 2018 at 7:07
  • @alsami I made the change to await the call and it made no difference. Commented Sep 3, 2018 at 7:21
  • @Tjaart you did it like that and nothing happend? await blobReference.UploadFromFileAsync("C:\\users\\tjaartb\\Downloads\\DebitOrderMandate.pdf"); Then it should have worked because the upload function is returning a task only. Check in azure if the file exists. Commented Sep 3, 2018 at 7:52

5 Answers 5

2

the following code with WindowsAzure.Storage - Version 9.3.1 package works on Asp Net Core 2.1.

public class AzureBlobModel
{
    public string FileName { get; set; }
    public long? FileSize { get; set; }
    public Stream Stream { get; set; }
    public string ContentType { get; set; }
}

public interface IImageStore
{
    Task<string> SaveDocument(Stream documentStream);
    Task<bool> DeleteDocument(string imageId);
    Task<AzureBlobModel> DownloadDocument(string documentId, string fileName);
    string UriFor(string documentId);
}

public class ImageStore : IImageStore
{
    CloudBlobClient blobClient;
    string baseUri = "https://xxxxx.blob.core.windows.net/";

    public ImageStore()
    {
        var credentials = new StorageCredentials("xxxxx accountName xxxxx", "xxxxx keyValue xxxxx");
        blobClient = new CloudBlobClient(new Uri(baseUri), credentials);
    }

    public async Task<string> SaveDocument(Stream documentStream)
    {
        var documentId = Guid.NewGuid().ToString();
        var container = blobClient.GetContainerReference("xxxxx container xxxxx");
        var blob = container.GetBlockBlobReference(documentId);
        await blob.UploadFromStreamAsync(documentStream);
        return documentId;
    }

    public async Task<bool> DeleteDocument(string documentId)
    {
        var container = blobClient.GetContainerReference("xxxxx container xxxxx");
        var blob = container.GetBlockBlobReference(documentId);
        bool blobExisted = await blob.DeleteIfExistsAsync();
        return blobExisted;
    }

    public async Task<AzureBlobModel> DownloadDocument(string documentId, string fileName)
    {
        var container = blobClient.GetContainerReference("xxxxx container xxxxx");
        var blob = container.GetBlockBlobReference(documentId);

        var doc = new AzureBlobModel()
        {
            FileName = fileName,
            Stream = new MemoryStream(),
        };

        doc.Stream = await blob.OpenReadAsync();
        doc.ContentType = blob.Properties.ContentType;
        doc.FileSize = blob.Properties.Length;

        return doc;
    }

    public string UriFor(string documentId)
    {
        var sasPolicy = new SharedAccessBlobPolicy
        {
            Permissions = SharedAccessBlobPermissions.Read,
            SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-15),
            SharedAccessExpiryTime = DateTime.UtcNow.AddDays(1)
        };

        var container = blobClient.GetContainerReference("xxxxx container xxxxx");
        var blob = container.GetBlockBlobReference(documentId);
        var sas = blob.GetSharedAccessSignature(sasPolicy);
        return $"{baseUri}xxxxx container xxxxx/{documentId}{sas}";
    }
}

public class DocForCreationDto
{
    public IFormFile File { get; set; }

    // other properties ...
}

// On the controller

[HttpPost]
public async Task<IActionResult> Upload([FromForm]DocForCreationDto docForCreationDto)
{
    if (docForCreationDto.File == null || !ModelState.IsValid)
    {
        return new UnprocessableEntityObjectResult(ModelState);
    }

    string documentId = string.Empty;
    using (var stream = docForCreationDto.File.OpenReadStream())
    {
        documentId = await _imageStore.SaveDocument(stream);
    }

    if (documentId != string.Empty)
    {
        // upload ok ...
        //some business logic here ...
        return Ok();
    }

    return BadRequest("xxx error xxx");
}

[HttpGet("{documentId}", Name = "GetDocument")]
public async Task<IActionResult> GetDocument(int documentId)
{
    var doc = await _imageStore.DownloadDocument(documentId, "output filename");

    return File(doc.Stream, doc.ContentType, doc.FileName);
}

// On Startup - ConfigureServices

services.AddSingleton<IImageStore, ImageStore>();
Sign up to request clarification or add additional context in comments.

Comments

1
blob.UploadFromStreamAsync(fileStream).Wait();

This method uploads the content of a stream (fileStream) to a blob asynchronously, and .Wait() is used to block the thread until the upload completes

Comments

0

The interface I am implementing in that method is part of a larger ecosystem that doesn't have async signatures. It would require a lot of effort to refactor it.

You could use Wait() to replace await to implement the async signatures.Refer to the following code:

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connection);
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
var cloudBlobContainer = cloudBlobClient.GetContainerReference("containername");
CloudBlockBlob blob = cloudBlobContainer.GetBlockBlobReference("DebitOrderMandate.pdf");
using (var fileStream = System.IO.File.OpenRead("C:\\users\\tjaartb\\Downloads\\DebitOrderMandate.pdf"))
{
    blob.UploadFromStreamAsync(fileStream).Wait();
}

Comments

0

Adding a / prefix to a Blob name results in a silent failure. The file does not upload at all. removing the / prefix fixed the problem.

Comments

0

With .NET Core 2.1 and WindowsAzure.Storage 9.3.2 all the methods are now async. If you don't await all the async method calls you can get silent failures. The comments below the question helped me figure that out.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.