2016-03-02 54 views
0

我正在評估DocumentDb並嘗試通過DocumentDb Rest api提交查詢。什麼是爲DocumentDb查詢帖創建授權有效載荷的正確方法?

當我嘗試發佈查詢,我收到以下錯誤消息:

"The input content is invalid because the required properties - 'id; ' - are missing" 
"The request payload is invalid. Ensure to provide a valid request payload." 

這似乎表明,集合中的文件不具有ID屬性,但這裏是我當前的測試我從蔚藍的檢索門戶網站,你可以看到有一個id屬性數據:

[ 
    { 
    "id": "c1058415-8e03-49e2-8c41-97bc902ebfb0", 
    "name": "Add a thing", 
    "description": "Ad a thing to the list" 
    }, 
    { 
    "id": "0f88f4af-7afc-4928-a60f-c3546b28e243", 
    "name": "find another thing", 
    "description": "find another thing" 
    }, 
    { 
    "id": "b669dbc6-6056-4392-a898-4d846e6c0126", 
    "name": "stuff goes there", 
    "description": "stuff goes there" 
    } 
] 

這是我目前正在嘗試使用(注意,實際值已替換爲虛擬數據)的代碼:

private static readonly string MasterKey = "my master key"; 
private static readonly Uri BaseUri = new Uri("https://mydocdb.documents.azure.com"); 

private static bool _useNames = true; 
private static readonly string DatabaseId = _useNames ? "MyDatabase" : "prdnAA=="; 
private static readonly string CollectionId = _useNames ? "MyCollection" : "prdnAKFrZAA="; 

private static readonly string UtcDate = DateTime.UtcNow.ToString("r"); 
private static void Main(string[] args) 
{ 
    var client = new HttpClient(); 
    client.DefaultRequestHeaders.Add("x-ms-date", UtcDate); 
    client.DefaultRequestHeaders.Add("x-ms-documentdb-isquery", "True"); 
    client.DefaultRequestHeaders.Add("x-ms-version", "2015-08-06"); 

    string verb = "POST"; 
    string resourceType = "docs"; 
    string resourceLink = $"dbs/{DatabaseId}/colls/{CollectionId}/docs"; 
    string resourceId = _useNames ? $"dbs/{DatabaseId}/colls/{CollectionId}" : $"{CollectionId}"; 

    string authHeader = GenerateAuthToken(verb, resourceId, resourceType, MasterKey, "master", "1.0"); 
    client.DefaultRequestHeaders.Remove("authorization"); 
    client.DefaultRequestHeaders.Add("authorization", authHeader); 

    var response = client.PostAsync(
     new Uri(BaseUri, resourceLink), 
     new StringContent("{\"query\":\"SELECT * FROM root \"}", 
      Encoding.UTF8, 
      "application/query+json") 
     ).Result; 
    string result = response.Content.ReadAsStringAsync().Result; 
    Console.WriteLine(result); 
} 

private static string GenerateAuthToken(string verb, string resourceId, string resourceType, string key, 
    string keyType, string tokenVersion) 
{ 
    var verbInput = verb ?? ""; 
    var resourceIdInput = resourceId ?? ""; 
    var resourceTypeInput = resourceType ?? ""; 

    var payLoad = string.Format(CultureInfo.InvariantCulture, 
     "{0}\n{1}\n{2}\n{3}\n{4}\n", 
     verbInput.ToLowerInvariant(), 
     resourceTypeInput.ToLowerInvariant(), 
     resourceIdInput, 
     UtcDate.ToLowerInvariant(), 
     "" 
     ); 

    var hmacSha256 = new HMACSHA256 { Key = Convert.FromBase64String(key) }; 
    var hashPayLoad = hmacSha256.ComputeHash(Encoding.UTF8.GetBytes(payLoad)); 
    var signature = Convert.ToBase64String(hashPayLoad); 

    return HttpUtility.UrlEncode(
     string.Format(
      CultureInfo.InvariantCulture, 
      "type={0}&ver={1}&sig={2}", 
      keyType, 
      tokenVersion, 
      signature) 
     ); 
} 

此代碼是來自Access Control on DocumentDB Resources文檔的示例代碼的變體。 頁面上給出的示例代碼相當有缺陷,因爲它使用函數 GenerateMasterKeyAuthorizationSignature,但函數名稱爲 GenerateAuthToken,與此示例類似。它也只顯示針對api的GET請求,並不表示如何爲POST請求創建授權令牌載荷。這就是爲什麼我最關心的主要事情是授權標題。我不相信我正確設置了resourceId或resourceType。如果我嘗試一個空的resourceId,這是我期望用於查詢,然後我得到一個未經授權的響應,指示有效負載的期望resourceId是對集合的引用(如果我使用_rid的小寫collectionId的數據庫和集合,或者如果我使用名稱命名的路徑)。

note注意引用的文檔頁面已被更新,示例代碼已被刪除。我還發現了其他的引用來生成auth頭文件,並發現我正確地創建了它。

我在創建授權有效載荷時使用了正確的ResourceType和ResourceId值嗎?如果我是,爲什麼我得到關於所需的id屬性的錯誤?

如果我沒有使用正確的值,他們應該是什麼?

分辨率的更新

瑞安曾表示,這個問題是與ContentType標頭的字符集屬性。他的鏈接代碼可能是一種更好的方法,但我也發現我可以創建一個變量StringContent並在發佈之前對其進行修改以獲得預期結果。

var stringQuery = new StringContent("{\"query\":\"SELECT * FROM root \"}", 
    Encoding.UTF8, 
    "application/query+json"); 
stringQuery.Headers.ContentType.CharSet = null; 
HttpResponseMessage response = client.PostAsync(new Uri(BaseUri, resourceLink) 
    ,stringQuery).Result; 

回答

1

請參閱REST API文檔的查詢資源 - https://msdn.microsoft.com/en-us/library/azure/dn783363.aspx

看起來你缺少ContentType標頭。 對於查詢,這必須設置爲「application/query + json」。

即使您添加了,我懷疑接下來會遇到的問題是.NET HttpClient始終在執行POST時在此標頭的末尾添加字符集。在你使用Encoding.UTF8的代碼中可以看到。

不幸的是,.NET中沒有簡單的方法(我知道)在不指定字符集的情況下執行POST。

我創建了一個自定義擴展到.NET HttpClient的示例。

看看了「從.NET REST」樣品貼在github - https://github.com/Azure/azure-documentdb-dotnet/tree/master/samples/rest-from-.net

,並將該樣品準確告訴你應該用什麼當值。 它在所有主要資源上執行GET並執行POST查詢。

+0

謝謝@ ryan-crawcour-msft。我不得不承認CharSet值是我預期會影響結果的最後一件事。我現在可以看到,刪除它會返回我期待的查詢結果。謝謝! – digitalnoiz

相關問題