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:
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..
Your blob storage account is set up with:
Allow Blob public access is set to "Disabled"
And then your code passes PublicAccessType.Blob
:
containerClient.CreateIfNotExists(PublicAccessType.Blob);
And then you get an exception:
throws an exception saying that public access is prohibited
Sounds to me like the fix is to either:
containerClient.CreateIfNotExists();
, or As documented :
To grant anonymous users read access to a container and its blobs, first allow public access for the storage account, then set the container's public access level. If public access is denied for the storage account, you will not be able to configure public access for a container.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.