2016-02-15 70 views
1

我想對Azure DocumentDb進行SQL查詢。我有一個相當混亂的代碼,但現在這是它的外觀嘗試通過REST API查詢DocumentDb時發生401(未授權)

public string GetResources(string collection) { 
    var client = new System.Net.Http.HttpClient(); 
    client.DefaultRequestHeaders.Add("x-ms-date", utc_date); 
    client.DefaultRequestHeaders.Add("x-ms-version", "2015-08-06"); 
    client.DefaultRequestHeaders.Add("x-ms-documentdb-isquery", "True"); 
    client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/query+json")); 

    //GET a document 
    var verb = "POST"; 
    var resourceType = "docs"; 
    var resourceLink = string.Format("dbs/{0}/colls/{1}/docs", databaseId, collection); 
    var resourceId = (idBased) ? resourceLink : ""; 

    var authHeader = GenerateAuthToken(verb, resourceId, resourceType, masterKey, "master", "1.0"); 
    Console.WriteLine(authHeader); 

    client.DefaultRequestHeaders.Remove("authorization"); 
    client.DefaultRequestHeaders.Add("authorization", authHeader); 


    var q = new DbQuery { 
     Query = "SELECT * FROM root" 
    }; 
    var postData = new List<KeyValuePair<string, string>>(); 
    postData.Add(new KeyValuePair<string, string>("query", q.Query)); 
    return PostAsync(resourceLink, postData, client).Result; 
} 


public async Task<string> PostAsync(string uri, List<KeyValuePair<string, string>> data, HttpClient httpClient) 
{ 
    var content = new FormUrlEncodedContent(data); 
    Console.WriteLine(httpClient.DefaultRequestHeaders.Authorization); 
    var response = await httpClient.PostAsync(new Uri(baseUri, uri), content); 

    response.EnsureSuccessStatusCode(); 

    string postContent = await response.Content.ReadAsStringAsync(); 
    return await Task.Run(() => postContent); 
} 

string GenerateAuthToken(string verb, string resourceId, string resourceType, string key, string keyType, string tokenVersion) 
{ 
    var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) }; 

    string verbInput = verb ?? ""; 
    string resourceIdInput = resourceId ?? ""; 
    string resourceTypeInput = resourceType ?? ""; 

    string payLoad = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}\n{1}\n{2}\n{3}\n{4}\n", 
      verb.ToLowerInvariant(), 
      resourceType.ToLowerInvariant(), 
      resourceId, 
      utc_date.ToLowerInvariant(), 
      "" 
    ); 

    byte[] hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad)); 
    string signature = Convert.ToBase64String(hashPayLoad); 

    return System.Net.WebUtility.UrlEncode(String.Format(System.Globalization.CultureInfo.InvariantCulture, "type={0}&ver={1}&sig={2}", 
     keyType, 
     tokenVersion, 
     signature)); 
} 

我有一個請求由它的ID來獲得文件和我使用同樣的方法。它工作正常。我相信這個問題可能與我resourceLink,但老實說,我嘗試了很多版本,都沒有結果..我在這裏錯過了什麼?

+0

您是否嘗試過格式化後的內容作爲JSON,而不是URL編碼?這將解釋爲什麼你的GET基於一個ID的作品,但這個POST不。另一方面,你得到401的事實表明內容不是問題,但auth頭是。另外,如果我建議使用REST API,你願意接受另一個問題的答案嗎? –

+0

謝謝@LarryMaccherone!但我是否正確,至少,「dbs/{0}/colls/{1}/docs」是查詢獲取文檔列表的正確途徑? – alexxjk

+1

我看到你已經使用了我們的REST文檔中的示例代碼。也許看看https://gist.github.com/ryancrawcour/cc5d898b924ebc9635d1,它將向您展示如何在各種資源上進行各種GET操作。你從根目錄中選擇*,就像我在做一個集合中所有文檔的GET一樣。如果你喜歡,我可以擴展這個例子並添加POST來做實際的查詢。 –

回答

2

resourceLink的值取決於您使用的是基於ID的路由還是基於路由的路由。

它看起來像你使用的是基於ID路由 所以,對於一個查詢時,resourceLink應

string.Format("dbs/{0}/colls/{1}/docs", databaseId, collectionId); 

和RESOURCEID應該是一樣的,

string.Format("dbs/{0}/colls/{1}", databaseId, collectionId) 

POST有一點不同因爲它需要設置特定的標題。 使用REST API應該記錄什麼是需要查詢DocumentDB資源的REST文檔 - https://msdn.microsoft.com/en-us/library/azure/dn783363.aspx

對於什麼樣的resourceLink & RESOURCEID和工作eample看看從.NET樣本,我們剛剛發佈的REST進一步的例子。 https://github.com/Azure/azure-documentdb-dotnet/blob/d3f8e9c731bc92816d023719e7e780b7a9546ca2/samples/rest-from-.net/Program.cs#L151-L164

1

對於POST我用這樣的:

var resourceLink = string.Format("dbs/{0}/colls/{1}", DataBaseName, DocumentCollectionName); 
using (var client = GetClient(
      "POST", 
      resourceLink, 
      "docs", 
      PrimaryKey)) 
{ 
     try 
     { 
      var content = 
        new StringContent("{\"query\":\"SELECT * FROM root\"}", Encoding.UTF8, "application/query+json"); 
       content.Headers.ContentType.CharSet = ""; 
      var r = client.PostAsync(
       new Uri(
        new Uri(EndpointUri), resourceLink + "/docs"), content).Result; 
      } 
      catch (Exception ex) 
      { 
      } 
     }} 

和它的作品對我來說