DBoi
DBoi

Reputation: 687

Upload image to blog storage from mvc registration form

I'm trying to build the functionality where the user can upload a profile image to blob storage on registration and then i can be called and included in the manage index view.

I have been able to create the container but no blob is showing inside the container and the url is not being saved to the database either (just NULL) so I'm feeling like its the controller code that's the issue.

CONTROLLER

[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(RegisterViewModel model, 
    HttpPostedFileBase photo, PhotoService photoService)
    {
        if (ModelState.IsValid)
        {

           var user = new ApplicationUser { UserName = model.Email, Email = model.Email, PhotoUrl = model.PhotoUrl };

            ApplicationUser.PhotoUrl = await photoService.UploadPhotoAsync(photo);

            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

                // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
                // Send an email with this link
                // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
                // await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

                //var db = new ApplicationDbContext();
                //model.PhotoUrl = await photoService.UploadPhotoAsync(photo);
                //db.Users.Add(user);
                //db.SaveChanges();

                return RedirectToAction("Index", "Home");
            }
            AddErrors(result);

        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

MODEL

public class RegisterViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

    public string PhotoUrl { get; set; }
}

SERVICE

public class PhotoService : IPhotoService
    {

        async public Task<string> UploadPhotoAsync(HttpPostedFileBase photoToUpload)
        {
            if (photoToUpload == null || photoToUpload.ContentLength == 0)
            {
                return null;
            }

            string fullPath = null;
            Stopwatch timespan = Stopwatch.StartNew();

            try
            {
                CloudStorageAccount storageAccount = StorageUtils.StorageAccount;

                // Create the blob client and reference the container
                CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer container = blobClient.GetContainerReference("images");

                // Create a unique name for the images we are about to upload
                string imageName = String.Format("task-photo-{0}{1}",
                    Guid.NewGuid().ToString(),
                    Path.GetExtension(photoToUpload.FileName));

                // Upload image to Blob Storage
                CloudBlockBlob blockBlob = container.GetBlockBlobReference(imageName);
                blockBlob.Properties.ContentType = photoToUpload.ContentType;
                await blockBlob.UploadFromStreamAsync(photoToUpload.InputStream);

                fullPath = blockBlob.Uri.ToString();

                timespan.Stop();
                // log.TraceApi("Blob Service", "PhotoService.UploadPhoto", timespan.Elapsed, "imagepath={0}", fullPath);
            }
            catch (Exception ex)
            {
                // log.Error(ex, "Error upload photo blob to storage");
                throw;
            }

            return fullPath;
        }

I'm working on this with this tutorial as a guide - https://learn.microsoft.com/en-us/aspnet/aspnet/overview/developing-apps-with-windows-azure/building-real-world-cloud-apps-with-windows-azure/unstructured-blob-storage

Would really appreciate it if someone could let me know how to get this working.

Thanks

Upvotes: 0

Views: 594

Answers (1)

Bruce Chen
Bruce Chen

Reputation: 18465

"an object reference is required for the nonstatic field method or property".

You need to init your user as follows:

var user = new ApplicationUser {
    UserName = model.Email,
    Email = model.Email,
    PhotoUrl = await photoService.UploadPhotoAsync(photo)
};

var result = await UserManager.CreateAsync(user, model.Password);

Moreover, I found the tutorial defined a interface IPhotoService and implement it by the PhotoService class, but I found you define the PhotoService in your Register action. In order to leverage dependency injection, I would recommend you follow this tutorial.

Also, I would recommend you move the HttpPostedFileBase photo parameter from the Register method into your RegisterViewModel as follows:

public class RegisterViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

    public HttpPostedFileBase Photo { get; set; }
}

Then, you could init your ApplicationUser instance as follows:

var user = new ApplicationUser {
    UserName = model.Email,
    Email = model.Email,
    PhotoUrl = await photoService.UploadPhotoAsync(model.Photo)
};

And for your register view, you could init the input file as follows:

@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form", enctype = "multipart/form-data" }))
{   
   //other properties
   @Html.TextBoxFor(m => m.Photo, new {type = "file"})
}

TEST:

enter image description here

In general, you need to make sure you have set the multipart/form-data for your register form in the register view. And the parameter photoService in the Register method is not null. Also, you need to make sure your container name images exists, or you need to await container.CreateIfNotExistsAsync(). Additionally, you could leverage debugging via Visual Studio and step into your code to narrow this issue, details about how to debug, you could follow here.

Upvotes: 1

Related Questions