1

I'm trying to add documentdb support to an existing app written in dotnetcore, so I can't use the SDK, but thought I'd just use the REST API. Easy enough and the samples were easy to duplicate. I can do all the list/queries that are in the REST API sample just fine.

The problem comes when trying to create documents. I am continually faced with a 401 and can't seem to get around it. I'm using the primary key - not the read only key. And I've read and re-read the API doc here: https://msdn.microsoft.com/en-us/library/azure/mt489088.aspx but can't quite make it work.

It's probably with my auth key, but I'm using the method in the samples GenerateMasterKeyAuthorizationSignature(string verb, string resourceId, string resourceType, string key, string keyType, string tokenVersion) and that works great for the queries. I'm using ID based resourceId and thought I could reuse the code from before:

resourceLink = string.Format("dbs/{0}/colls/{1}/docs", databaseId, collectionId);
resourceId = (idBased) ? string.Format("dbs/{0}/colls/{1}/docs", databaseId, collectionId) : collectionId.ToLowerInvariant();`

The timestamp seems right because the queries work, although I've seen that problem stated elsewhere. And I'm using Ryan's PostWithNoCharSetAsync

I've tried with and without client.DefaultRequestHeaders.Add("x-ms-documentdb-is-upsert", "true");

Could there be something with partitions? Should I be specifying that?

The API docs have headers like cookies and no-cache. Those aren't making a difference are they?

Does it matter if the JSON document comes across with string literal markings - like this: " {\r\n \"id\": 4441,\r\n \"Name\": \"Artesia Spa - Grand Hotel\",\r\n }

Below is the POST from fiddler.

REQUEST

POST https://etest.documents.azure.com/dbs/etest/colls/unittest/docs HTTP/1.1
x-ms-date: Tue, 08 Nov 2016 20:34:40 GMT
x-ms-version: 2015-12-16
authorization: type%3dmaster%26ver%3d1.0%26sig%3dU8BmnPhUMWyoVqNdbI0hy1Kc%2b1Yge79dCBMz8f2v9pE%3d
x-ms-documentdb-is-upsert: true
Content-Type: application/query+json
Host: etest.documents.azure.com
Content-Length: 48
Expect: 100-continue

{"id": 4441,"Name": "Artesia Spa - Grand Hotel"}

RESPONSE

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Server: Microsoft-HTTPAPI/2.0
x-ms-activity-id: d83ae44f-3dc8-47a6-b310-cdf8ca87c597
Strict-Transport-Security: max-age=31536000
x-ms-gatewayversion: version=1.10.39.1
Date: Tue, 08 Nov 2016 20:36:11 GMT
Content-Length: 358

{"code":"Unauthorized","message":"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'post\ndocs\ndbs/etest/colls/unittest\ntue, 08 nov 2016 20:34:40 gmt\n\n'\r\nActivityId: d83ae44f-3dc8-47a6-b310-cdf8ca87c597"}
2
  • hi, do you mind posting your code for GenerateMasterKeyAuthorizationSignature? It would be easier to troubleshoot with code. Please note that if you use resource id to construct the token, the resourceid must maintain the casing matching to the resource, e,g. MyCollection. Here's a reference to construct Auth Token string using the REST API : msdn.microsoft.com/en-us/library/azure/dn783368.aspx A Commented Nov 9, 2016 at 22:55
  • Also, can you please take a look and compare your implementation to github.com/Azure/azure-documentdb-dotnet/blob/master/samples/…? Commented Nov 21, 2016 at 15:20

2 Answers 2

2

Since I just spent like 2 days trying to figure this out, here is an actual answer for anyone interested. DocumentDB is now CosmosDB currently.

Create a DB

var verb = "POST";
var resourceId = "";
var resourceType = "dbs";
var resourceLink = "dbs"; 
var body = new { id = "<databaseId>" };

Create a Collection

var verb = "POST";
var resourceId = "dbs/<databaseId>";
var resourceType = "colls";
var resourceLink = "dbs/<databaseId>/colls"; 
var body = new { id = "<collectionId>" };

Create a Document

var verb = "POST";
var resourceId = "dbs/<databaseId>/colls/<collectionId>";
var resourceType = "docs";
var resourceLink = "dbs/<databaseId>/colls/<collectionId>/docs"; 
var body = new { id = "<documentId>" };

Create a User

var verb = "POST";
var resourceId = "dbs/<databaseId>";
var resourceType = "users";
var resourceLink = "dbs/<databaseId>/users"; 
var body = new { id = "<userId>" };

**Basically resourceId is the same as resourceLink but without the last option (which was not obvious to me)

Setup request something like this (see the example program from msft for the rest)

var client = new System.Net.Http.HttpClient();
string response = string.Empty;
string authHeader = string.Empty;

authHeader = GenerateMasterKeyAuthorizationSignature(verb, resourceId, resourceType, key, keyType, tokenVersion);

client.DefaultRequestHeaders.Add("x-ms-date", utc_date);
client.DefaultRequestHeaders.Add("x-ms-version", "2017-02-22");
client.DefaultRequestHeaders.Remove("authorization");
client.DefaultRequestHeaders.Add("authorization", authHeader);

Also note that the sample program from MSFT includes a NoCharSetJsonMediaTypeFormatter for querying. This needs to be updated for POSTs since the header needs to be "application/json" instead of "application/query+json"

Sign up to request clarification or add additional context in comments.

Comments

0

There is now an official .Net Core SDK you can obtain and use, just like the previous SDK, from Nuget.

In case you need a full sample you can take a look at a GitHub repo I published which covers the most common scenarios.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.