I have been researching this for quite some time and I am stuck at being able to do basic operations on my storage account from my .NET Core webapi.
You should know the following:
- Allow Blob public access is set to "Disabled" (Strongly recommended by Microsoft)
- Account type is BlobStorage
- Authorize requests to Azure Storage must be done through a shared key (I do not prefer SAS)
I have referenced the package Azure.Storage.Blobs in my project and injected it as a service like the following:
services.AddSingleton(x => new BlobServiceClient(config.GetValue<string>("AzureBlobStorage")));
The AzureBlobStorage
is my connection string to the storage account.
I also created a blob service and I put the following methods in
Task<Uri> UploadBlobAsync(string blobContainerName, Stream content, string contentType, string fileName); Task<CustomBlobInfo> GetBlobAsync(string blobContainerName, string fileName); Task<IEnumerable<string>> ListBlobsAsync(string blobContainerName); Task DeleteBlobAsync(string blobContainerName, string fileName);
The process of uploading a blob starts as the following:
-
I hit the following http request (Method:POST) in my post man
http://localhost:5000/api/blob/container/6735D6F0-8FC1-4C6E-B08C-FFBB5B29C4A1
The uniqueidentifier is the container name in my storage account.
-
In my controller, I have the following logic that calls
IFormFile file = Request.Form.Files[0]; if (file == null) { return BadRequest(); } string fileName = Guid.NewGuid().ToString().ToLower(); string containerName = blobContainerName.ToLower(); var result = await this.blobService.UploadBlobAsync( containerName, file.OpenReadStream(), file.ContentType, fileName); var toReturn = result.AbsoluteUri; return Ok(new { path = toReturn });
-
The call hits my
UploadBlobAsync
method and pass the arguments.. so far so good!
However, I run into a problem where my code throws an exception saying that public access is prohibited
public async Task<Uri> UploadBlobAsync(string blobContainerName, Stream content, string contentType, string fileName) { var containerClient = GetContainerClient(blobContainerName); // <<<<< EXCEPTION var blobClient = containerClient.GetBlobClient(fileName); await blobClient.UploadAsync(content, new BlobHttpHeaders { ContentType = contentType }); return blobClient.Uri; }
My GetContainerClient()
is a private method that I use to check if the container exists or not, if it doesn't, then create a container
private BlobContainerClient GetContainerClient(string blobContainerName) { var containerClient = this.blobServiceClient.GetBlobContainerClient(blobContainerName); containerClient.CreateIfNotExists(PublicAccessType.Blob); return containerClient; }
So far, it is obvious why I am getting this exception.. because the public access level is disabled..
Microsoft documentation says that I need to generate a shared access key that somehow gets attached to my request..
This is why I have another method that generate the appropriate request headers as the following:
private void GenerateSharedAccessKeyRequestHeader(string blobContainerName, Stream content, string fileName, string contentType) { string storageKey = "key"; string storageAccount = "name"; string method = "PUT"; long contentLength = content.Length; string requestUri = $"https://{storageAccount}.blob.core.windows.net/{blobContainerName}/{fileName}"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri); string now = DateTime.UtcNow.ToString("R"); request.Method = method; request.ContentType = contentType; request.ContentLength = contentLength; request.Headers.Add("x-ms-version", "2015-12-11"); request.Headers.Add("x-ms-date", now); request.Headers.Add("x-ms-blob-type", "BlockBlob"); request.Headers.Add("Authorization", AuthorizationHeader(method, now, request, storageAccount, storageKey, blobContainerName, fileName)); } private string AuthorizationHeader(string method, string now, HttpWebRequest request, string storageAccount, string storageKey, string containerName, string blobName) { string headerResource = $"x-ms-blob-type:BlockBlob\nx-ms-date:{now}\nx-ms-version:2015-12-11"; string urlResource = $"/{storageAccount}/{containerName}/{blobName}"; string stringToSign = $"{method}\n\n\n{request.ContentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{headerResource}\n{urlResource}"; HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(storageKey)); string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign))); String AuthorizationHeader = String.Format("{0} {1}:{2}", "SharedKey", storageAccount, signature); return AuthorizationHeader; }
The problem is I am not sure where to inject those request headers to upload my blob or to create container or even to do get/list/delete a blob from my storage account?
public async Task<CustomBlobInfo> GetBlobAsync(string blobContainerName, string fileName) { var containerClient = GetContainerClient(blobContainerName); var blobClient = containerClient.GetBlobClient(fileName); var blobDownloadInfo = await blobClient.DownloadAsync(); return new CustomBlobInfo(blobDownloadInfo.Value.Content, blobDownloadInfo.Value.ContentType); } public async Task<IEnumerable<string>> ListBlobsAsync(string blobContainerName) { var containerClient = GetContainerClient(blobContainerName); var items = new List<string>(); await foreach (var item in containerClient.GetBlobsAsync()) { items.Add(item.Name); } return items; } public async Task DeleteBlobAsync(string blobContainerName, string fileName) { var containerClient = GetContainerClient(blobContainerName); var blobClient = containerClient.GetBlobClient(fileName); await blobClient.DeleteIfExistsAsync(); }
This should be easy but for some reason, I have been stuck in this for days..
https://stackoverflow.com/questions/67341436/upload-get-blob-create-container-with-azure-storage-account-in-net-core May 01, 2021 at 07:12AM
没有评论:
发表评论