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

C# 上载/获取Blob-使用.NET Core中的Azure存储帐户创建容器,c#,.net-core,azure-storage-blobs,C#,.net Core,Azure Storage Blobs,我已经对此进行了相当长一段时间的研究,我一直致力于从.NET核心webapi对我的存储帐户执行基本操作 你应该知道以下几点: services.AddSingleton(x => new BlobServiceClient(config.GetValue<string>("AzureBlobStorage"))); private void GenerateSharedAccessKeyRequestHeader(string blobContainerN

我已经对此进行了相当长一段时间的研究,我一直致力于从.NET核心webapi对我的存储帐户执行基本操作

你应该知道以下几点:

services.AddSingleton(x => new BlobServiceClient(config.GetValue<string>("AzureBlobStorage")));
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;
 }
  • “允许Blob公共访问”设置为“已禁用”(强烈禁用) (微软推荐)
  • 帐户类型为BlobStorage
  • 对Azure存储的授权请求必须通过共享密钥完成(我不喜欢SAS)
  • 我在项目中引用了包Azure.Storage.Blobs,并将其作为服务注入,如下所示:

    services.AddSingleton(x => new BlobServiceClient(config.GetValue<string>("AzureBlobStorage")));
    
    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;
     }
    
    上传blob的过程如下所示:

    services.AddSingleton(x => new BlobServiceClient(config.GetValue<string>("AzureBlobStorage")));
    
    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;
     }
    
  • 我在postman中点击了下面的http请求(方法:POST)

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

  • 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 });
    
  • 调用点击my
    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;
    }
    
    到目前为止,我得到这个例外的原因是显而易见的。。因为公共访问级别已禁用

    Microsoft文档说明我需要生成一个共享访问密钥,该密钥以某种方式附加到我的请求中

    这就是为什么我有另一个方法生成适当的请求头,如下所示:

    services.AddSingleton(x => new BlobServiceClient(config.GetValue<string>("AzureBlobStorage")));
    
    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;
     }
    
    问题是我不确定在哪里注入这些请求头来上传我的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();
    }
    
    公共异步任务GetBlobAsync(字符串blobContainerName,字符串文件名)
    {
    var containerClient=GetContainerClient(blobContainerName);
    var blobClient=containerClient.GetBlobClient(文件名);
    var blobDownloadInfo=await blobClient.downloadsync();
    返回新的CustomBlobInfo(blobDownloadInfo.Value.Content,blobDownloadInfo.Value.ContentType);
    }
    公共异步任务列表BlobAsync(字符串blobContainerName)
    {
    var containerClient=GetContainerClient(blobContainerName);
    var items=新列表();
    等待foreach(containerClient.GetBlobsAsync()中的变量项)
    {
    items.Add(item.Name);
    }
    退货项目;
    }
    公共异步任务DeleteBlobAsync(字符串blobContainerName,字符串文件名)
    {
    var containerClient=GetContainerClient(blobContainerName);
    var blobClient=containerClient.GetBlobClient(文件名);
    等待blobClient.DeleteIfExistsAsync();
    }
    

    这应该很容易,但由于某些原因,我已经在这方面困了好几天了。

    您的blob存储帐户设置为:

    允许Blob公共访问设置为“禁用”

    然后,您的代码将通过
    publiccesstype.Blob

    containerClient.CreateIfNotExists(PublicAccessType.Blob)

    然后你会得到一个例外:

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

    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;
    }
    
    在我看来,解决方案是:

  • 删除blob的公共访问:
    containerClient.CreateIfNotExists(),或
  • 作为:

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


    嗨,斯蒂芬。。我不敢相信我错过了这个!!!!!!删除公共访问类型是问题所在。多谢各位much@GauravMantri伙计,我正在传递PublicAccessType,在禁用存储公共访问后,我完全忘记删除它。。用我的代码修复你的。。感谢斯蒂芬