I'm currently able to upload and display an image from my blob storage but i'm struggling to find a way to 'update/replace' that image if a user would like to change it. I'm happy with either of two methods:
In the controller i'm using Dependency Injection for the photoService:
MANAGE CONTROLLER
//
// GET: /Manage/Index
public async Task<ActionResult> Index(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
: message == ManageMessageId.Error ? "An error has occurred."
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
: "";
var userId = User.Identity.GetUserId();
var model = new IndexViewModel
{
HasPassword = HasPassword(),
PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
Logins = await UserManager.GetLoginsAsync(userId),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId)
};
// PhotoService
var user = new ApplicationUser
{
PhotoUrl = await _photoService.UploadPhotoAsync(model.Photo)
};
await UserManager.CreateAsync(user);
// PhotoService END
return View(model);
}
SERVICE
public class PhotoService : IPhotoService
{
public async void CreateAndConfigureAsync()
{
try
{
CloudStorageAccount storageAccount = StorageUtils.StorageAccount;
// Create a blob client and retrieve reference to images container
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("images");
// Create the "images" container if it doesn't already exist.
if (await container.CreateIfNotExistsAsync())
{
// Enable public access on the newly created "images" container
await container.SetPermissionsAsync(
new BlobContainerPermissions
{
PublicAccess =
BlobContainerPublicAccessType.Blob
});
// Logging
}
}
catch (Exception ex)
{
// Logging
}
}
public async 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);
// Convert to be HTTP based URI (default storage path is HTTPS)
var uriBuilder = new UriBuilder(blockBlob.Uri);
uriBuilder.Scheme = "http";
fullPath = uriBuilder.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");
}
return fullPath;
}
}
INTERFACE
public interface IPhotoService
{
void CreateAndConfigureAsync();
Task<string> UploadPhotoAsync(HttpPostedFileBase photoToUpload);
}
MODEL
public class IndexViewModel
{
public bool HasPassword { get; set; }
public IList<UserLoginInfo> Logins { get; set; }
public string PhoneNumber { get; set; }
public bool TwoFactor { get; set; }
public bool BrowserRemembered { get; set; }
public HttpPostedFileBase Photo { get; set; }
public string PhotoUrl { get; set; }
}
VIEW
@using Microsoft.AspNet.Identity
@model AzureBlobStorageTest.Models.IndexViewModel
@{
ViewBag.Title = "Manage";
}
<h2>@ViewBag.Title.</h2>
<p class="text-success">@ViewBag.StatusMessage</p>
<div>
<h4>Change your account settings</h4>
<h5>Image:</h5>
<img src="@(Model.PhotoUrl)" alt="Photo"/>
@using (Html.BeginForm("Index", "Manage", FormMethod.Post, new { role = "form", enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary("", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(m => m.Photo, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Photo, new { type = "file" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
</div>
It would be great if someone could help me with this as I've been trying all sorts of ways but having no luck.
Please let me know if you require any further info.
Thanks
As Thomas commented that CloudBlockBlob.UploadFromStreamAsync would upload a stream to a block blob and if the blob already exists, it will be overwritten. But your blob name is unique under the UploadPhotoAsync
method as follows:
string imageName = String.Format("task-photo-{0}{1}",
Guid.NewGuid().ToString(),
Path.GetExtension(photoToUpload.FileName));
I would recommend you define a new method (e.g. DeletePhotoAsync
) under IPhotoService
, and retrieve the existing image then delete it before invoking the UploadPhotoAsync
method for uploading the new image.
Or you could add a optional parameter names photoUrl
for the UploadPhotoAsync
method, and if the photoUrl
is not null or empty, then you could initialize your imageName
as follows:
imageName = new CloudBlockBlob(new Uri($"{photoUrl}")).Name;
UPDATE:
Your PhotoService
would look like this:
public class PhotoService:IPhotoService
{
CloudBlobContainer container;
public PhotoService()
{
CloudStorageAccount storageAccount = StorageUtils.StorageAccount;
// Create a blob client and retrieve reference to images container
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
container= blobClient.GetContainerReference("images");
}
//photoUrl: https://<account-name>.blob.core.windows.net/images/task-photo-09e0e292-8df2-4630-81a5-cb4977eef1f9.png
public async Task<bool> DeletePhotoAsync(string photoUrl)
{
string blobName = new CloudBlockBlob(new Uri(photoUrl)).Name;
var targetBlob = container.GetBlockBlobReference(blobName);
return await targetBlob.DeleteIfExistsAsync();
}
public async void CreateAndConfigureAsync()
{
try
{
// Create the "images" container if it doesn't already exist.
if (await container.CreateIfNotExistsAsync())
{
// Enable public access on the newly created "images" container
await container.SetPermissionsAsync(
new BlobContainerPermissions
{
PublicAccess =
BlobContainerPublicAccessType.Blob
});
// Logging
}
}
catch (Exception ex)
{
// Logging
}
}
//UploadPhotoAsync
}