using Azure; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Hutopy.Application.Common.Interfaces; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Hutopy.Infrastructure.AzureBlob; public class AzureBlobStorageService : IAzureBlobStorageService { private readonly BlobServiceClient _blobServiceClient; private readonly ILogger _logger; private readonly long _maxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes public AzureBlobStorageService(IConfiguration configuration, ILogger logger) { _logger = logger; var connectionString = configuration["Azure-Blob-Connection-String"] ?? ""; _blobServiceClient = new BlobServiceClient(connectionString); } /// /// Upload a file to microsoft azure blob storage. /// /// The blob name (path within the container, include the file name). /// The name of the container where the file is stored. /// The stream. /// The content type. /// public async Task UploadFileAsync(string containerName, string blobName, Stream fileStream, string contentType) { // Read the file stream into a memory stream to determine the length // WATCH FOR MEMORY USAGE USING THE MEMORY STREAM. var memoryStream = new MemoryStream(); await fileStream.CopyToAsync(memoryStream); memoryStream.Position = 0; // Check if the file size exceeds the maximum upload size if (memoryStream.Length > _maxUploadSize) { _logger.LogInformation($"Blob storage: File size exceeds the maximum allowed size of {_maxUploadSize} bytes."); throw new InvalidOperationException($"Blob storage: File size exceeds the maximum allowed size of {_maxUploadSize} bytes."); } // Validate content type if (!ContentTypes.IsAllowed(contentType, memoryStream)) { _logger.LogInformation($"Blob storage: Unsupported file type {contentType}. Only PNG and JPEG are allowed."); throw new InvalidOperationException("Unsupported file type. Only PNG and JPEG are allowed."); } try { // Get a reference to a container var containerClient = _blobServiceClient.GetBlobContainerClient(containerName); // Create the container if it does not exist await containerClient.CreateIfNotExistsAsync(); // Get a reference to a blob var blobClient = containerClient.GetBlobClient(blobName); // Define the BlobHttpHeaders to include the content type var blobHttpHeaders = new BlobHttpHeaders { ContentType = contentType }; // Upload the file var response = await blobClient.UploadAsync(memoryStream, new BlobUploadOptions { HttpHeaders = blobHttpHeaders }); var fileUri = blobClient.Uri.ToString(); _logger.LogInformation( $"Blob storage: Status [ {response.GetRawResponse().Status.ToString()} ] " + $"Uploaded [ {blobName} ] to the container [ {containerName} ] " + $"with contentType [ {contentType} ] " + $"with a length of [ {memoryStream.Length} bytes ]" + $"with the uri [ {fileUri} ]" ); // Return the URI of the uploaded blob return fileUri; } catch (RequestFailedException ex) { _logger.LogError($"Blob storage: Azure Storage request failed: {ex.Message}"); throw new Exception("Error uploading file to Azure Blob Storage", ex); } catch (Exception ex) { _logger.LogError($"Blob storage: An error occurred: {ex.Message}"); throw; } } /// /// Download a file to microsoft azure blob storage. /// /// The blob name (path within the container). /// The name of the container where the file is stored. (users) /// public async Task DownloadFileAsync(string containerName, string blobName) { try { // Get a reference to a container var containerClient = _blobServiceClient.GetBlobContainerClient(containerName); // Get a reference to a blob var blobClient = containerClient.GetBlobClient(blobName); // Download the blob to a stream BlobDownloadInfo download = await blobClient.DownloadAsync(); MemoryStream memoryStream = new(); await download.Content.CopyToAsync(memoryStream); memoryStream.Position = 0; // Ensure the stream is at the beginning return memoryStream; } catch (RequestFailedException ex) { _logger.LogError($"Azure Storage request failed: {ex.Message}"); throw new Exception("Error downloading file from Azure Blob Storage", ex); } catch (Exception ex) { _logger.LogError($"An error occurred: {ex.Message}"); throw new ApplicationException("Error downloading file from Azure Blob Storage.", ex); } } }