Reputation: 34038
I have a webapi method so that users can upload their own profile picture, however in my entity which is saved in CosmosDB I save the profile picture URL.
public async Task<IHttpActionResult> UpdateSuperAdministrator(SuperAdministrator superadministrator)
{
var telemetry = new TelemetryClient();
try
{
var superAdministratorStore = CosmosStoreHolder.Instance.CosmosStoreSuperAdministrator;
//First we validate the model
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//Then we validate the content type
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
//Initalize configuration settings
var accountName = ConfigurationManager.AppSettings["storage:account:name"];
var accountKey = ConfigurationManager.AppSettings["storage:account:key"];
var profilepicturecontainername = ConfigurationManager.AppSettings["storage:account:profilepicscontainername"];
//Instance objects needed to store the files
var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer imagesContainer = blobClient.GetContainerReference(profilepicturecontainername);
var provider = new AzureStorageMultipartFormDataStreamProvider(imagesContainer);
foreach (MultipartFileData file in provider.FileData)
{
var fileName = file.Headers.ContentDisposition.FileName.Trim('\"').Trim();
if (fileName.EndsWith(".png"))
{
var img = Image.FromFile(file.LocalFileName);
if (img.Width != 200 && img.Height != 200)
{
string guid = Guid.NewGuid().ToString();
return BadRequest($"Error Lulo. Unsupported extension, only PNG is valid. Or unsuported image dimensions (200px x 200px)");
}
}
}
//Try to upload file
try
{
await Request.Content.ReadAsMultipartAsync(provider);
}
catch (Exception ex)
{
string guid = Guid.NewGuid().ToString();
var dt = new Dictionary<string, string>
{
{ "Error Lulo: ", guid }
};
telemetry.TrackException(ex, dt);
return BadRequest($"Error Lulo. An error has occured. Details: {guid} {ex.Message}: ");
}
// Retrieve the filename of the file you have uploaded
var filename = provider.FileData.FirstOrDefault()?.LocalFileName;
if (string.IsNullOrEmpty(filename))
{
string guid = Guid.NewGuid().ToString();
var dt = new Dictionary<string, string>
{
{ "Error Lulo: ", guid }
};
return BadRequest($"Error Lulo. An error has occured while uploading your file. Please try again.: {guid} ");
}
//Rename file
CloudBlockBlob blobCopy = imagesContainer.GetBlockBlobReference(superadministrator.Id + ".png");
if (!await blobCopy.ExistsAsync())
{
CloudBlockBlob blob = imagesContainer.GetBlockBlobReference(filename);
if (await blob.ExistsAsync())
{
await blobCopy.StartCopyAsync(blob);
await blob.DeleteIfExistsAsync();
}
}
superadministrator.ProfilePictureUrl = blobCopy.Name;
var result = await superAdministratorStore.UpdateAsync(superadministrator);
return Ok(result);
}
catch (Exception ex)
{
string guid = Guid.NewGuid().ToString();
var dt = new Dictionary<string, string>
{
{ "Error Lulo: ", guid }
};
telemetry.TrackException(ex, dt);
return BadRequest("Error Lulo: " + guid);
}
}
Now my question is about the endpoind GET. Because the profile picture needs to be shown in the navigation bar on the app, I need to get it in binary format, if that makes sense? In other words, I cant return the ProfilePicture URL to the client (a React App), because its a client app which does not have access to the blob storage.
Here is my get.
[HttpGet]
public async Task<IHttpActionResult> GetSuperAdministrator(string email)
{
var telemetry = new TelemetryClient();
try
{
var superAdministratorStore = CosmosStoreHolder.Instance.CosmosStoreSuperAdministrator;
var superadministrator = await superAdministratorStore.Query().FirstOrDefaultAsync(x => x.EmailAddress == email);
if (superadministrator == null)
{
return NotFound();
}
return Ok(superadministrator);
}
catch (Exception ex)
{
string guid = Guid.NewGuid().ToString();
var dt = new Dictionary<string, string>
{
{ "Error Lulo: ", guid }
};
telemetry.TrackException(ex, dt);
return BadRequest("Error Lulo: " + guid);
}
}
Upvotes: 1
Views: 7189
Reputation: 5549
Based on my knowledge, you React App will show a html page, which means that there will be a html <img src="url">
in the html. Then the browser will try to get the image from the url.
So, there would be 2 optional solutions:
1.Generate a storage blob url with SAS, and set it as the image's url in <img>
. With SAS, a clinet will be able to access the image from storage directly.
2.The url would be the request path of yout Web API. For example: /image/{image_name}
. And your web api will return a image:
[HttpGet]
public IActionResult GetImage()
{
// Get the image blob
CloudBlockBlob cloudBlockBlob = ********;
using(MemoryStream ms = new MemoryStream())
{
cloudBlockBlob.DownloadToStream(ms);
return File(ms.ToArray(), "image/jpeg");
}
}
Update:
My code:
public IActionResult Index()
{
string connString = "DefaultEndpointsProtocol=https;AccountName=storagetest789;AccountKey=G36mcmEthM****=;EndpointSuffix=core.windows.net";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connString);
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("pub");
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference("p033tw9j.jpg");
using (MemoryStream ms = new MemoryStream())
{
cloudBlockBlob.DownloadToStream(ms);
return File(ms.ToArray(), "image/jpeg");
}
}
Screenshot:
Upvotes: 3