使用REST API和C#将PDF文件上传到Azure Blob存储不使用任何AZURE STORAGE SDK

问题描述

我正在尝试使用REST API将文件上传到Azure存储容器中,而不使用任何SDK。

不使用Azure.Storage.Blobs SDK的原因是,它依赖于.netstandard2.0,并且在项目运行.NET Framework 4.6.1时,SDK引用的某些DLL不兼容。我在配置中尝试了程序集绑定重定向,但没有很好地进行锻炼(System.ValueTuple.dll参考问题)。

因此,我试图使用C#和REST API在没有SDK的情况下重新编写我的上载代码

这是我正在尝试的代码

public class AzureRestApi
{
        private string _x_ms_client_request_id = string.Empty;

        private string _x_ms_date = string.Empty;

        public string AzureStorageAccountName { get; set; }

        public string AzureStorageAccessKey { get; set; }

        public string BlobSaveFolder
        {
            get; set;
        }

        public string X_MS_DATE
        {
            get
            {
                return _x_ms_date;
            }
        }

        public string X_MS_VERSION
        {
            get
            {
                return "2019-12-12";
            }
        }

        public string BaseURI
        {
            get
            {
                return string.Format("https://{0}.blob.core.windows.net/",AzureStorageAccountName);

            }
        }        

        public AzureRestApi()
        {
            //Date and GUID should be same that is used to create the key signing string and the one that is being sent in the 
            //header of REST api requests.
            _x_ms_date  = DateTime.UtcNow.ToString("R",CultureInfo.InvariantCulture); 
            _x_ms_client_request_id = System.Guid.NewGuid().ToString();
        }

        public bool UploadBlobToContainer(string filePath,string containerName)
        {
            bool isuploaded = false;

            try
            {
                FileInfo fileInfo = new FileInfo(filePath);
                long contentLength = fileInfo.Length;
                long range = contentLength - 1;
                string method = "PUT";
                string contentType = "application/pdf";
                string blobName = fileInfo.Name;
                string blobURI = BaseURI + containerName + "/" + blobName;
                string xmsHeader = $"x-ms-blob-type:BlockBlob\nx-ms-date:{X_MS_DATE};\nx-ms-version:{X_MS_VERSION}";
                string resHeader = $"/{AzureStorageAccountName}/{containerName}/{blobName}";

                if (WebRequest.Create(blobURI) is HttpWebRequest request)
                {
                    request.Method = method;
                    request.ContentType = contentType;
                    request.ContentLength = contentLength;
                    request.Headers.Add("x-ms-blob-type","BlockBlob");
                    request.Headers.Add("x-ms-date",X_MS_DATE);
                    request.Headers.Add("x-ms-version",X_MS_VERSION);                    
                    request.Headers.Add("Authorization",GetAuthorizationHeader(method,xmsHeader,resHeader,request));

                    using (Stream requestStream = request.GetRequestStream())
                    {
                        byte[] fileContents = null;
                        using (FileStream fs = fileInfo.OpenRead())
                        {
                            fileContents = new byte[fs.Length];
                            fs.Read(fileContents,fileContents.Length);
                            fs.Close();
                        }
                        requestStream.Write(fileContents,fileContents.Length);
                    }

                    if (request.GetResponse() is HttpWebResponse response)
                    {
                        if (response.StatusCode == HttpStatusCode.OK)
                            isuploaded = true;
                        else
                            isuploaded = false;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.LogException(ex);
            }
            return isuploaded;
        }

        private string GetAuthorizationHeader(string method,string xmsHeader,string resHeader,HttpWebRequest request)
        {
            string strToSign = $"{method}\n\n\n{request.ContentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{xmsHeader}\n{resHeader}";

            string signatureString = GetHashedString(strToSign,AzureStorageAccessKey);

            string authorizationHeader = string.Format(
                 CultureInfo.InvariantCulture,"{0} {1}:{2}","SharedKey",AzureStorageAccountName,signatureString);

            return authorizationHeader;
        }
}

调用Upload函数代码

string storageName = "MyDefaultStorage";
            
string containerName = "MyDefaultContainer";
            
AzureRestApi restApi = new AzureRestApi()
{
    AzureStorageAccountName = storageName,AzureStorageAccessKey = "MY_STORAGE_ACCOUNT_ACCESS_KEY",};

restApi.UploadBlobToContainer("E:\\UploadFiles\\UploadDocument1.pdf",containerName);

执行此行时抛出异常 if (request.GetResponse() is HttpWebResponse response)

异常消息:远程服务器返回错误:(403)禁止

我尝试使用PostMan模拟此请求,并收到此错误消息

Server Failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

The MAC signature found in the HTTP request 'RW1ACnL1aYqtSnJeHhV2694Ek95Olnf+V3Eup4Jt5ng=' is not the same as any computed signature. Server used following string to sign: 'PUT



461804


application/pdf






x-ms-blob-type:BlockBlob
x-ms-date:Wed,12 Aug 2020 19:30:20 GMT
x-ms-version:2019-12-12
/MyDefaultStorage/MyDefaultContainer/UploadDocument1.pdf'

我尝试了这些链接中给出的答案,如果该文件是文本文件,则可以使用,但是尝试使用pdf时失败

Azure rest api put blob REST Api to Azure blob storage using Access key

任何帮助将不胜感激。

谢谢 拉古纳森S

解决方法

您在此代码中添加了一个额外的分号:

string xmsHeader = $"x-ms-blob-type:BlockBlob\nx-ms-date:{X_MS_DATE};\nx-ms-version:{X_MS_VERSION}";

请更改为此:

string xmsHeader = $"x-ms-blob-type:BlockBlob\nx-ms-date:{X_MS_DATE}\nx-ms-version:{X_MS_VERSION}";

希望这可以为您提供帮助。