0
votes

I am trying to use the WebJobs SDK extensions (and the Azure Functions tools for VS) to migrate my Azure functions to pre-compiled binaries, but I'm having problems with the DocumentDB bindings.

I'm trying to create an input binding to an existing DocumentDB document that I can read from, then update the data. When I do this in a script-based Azure function, everything works the way I want. Here's the code I'm using:

public static void Run(TimerInfo myTimer, JObject document, TraceWriter log)
{
    log.Info(document.ToString());

    var active = document["active"] as JArray;
    foreach (var item in active)
    {
        log.Info($"Polling {item}...");
    }

    document["processed"] = DateTime.Now;
    log.Info(document.ToString());
}

The document in question looks like this:

{
    "id": "sites",
    "_rid": "(hash)",
    "_self": "(stuff)",
    "_etag": "\"(guid)\"",
    "_attachments": "attachments/",
    "active": [
        "scifi"
    ],
    "_ts": 1497184149
}

If I try to move this exact code into a pre-compiled function, using WebJobs attributes:

    [FunctionName("TimerFeed")]
    public static void Run(
        [TimerTrigger("0 */5 * * * *")]TimerInfo myTimer,
        [DocumentDB("FeedStateDatabase", "FeedItemsCollection", ConnectionStringSetting = "feed_DOCUMENTDB", Id = "sites")] JObject document,
        TraceWriter log)

then I get an error trying to run the function:

2017-06-11T12:26:36.046 Exception while executing function: Functions.TimerFeed. Newtonsoft.Json: Cannot create and populate list type Newtonsoft.Json.Linq.JToken. Path 'active', line 1, position 219.

Note that the error is thrown before any of my function's code runs. It is thrown even if I remove all of the code and just do a simple diagnostic log. So, I'm pretty sure there's something wrong with my binding. The functions.json file that is being generated looks off, specifically it's claiming that this is an output binding:

{
  "type": "documentDB",
  "databaseName": "FeedStateDatabase",
  "collectionName": "FeedItemsCollection",
  "createIfNotExists": false,
  "connection": "feed_DOCUMENTDB",
  "id": "sites",
  "direction": "out",
  "name": "document"
}
2
I'm not familiar with using JObject type as your document - I've only been using dynamic or a POCO that represents the document structure. Any reason you couldn't use one of those options? I logged that github issue referenced in the other answer, agree that it's unlikely to be your problem here.Garth Mason
I can try dynamic, I was just following the Web Jobs SDK example.Michael Edenfield
No worries. Might be worth logging this on the Azure Functions github if you don't get a definitive answer here, in my experience they have been really responsive to queries on there, particularly since the VS tooling was released.Garth Mason
Switching to dynamic appears to solve the problem; it actually looks unrelated to the binding direction (at least, the "broken" binding works fine as a dynamic.Michael Edenfield
Sounds like what I found - the binding direction didn't seem to stop my function from running as expected either.Garth Mason

2 Answers

3
votes

I'm using Visual Studio 2017 v15.3 Preview with the Azure Function Tools extension installed. After publish to Azure function, the code you mentioned could work correctly after change direction from out to in and add new documentdb connection string. The following is my detail steps:

1.Install Visual Studio 2017 v15.3 Preview and Azure function tool extension

2.Create Azure Function project and add timetrigger function add reference Microsoft.Azure.WebJobs.Extensions.DocumentDB

enter image description here

3.Add the storage connection string to AzureWebStorage and AzureWebJobsDashboard in the local.setting.json file

4.From the Azure WebJob Extension SDK we cloud know that documentdb default connection string name is AzureWebJobsDocumentDBConnectionString. Add the corresponding value for it.

enter image description here

5.Add the following code in the timetrigger function

[FunctionName("TimerTriggerCSharp")]
        public static void Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, [DocumentDB("database name", "collection name", ConnectionStringSetting = "AzureWebJobsDocumentDBConnectionString", Id = "document Id")] JObject document, TraceWriter log)
        {
            log.Info($"C# Timer trigger function executed at: {DateTime.Now}");
            log.Info($"My property: {documents["MyProperty"]}");
        }

My test document is:

{
    "MyProperty": "hello1",
    "id": "a3e6a493-7c2c-4a73-8715-e7efad107d96",
    "_rid": "IgcwAN0Etg8BAAAAAAAAAA==",
    "_self": "dbs/IgcwAA==/colls/IgcwAN0Etg8=/docs/IgcwAN0Etg8BAAAAAAAAAA==/",
    "_etag": "\"0600e070-0000-0000-0000-590152cc0000\"",
    "_attachments": "attachments/",
    "_ts": 1493258955
}

6.I debug it in the local, I find that document always get null. I assume it may be the SDK issue.

enter image description here

7.Skip the issue and publish the project to Azure and I also reproduce the issue that Naren mentioned .

Visual Studio 2017 tooling always generates direction out for DocumentDb

8.Then I changed "direction": "in" in the function.json manually.

enter image description here

9.Save the change and switch to integrate tab and create corresponding documentdb connectionstring.

enter image description here

10.Run the function from the azure portal, it works correctly

enter image description here

1
votes

This looks like a known issue. Visual Studio 2017 tooling always generates direction out for DocumentDb. For storage bindings like blob. FileAccess is used to identify whether it is an input binding or output binding.

https://github.com/Azure/azure-functions-vs-build-sdk/issues/41