Search code examples
c#asp.net-mvcazureasyncfileupload

Async method fails first run on multiple image upload


I have a website where photographers can upload photos. The site is being hosted on an shared azure web app and The photos and thumbnails of the photos are uploaded to Azure Blob storage and a record is written to the db. Photographers can upload potentially up to 700mb of photos at a time.

My problem

I had a synchronous method for the upload that A) took ages to run and B) failed with the "There is not enough space on disk" error message. I'm guessing this is because the temp folder for a Azure shared web app is restricted to 200mb.

I tried to implement a Asynchronous method to help speed up the upload but it completes the first photo successfully (ie blobs and db records exist) and then It appears to just hang. This is my first attempt at writing an asynchronous method.

I also don't know how to fix the temp folder size issue.

My calling method

    public static async Task<Tuple<bool, string>> UploadAsync(HttpPostedFileBase[] photos, Bookings booking, string photoType, ApplicationUser user)
    {

        // For each file to be uploaded
        foreach (HttpPostedFileBase file in photos)
        {
            try
            {
                await UploadPhotoFromFileAsync(file, user, booking.BookingsId, photoType);

            }
            catch (Exception ex)
            {
                // Not Implemented
            }
        }

        return new Tuple<bool, string>(true, "Photos uploaded successfully");
    }

My Photo Upload method

    public static Task UploadPhotoFromFileAsync(HttpPostedFileBase file, ApplicationUser user, int bookingId, string photoType)
    {
        return Task.Run(() =>
        {
            using (ApplicationDbContext dbt = new ApplicationDbContext())
            {
                Bookings booking = dbt.Bookings.Find(bookingId);

                // Craete a new record in the UserFiles table
                Photos photo = new Photos();
                photo.BookingsId = booking.BookingsId;
                photo.PhotoType = photoType;
                photo.FileName = Path.GetFileName(file.FileName);

                string confirmedDate = string.Empty;
                if (booking.ConfirmedDate.HasValue)
                {
                    DateTime actualConfirmedDate = booking.ConfirmedDate.Value;
                    confirmedDate = actualConfirmedDate.Year.ToString() + actualConfirmedDate.Month.ToString() + actualConfirmedDate.Day.ToString();
                }

                string blobName = string.Empty;
                string blobThumbName = string.Empty;
                if (photoType == "SamplePhoto")
                {
                    // Get the count of the sample photos in the gallery 
                    List<Photos> samplePhotos = dbt.Photos.Where(m => m.BookingsId == booking.BookingsId && m.PhotoType == "SamplePhoto").ToList();

                    blobName = "TS_" + booking.location.Location.Replace(" ", "") + "_" + booking.BookingsId.ToString() + "_" + confirmedDate + "_" + (samplePhotos.Count).ToString() + "_sample" + Path.GetExtension(file.FileName);
                    blobThumbName = "TS_" + booking.location.Location.Replace(" ", "") + "_" + booking.BookingsId.ToString() + "_" + confirmedDate + "_" + (samplePhotos.Count).ToString() + "_sample_thumb" + Path.GetExtension(file.FileName);
                }
                else
                {
                    // Get the count of the sample photos in the gallery 
                    List<Photos> photos = dbt.Photos.Where(m => m.BookingsId == booking.BookingsId && m.PhotoType == "GalleryPhoto").ToList();

                    blobName = "TS_" + booking.location.Location.Replace(" ", "") + "_" + booking.BookingsId.ToString() + "_" + confirmedDate + "_" + (photos.Count).ToString() + Path.GetExtension(file.FileName);
                    blobThumbName = "TS_" + booking.location.Location.Replace(" ", "") + "_" + booking.BookingsId.ToString() + "_" + confirmedDate + "_" + (photos.Count).ToString() + "_thumb" + Path.GetExtension(file.FileName);
                }

                // Create the Thumbnail image.
                CloudBlobContainer thumbnailBlobContainer = _blobStorageService.GetCloudBlobContainer("thumbnails");
                if (CreateThumbnailImageFromHttpPostedFileBase(file, blobThumbName, photo))
                {
                    photo.ThumbnailBlobName = blobThumbName;
                    photo.ThumbnailBlobUrl = thumbnailBlobContainer.Uri + "/" + blobThumbName;
                }

                CloudBlobContainer blobContainer = _blobStorageService.GetCloudBlobContainer("photos");
                photo.BlobName = blobName;
                photo.BlobUrl = blobContainer.Uri + "/" + blobName;

                photo.DateCreated = DateTime.Now;
                photo.CreatedBy = user.Id;

                dbt.Photos.Add(photo);
                dbt.SaveChanges();

                booking.Photos.Add(photo);
                dbt.SaveChanges();

                //Upload to Azure Blob Storage
                CloudBlockBlob blob = blobContainer.GetBlockBlobReference(blobName);
                blob.UploadFromStream(file.InputStream);
            }
        });
    }

Solution

  • The problem was actually being caused by the request length set in the Web.Config. It wasn't high enough to allow for the size of the photos being uploaded. I simply added the following code to the Web.Config.

    <system.web>
         <httpRuntime targetFramework="4.5" maxRequestLength="1048576" executionTimeout="900" />
    </system.web>
    <system.webServer>
        <modules>
            <remove name="FormsAuthentication" />
        </modules>
    </system.webServer>