5

これに近いすべての投稿を読んだ後、私はまだ解決策を見つけられません.

私が見つけた最も近い応答は ここにあります

ただし、これらの投稿の 2 つの点は当てはまりません。1. ほとんどの場合に確実に機能するコード例を使用しています。2. .NET クライアント プロファイルを使用する必要があるため、Azure StorageClient 単純化機能にアクセスできません。3. 私が見ないのはおそらくばかげたエラーです :-)

呼び出しは次のとおりです。

// Create Blob
// using REST: http://msdn.microsoft.com/en-us/library/windowsazure/dd135733.aspx
BlobHelper blobHelper = new BlobHelper(_storageAccountName, _storageKey);
Console.WriteLine("Create container...");
if (!blobHelper.CreateContainer("mytestcontainer")) //(blobInfo.ContainerName))
   {
     Console.WriteLine("REST: Create Blob Failed");
   }

そして、これがワイヤーリクエストです(フィドラー):

PUT /devstoreaccount1/mytestcontainer?restype=container HTTP/1.1
x-ms-date: Mon, 25 Jun 2012 16:54:01 GMT
x-ms-version: 2009-09-19
Authorization: SharedKey devstoreaccount1:REpHdtTSQrwGtXuEbLJmRQdpe/j2l5icmGUeFkQ09jw=
Host: 127.0.0.1:10000
Content-Length: 0
Connection: Keep-Alive

ライブの Azure Storage を使用しても、Developer Storage を使用しても、同じことが起こります。

ワイヤー応答は次のとおりです。

HTTP/1.1 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
Content-Length: 698
Content-Type: application/xml
Server: Microsoft-HTTPAPI/2.0
x-ms-request-id: d5430ddc-f146-4102-b8db-a8bfab0ed82f
Date: Mon, 25 Jun 2012 16:54:00 GMT

<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:d5430ddc-f146-4102-b8db-a8bfab0ed82f
Time:2012-06-25T16:54:01.3354093Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'REpHdtTSQrwGtXuEbLJmRQdpe/j2l5icmGUeFkQ09jw=' is not the same as any computed signature. Server used following string to sign: 'PUT


0








x-ms-date:Mon, 25 Jun 2012 16:54:01 GMT
x-ms-version:2009-09-19
/devstoreaccount1/devstoreaccount1/mytestcontainer
restype:container'.</AuthenticationErrorDetail></Error>

言うまでもなく、これは私を夢中にさせるので、どんなヒントでも感謝します.

Azure Storage REST API サンプル、RESTHelper.cs から直接取得したソース コード。これは多くのシナリオで機能しますが、次のシナリオでは機能しません。

    #region REST HTTP Request Helper Methods

    // Construct and issue a REST request and return the response.

    public HttpWebRequest CreateRESTRequest(string method, string resource, string requestBody = null, SortedList<string, string> headers = null, 
        string ifMatch = "", string md5 = "")
    {
        byte[] byteArray = null;
        DateTime now = DateTime.UtcNow;
        string uri = Endpoint + resource;

        HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
        request.Method = method;
        request.ContentLength = 0;
        request.Headers.Add("x-ms-date", now.ToString("R", System.Globalization.CultureInfo.InvariantCulture));
        request.Headers.Add("x-ms-version", "2009-09-19"); //2009-09-19, 2011-08-18

        if (IsTableStorage)
        {
            request.ContentType = "application/atom+xml";

            request.Headers.Add("DataServiceVersion", "1.0;NetFx");
            request.Headers.Add("MaxDataServiceVersion", "1.0;NetFx");
        }

        if (headers != null)
        {
            foreach (KeyValuePair<string, string> header in headers)
            {
                request.Headers.Add(header.Key, header.Value);
            }
        }

        if (!String.IsNullOrEmpty(requestBody))
        {
            request.Headers.Add("Accept-Charset", "UTF-8");

            byteArray = Encoding.UTF8.GetBytes(requestBody);
            request.ContentLength = byteArray.Length;
        }

        request.Headers.Add("Authorization", AuthorizationHeader(method, now, request, ifMatch, md5));

        if (!String.IsNullOrEmpty(requestBody))
        {
            request.GetRequestStream().Write(byteArray, 0, byteArray.Length);
        }

        return request;
    }


    // Generate an authorization header.
    //RHT: http://msdn.microsoft.com/en-us/library/dd179428.aspx

    public string AuthorizationHeader(string method, DateTime now, HttpWebRequest request, string ifMatch = "", string md5 = "")
    {
        string MessageSignature;

        if (IsTableStorage)
        {
            MessageSignature = String.Format("{0}\n\n{1}\n{2}\n{3}",
                method,
                "application/atom+xml",
                now.ToString("R", System.Globalization.CultureInfo.InvariantCulture),
                GetCanonicalizedResource(request.RequestUri, StorageAccount)
                );
        }
        else
        {
            MessageSignature = String.Format("{0}\n\n\n{1}\n{5}\n\n\n\n{2}\n\n\n\n{3}{4}",
                method,
                (method == "GET" || method == "HEAD") ? String.Empty : request.ContentLength.ToString(),
                ifMatch,
                GetCanonicalizedHeaders(request),
                GetCanonicalizedResource(request.RequestUri, StorageAccount),
                md5
                );
        }
        byte[] SignatureBytes = System.Text.Encoding.UTF8.GetBytes(MessageSignature);
        System.Security.Cryptography.HMACSHA256 SHA256 = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String(StorageKey));
        String AuthorizationHeader = "SharedKey " + StorageAccount + ":" + Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));
        return AuthorizationHeader;
    }

    // Get canonicalized headers.

    public string GetCanonicalizedHeaders(HttpWebRequest request)
    {
        ArrayList headerNameList = new ArrayList();
        StringBuilder sb = new StringBuilder();
        foreach (string headerName in request.Headers.Keys)
        {
            if (headerName.ToLowerInvariant().StartsWith("x-ms-", StringComparison.Ordinal))
            {
                headerNameList.Add(headerName.ToLowerInvariant());
            }
        }
        headerNameList.Sort();
        foreach (string headerName in headerNameList)
        {
            StringBuilder builder = new StringBuilder(headerName);
            string separator = ":";
            foreach (string headerValue in GetHeaderValues(request.Headers, headerName))
            {
                string trimmedValue = headerValue.Replace("\r\n", String.Empty);
                builder.Append(separator);
                builder.Append(trimmedValue);
                separator = ",";
            }
            sb.Append(builder.ToString());
            sb.Append("\n");
        }
        return sb.ToString();
    }

    // Get header values.

    public ArrayList GetHeaderValues(NameValueCollection headers, string headerName)
    {
        ArrayList list = new ArrayList();
        string[] values = headers.GetValues(headerName);
        if (values != null)
        {
            foreach (string str in values)
            {
                list.Add(str.TrimStart(null));
            }
        }
        return list;
    }

    // Get canonicalized resource.

    public string GetCanonicalizedResource(Uri address, string accountName)
    {
        StringBuilder str = new StringBuilder();
        StringBuilder builder = new StringBuilder("/");
        builder.Append(accountName);
        builder.Append(address.AbsolutePath);
        str.Append(builder.ToString());
        NameValueCollection values2 = new NameValueCollection();
        if (!IsTableStorage)
        {
            //Uri.EscapeDataString(...)
            //WebUtility.HtmlEncode(...)     
            //https://stackoverflow.com/questions/36315/alternative-to-httputility-for-net-3-5-sp1-client-framework
            //NameValueCollection values = HttpUtility.ParseQueryString(address.Query);
            //foreach (string str2 in values.Keys)
            //{
            //    ArrayList list = new ArrayList(values.GetValues(str2));
            //    list.Sort();
            //    StringBuilder builder2 = new StringBuilder();
            //    foreach (object obj2 in list)
            //    {
            //        if (builder2.Length > 0)
            //        {
            //            builder2.Append(",");
            //        }
            //        builder2.Append(obj2.ToString());
            //    }
            //    values2.Add((str2 == null) ? str2 : str2.ToLowerInvariant(), builder2.ToString());
            //}
        }
        ArrayList list2 = new ArrayList(values2.AllKeys);
        list2.Sort();
        foreach (string str3 in list2)
        {
            StringBuilder builder3 = new StringBuilder(string.Empty);
            builder3.Append(str3);
            builder3.Append(":");
            builder3.Append(values2[str3]);
            str.Append("\n");
            str.Append(builder3.ToString());
        }
        return str.ToString();
    }

    #endregion
4

1 に答える 1

3

ありがとう、スマルクス

確かに、目を見張るものがあり、それは私を解決策に導きました:

.NET クライアント プロファイルには HttpUtility がありません。そのため、ビルダーが必要とする形式を提供していない正規表現に置き換えました。だから、私はそれをこれに置き換えました:

http://google-gdata.googlecode.com/svn/trunk/clients/cs/src/core/HttpUtility.cs

そしてそれは動作します。ヘッダーは次のようになります。

PUT /devstoreaccount1/mytestcontainer?restype=container HTTP/1.1
x-ms-date: Mon, 25 Jun 2012 18:57:04 GMT
x-ms-version: 2009-09-19
Authorization: SharedKey devstoreaccount1:J5D1E7PK/yNBgQITHmYgVuu4cHtcGad+YKGb1Lh/YUU=
Host: 127.0.0.1:10000
Content-Length: 0

そして結果:

HTTP/1.1 201 Created
Transfer-Encoding: chunked
Last-Modified: Mon, 25 Jun 2012 18:57:04 GMT
ETag: 0x8CF211B72040930
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 079bcdc1-a7fa-4207-99cd-b7f1c2d1b981
x-ms-version: 2009-09-19
Date: Mon, 25 Jun 2012 18:57:04 GMT

0

コードをステップ実行しましたが、この違いは見られませんでした。ありがとう、R.

于 2012-06-27T17:01:18.863 に答える