blazorazure-blob-storageblazor-server-sideblazor-webassemblysyncfusion

File uploaded to Azure Storage Blob showing size is 0 bytes


I am using the Syncfusion Blazor Uploader component detailed [here] (https://blazor.syncfusion.com/documentation/file-upload/getting-started#without-server-side-api-endpoint) to upload a file to Azure Blob Storage. The component resides in the client-side project and calls a service to route the call to the controller which is in the server-side project. Here is the code for when the user adds a new file (client-side)

private async Task OnChange(UploadChangeEventArgs args)
{
    foreach (var file in args.Files)
    {
        try
        {
            var serializedFile = JsonSerializer.Serialize<Syncfusion.Blazor.Inputs.FileInfo>(file.FileInfo);
            
            await RemoteService.UploadStudyGuide(serializedFile);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

The requirements I currently have are to send it through a service which in turn calls a controller. Here is the method inside the service

public async Task UploadStudyGuide(string serializedFile)
{    
    var response =
    await _httpClient.PostAsJsonAsync("StudyGuide/Upload", serializedFile);
}

and here is the controller:

[HttpPost("Upload")]
public async Task Upload([FromBody] string serializedFile)
{
    string devConnectionString = "myConnectionString";
    string blobContainerName = "myContainerName";
    var file = JsonSerializer.Deserialize<Syncfusion.Blazor.Inputs.FileInfo>(serializedFile);

    try
    {
        // Azure connection string and container name passed as argument to get the Blob reference of container.
        // Provide your container name as second argument to this method. Example, upload-container.
        var container = new BlobContainerClient(devConnectionString, blobContainerName);

        // Method to create our container if it doesn’t exist.
        var createResponse = await container.CreateIfNotExistsAsync();

        // If successfully created our container then set a public access type to Blob.
        if (createResponse != null && createResponse.GetRawResponse().Status == 201)
            await container.SetAccessPolicyAsync(Azure.Storage.Blobs.Models.PublicAccessType.Blob);

        // Method to create a new Blob client.
        var blob = container.GetBlobClient($"/ASPTDEV/StudyGuides/{file.Name}");


        // If the blob with the same name exists, then we delete the blob and its snapshots.
        await blob.DeleteIfExistsAsync(Azure.Storage.Blobs.Models.DeleteSnapshotsOption.IncludeSnapshots);

        // Create a file stream and use the UploadSync method to upload the blob.
        using (var fileStream = new FileStream(blob.BlobContainerName, FileMode.Create))
        {
            await blob.UploadAsync(fileStream, new BlobHttpHeaders { ContentType = $"{file.MimeContentType}" });
        fileStream.Close();
        }
    }
    catch (Exception e)
    {
        Response.Clear();
        Response.StatusCode = 204;
        Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "File failed to upload";
        Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = e.Message;
    }
}

The file successfully uploads to the blob with no errors. But when it does the size is 0 bytes. I have tried with and without the content type headers as well as multiple different files all with the same result.

In case it helps, here is the Syncfusion class I am serializing to:


public class FileInfo
{
    [JsonPropertyName("fileSource")]
    public string FileSource { get; set; }

    [JsonPropertyName("id")]
    public string Id { get; set; }

    [JsonPropertyName("input")]
    public DOM Input { get; set; }

    [JsonPropertyName("list")]
    public DOM List { get; set; }

    [JsonPropertyName("name")]
    public string Name { get; set; }

    [DefaultValue(null)]
    [JsonPropertyName("rawFile")]
    public object RawFile { get; set; }

    [JsonPropertyName("size")]
    public double Size { get; set; }

    [JsonPropertyName("status")]
    public string Status { get; set; }

    [JsonPropertyName("statusCode")]
    public string StatusCode { get; set; }

    [JsonPropertyName("type")]
    public string Type { get; set; }

    [JsonPropertyName("mimeContentType")]
    public string MimeContentType { get; set; }

    [JsonPropertyName("lastModifiedDate")]
    public DateTime LastModifiedDate { get; set; }
 
    [JsonPropertyName("validationMessages")]
    public ValidationMessages ValidationMessages { get; set; }
}

Solution

  • The cause of the error

    This is the code that's causing you the problem:

    using (var fileStream = new FileStream(blob.BlobContainerName, FileMode.Create))
    {
        await blob.UploadAsync(fileStream, // this is the problem.
    

    What you're doing is creating a new (i.e. totally empty) FileStream. You then ask the blob client to upload that empty fileStream object. So, you get a blob uploaded that's empty. Zero length.

    Solution 1

    You could write your data directly using the BlobClient with no need for the FileStream at all:

    await blob.UploadAsync(BinaryData.FromString(serializedFile));
    

    Solution 2

    It's not clear from your example exactly how you want to store the serializedFile data in the Blob, so the first solution might not be what you want.

    For example, if you do need to serialise your FileInfo object, then you can use a stream. But rather than creating an empty FileStream and writing that, you can instead ask the BlobClient to open a stream and then write to it from the JsonSerializer:

    using (var stream = await blob.OpenWriteAsync(true))
    {
        await JsonSerializer.SerializeAsync(stream, file);
    }