上载/获取Blob-在.NET Core中使用Azure存储帐户创建容器



我已经研究了很长一段时间,我一直无法从.NET Core webapi对我的存储帐户进行基本操作。

你应该知道以下几点:

  1. 允许Blob公共访问被设置为"允许";被禁用";(强烈Microsoft推荐(
  2. 帐户类型为Blob存储
  3. 对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的过程如下所示:

  1. 我在我的POST-man 中点击了以下http请求(方法:POST(

    http://localhost:5000/api/blob/container/6735D6F0-8FC1-4C6E-B08C-ffbb529c4a1

uniqueidentifier是我的存储帐户中的容器名称。

  1. 在我的控制器中,我有以下调用的逻辑

    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 });
    
  2. 调用命中我的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(;

然后你会得到一个异常:

抛出一个异常,表示禁止公共访问

在我看来,修复方法是:

  1. 删除blob的公共访问权限:containerClient.CreateIfNotExists();,或
  2. 为存储帐户启用blob公共访问

如文件所示:

若要授予匿名用户对容器及其Blob的读取访问权限,请首先允许存储帐户的公共访问权限,然后设置容器的公共访问级别。如果存储帐户的公共访问被拒绝,您将无法配置容器的公共访问。

最新更新