我已经研究了很长一段时间,我一直无法从.NET Core webapi对我的存储帐户进行基本操作。
你应该知道以下几点:
- 允许Blob公共访问被设置为"允许";被禁用";(强烈Microsoft推荐(
- 帐户类型为Blob存储
- 对Azure存储的授权请求必须通过共享密钥完成(我不喜欢SAS(
我在项目中引用了Azure.Storage.Blobs包,并将其作为如下服务注入:
services.AddSingleton(x => new BlobServiceClient(config.GetValue<string>("AzureBlobStorage")));
AzureBlobStorage
是我与存储帐户的连接字符串。
我还创建了一个blob服务,并在中使用了以下方法
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);
上传blob的过程如下所示:
我在我的POST-man 中点击了以下http请求(方法:POST(
http://localhost:5000/api/blob/container/6735D6F0-8FC1-4C6E-B08C-ffbb529c4a1
uniqueidentifier是我的存储帐户中的容器名称。
在我的控制器中,我有以下调用的逻辑
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 });
调用命中我的
UploadBlobAsync
方法并传递参数。。到目前为止还不错!
但是,我遇到了一个问题,我的代码抛出了一个异常,说公共访问被禁止
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;
}
我的GetContainerClient()
是一个私有方法,我用它来检查容器是否存在,如果不存在,然后创建一个容器
private BlobContainerClient GetContainerClient(string blobContainerName)
{
var containerClient = this.blobServiceClient.GetBlobContainerClient(blobContainerName);
containerClient.CreateIfNotExists(PublicAccessType.Blob);
return containerClient;
}
到目前为止,我得到这个例外的原因是显而易见的。。因为公共访问级别已禁用。。
微软文档说,我需要生成一个共享访问密钥,以某种方式附加到我的请求中。。
这就是为什么我有另一种方法来生成适当的请求头,如下所示:
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:BlockBlobnx-ms-date:{now}nx-ms-version:2015-12-11";
string urlResource = $"/{storageAccount}/{containerName}/{blobName}";
string stringToSign = $"{method}nnn{request.ContentLength}nn{request.ContentType}nnnnnnn{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;
}
问题是,我不确定在哪里注入这些请求头来上传我的blob或创建容器,甚至从我的存储帐户中获取/列出/删除blob?
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();
}
这应该很容易,但由于某种原因,我已经被困了好几天了。。
您的blob存储帐户设置为:
允许Blob公共访问被设置为"允许";被禁用";
然后您的代码通过PublicAccessType.Blob
:
containerClient.CreateIfNotExists(PublicAccessType.Blob(;
然后你会得到一个异常:
抛出一个异常,表示禁止公共访问
在我看来,修复方法是:
- 删除blob的公共访问权限:
containerClient.CreateIfNotExists();
,或 - 为存储帐户启用blob公共访问
如文件所示:
若要授予匿名用户对容器及其Blob的读取访问权限,请首先允许存储帐户的公共访问权限,然后设置容器的公共访问级别。如果存储帐户的公共访问被拒绝,您将无法配置容器的公共访问。