Yanayaya
Yanayaya

Reputation: 2184

Why do my uploaded images to Azure contain errors preventing them being displayed?

I have uploaded images to my blob storage account in Azure, whenever I try to access those images either via a web browser or via the azure container explorer I get an error of

The image "whatever.jpg" cannot be displayed because it contains errors.

It doesn't give me any more information than that, looking at the file in Azure explorer I can see that it's been named correctly, has the correct image type, has data as in I can see the bytes.

I've looked at the access rights and I've set the container folder to be public read access as to not require a key. To further test for errors, I uploaded the same images via the azure dashboard directly to the storage account and they work, therefore the problem must be in the way I'm uploaded them.

For the sake of context, I am using a blob storage service in my application with dependency injection for use in my controller.

Create

@model Car
<div class="row">
    <div class="col">
        <form asp-action="Create" asp-controller="Car" method="post" enctype="multipart/form-data">
            <div class="row">
                <div class="col">
                    <div class="md-form form-group">
                        <label asp-for="Name"></label>
                        <input type="text" class="form-control" asp-for="Name" />
                    </div>
                    <div class="md-form form-group">
                        <label asp-for="ImageFile" class="active">Image</label>
                        <!-- Image Upload-->
                        <kendo-upload name="ImageFile" show-file-list="true">
                        </kendo-upload>
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col">
                    <hr />
                    <button type="submit" class="btn btn-success">Submit</button>
                    <button type="reset" class="btn btn-amber">Reset</button>
                </div>
            </div>
        </form>
    </div>
</div>

CarController.cs

private readonly ICarService _carService;
private readonly IWebHostEnvironment _env;
private readonly IConfiguration _configuration;

public CarController(
    IWebHostEnvironment env,
    ICarService carService,
    IConfiguration configuration)
{
    _carService = carService;
    _env = env;
    _configuration = configuration;
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Car car)
{
    if (ModelState.IsValid)
    {
        //
        //Create Car First
        _carService.InsertCar(car);

        //
        //Get the id if the car just created            
        int id = car.Id;

        //
        //If file data is there, prepare and upload to
        //blob storage.
        if (car.ImageFile != null)
        {
            string category = "car";
            var fileName = "car-image.jpg";
            byte[] fileData = new byte[car.ImageFile.Length];
            string mimeType = car.ImageFile.ContentType;                   

            BlobStorageService objBlobService = new BlobStorageService(_configuration.GetConnectionString("AzureStorage"));

                car.ImagePath = objBlobService.UploadFileToBlob(
                    category, 
                    id, 
                    fileName, 
                    fileData, 
                    mimeType);
            }                
            return RedirectToAction(nameof(Index));
        }
        return View(car);
    }

BlobStorageService.cs

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;

namespace MyProject.Services
{
    public class BlobStorageService
    {
        string accessKey = string.Empty;        

        public BlobStorageService(string endPoint)
        {
            accessKey = endPoint;
        }

        public string UploadFileToBlob(string category, int id, string strFileName, byte[] fileData, string fileMimeType)
        {
            try
            {
                var _task = Task.Run(() => this.UploadFileToBlobAsync(category, id, strFileName, fileData, fileMimeType));
                _task.Wait();
                string fileUrl = _task.Result;
                return fileUrl;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async void GetBlobData(string id)
        { 
            CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(accessKey);
            CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();

            string strContainerName = "uploads";
            CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(strContainerName);

            string pathPrefix = "car/" + id;
            CloudBlobDirectory blobDirectory = cloudBlobContainer.GetDirectoryReference(pathPrefix);

            // get block blob reference  
            CloudBlockBlob blockBlob = blobDirectory.GetBlockBlobReference("car-image.jpg");

            await blockBlob.FetchAttributesAsync();
        }          

        private async Task<string> UploadFileToBlobAsync(string category, int id, string strFileName, byte[] fileData, string fileMimeType)
        {
            try
            {
                string strContainerName = "uploads";
                string fileName = category + "/" + id + "/" + strFileName;

                CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(accessKey);
                CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();                
                CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(strContainerName);                

                if (await cloudBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false))
                {
                    await cloudBlobContainer.SetPermissionsAsync(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob }).ConfigureAwait(false);
                }

                if (fileName != null && fileData != null)
                {
                    CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(fileName);
                    cloudBlockBlob.Properties.ContentType = fileMimeType;
                    await cloudBlockBlob.UploadFromByteArrayAsync(fileData, 0, fileData.Length).ConfigureAwait(false);
                    return cloudBlockBlob.Uri.AbsoluteUri;
                }
                return "";
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }
    }
}

The only thing I could think of that might cause a problem is that the file type i.e. jpg is defined in the string instead of being taken from the uploaded file. The files that are uploaded are always jpg and furthermore, down the line, the images will be processed for resizing and converting (if needed) by a third party library. As a test, however, having the filetype in the string didn't seem to be an issue but I'll take guidance on that.

Upvotes: 0

Views: 314

Answers (2)

Patrick Mcvay
Patrick Mcvay

Reputation: 2281

If your car.ImageFile is type IFormFile you can simply use the file stream to upload the image like below. The problem is that you are uploading an empty byte array.

using (var fileStream = car.ImageFile.OpenReadStream())
{
    await cloudBlockBlob.UploadFromStreamAsync(fileStream);
}

Edit: (In Your Code) (Note: this is just an idea, untested)

Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Car car)
{
    if (ModelState.IsValid)
    {
        //
        //Create Car First
        _carService.InsertCar(car);

        //
        //Get the id if the car just created            
        int id = car.Id;

        //
        //If file data is there, prepare and upload to
        //blob storage.
        if (car.ImageFile != null)
        {
            string category = "car";
            var fileName = "car-image.jpg";
            byte[] fileData = new byte[car.ImageFile.Length];
            string mimeType = car.ImageFile.ContentType;                   

            BlobStorageService objBlobService = new BlobStorageService(_configuration.GetConnectionString("AzureStorage"));
            using (var fileStream = car.ImageFile.OpenReadStream())
            {
                car.ImagePath = objBlobService.UploadFileToBlob(
                    category, 
                    id, 
                    fileName, 
                    fileStream, 
                    mimeType);
            }
            }                
            return RedirectToAction(nameof(Index));
        }
        return View(car);
    }

BlobStorageService.cs

    public string UploadFileToBlob(string category, int id, string strFileName, Stream fileStream, string fileMimeType)
    {
        try
        {
            var _task = Task.Run(() => this.UploadFileToBlobAsync(category, id, strFileName, fileStream, fileMimeType));
            _task.Wait();
            string fileUrl = _task.Result;
            return fileUrl;
        }
        catch (Exception)
        {
            throw;
        }
    }

    private async Task<string> UploadFileToBlobAsync(string category, int id, string strFileName, Stream fileStream, string fileMimeType)
    {
        try
        {
            string strContainerName = "uploads";
            string fileName = category + "/" + id + "/" + strFileName;

            CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(accessKey);
            CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();                
            CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(strContainerName);                

            if (await cloudBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false))
            {
                await cloudBlobContainer.SetPermissionsAsync(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob }).ConfigureAwait(false);
            }

            if (fileName != null && fileStream != null)
            {
                CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(fileName);
                cloudBlockBlob.Properties.ContentType = fileMimeType;
                await cloudBlockBlob.UploadFromStreamAsync(fileStream).ConfigureAwait(false);
                return cloudBlockBlob.Uri.AbsoluteUri;
            }
            return "";
        }
        catch (Exception ex)
        {
            throw (ex);
        }
    }

Upvotes: 1

Gaurav Mantri
Gaurav Mantri

Reputation: 136216

One issue I see in your code is that you're simply initializing the fileData array but not populating it with actual file bytes.

byte[] fileData = new byte[car.ImageFile.Length];

So actually you're uploading a file with all bytes as zero.

Somehow you will need to fill this array with the data (image) uploaded by the user.

Upvotes: 1

Related Questions