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"
}
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
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.
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.
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.
9.Save the change and switch to integrate tab and create corresponding
documentdb connectionstring.
10.Run the function from the azure portal, it works correctly
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
Related
I created Azure Function (2.0v) from C# HTTP template . Then I added output binding to CosmosDB based on CosmosDB docs:
public static class AddEvent
{
[FunctionName("AddEvent")]
public static void Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
HttpRequest req,
[CosmosDB("SomeDatabase", "SomeCollection", Id = "id",
ConnectionStringSetting = "myCosmosDB", CreateIfNotExists = true)]
out dynamic document)
{
document = new { Text = "something", id = Guid.NewGuid() };
}
}
Packages, that I use (csproj file):
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.0-beta7" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.11" />
This is my local.settings.json. I based them on values from CosmosDB emulator:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"AzureWebJobsDashboard": "",
"myCosmosDB": "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
}
}
Unfortunately, when I hit HTTP trigger I get:
System.Private.CoreLib: Exception while executing function: AddEvent.
Microsoft.Azure.WebJobs.Host: Exception binding parameter 'document'.
Microsoft.Azure.DocumentDB.Core: The type initializer for 'Microsoft.Azure.Documents.UserAgentContainer' threw an exception.
Object reference not set to an instance of an object.
What does this exception means? I cannot find any relevant information about it and it completely stops my local work. Function works well without CosmosDB attribute.
This was a regression with the latest version (2.0.11776) of the host. This has been addressed and the release is currently in progress.
It should be a breaking change in new cli. Try to downgrade cli to 2.0.1-beta.25, it works on my side. BTW, I recommend you to update Microsoft.NET.Sdk.Functions to 1.0.13 to avoid possible exception.
beta.24 seems outdated and also causes Method not found error on my side. While beta.26 leads to error same as beta.28.
However, if I debug the project directly using VS(which uses beta.26 no-runtime version) or publish it to Azure, works fine. Have opened an issue on github, you can track it if interested.
Update
Solved in 2.0.1-beta.29, runtime 2.0.11857.0.
What version of the DocumentDB package are you referencing?
Recommendation would be to either:
downgrade any DocumentDB nuget to 1.13.2.
Remove the DocumentDB reference completely and instead directly reference Microsoft.Azure.WebJobs.Extensions.DocumentDB, which will reference the correct version for you.
I'm trying to create an Azure function that will output to a table. I'm using the Azure Function App, and so, as I currently understand it, the function.json is generated for me by the SDK. My function definition is as follows:
public static HttpResponseMessage Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req,
TraceWriter log,
[StorageAccount("table_storage")] ICollector<TableItem> outputTable)
I've defined TableItem as a class that inherits from TableEntity. When I deploy this and look at the generated function.json, it doesn't mention the output parameter binding:
{
"generatedBy": "Microsoft.NET.Sdk.Functions.Generator-1.0.7",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"methods": [
"post"
],
"authLevel": "function",
"name": "req"
}
],
"disabled": false,
"scriptFile": "../bin/FunctionApp5.dll",
"entryPoint": "FunctionApp5.DeliveryComplete.Run"
}
If I run this from Visual Studio, I get the following error:
Cannot bind parameter 'outputTable' to type ICollector`1
I have a few questions about this behaviour: the first and main one is, why is function.json not showing the output binding? Secondly, I understand why this can't be edited when you deploy from VS, but is there a way to manage the bindings without guesswork (I came across using ICollector in this post), but I can't find anywhere else that says it should or shouldn't be there.
Finally, how does (or does) running this from the desktop interact with the published function: does it connect to the published version of the function, or does it generate the function.json locally?
That's a common source of confusion, but input and output bindings are not visible in generated function.json, only trigger does. They will still work normally.
If you are trying to write to Table Storage, you should use Table attribute instead of StorageAccount. ICollector is mentioned in Azure Table storage bindings for Azure Functions.
When running locally, the files stay locally and run in local runtime, without deployment to Azure. They might still interact with real Azure services via bindings.
I'm having an issue with an Azure Service Bus output binding that I'm uncertain about how to proceed with. I've had no luck finding a similar question, so I apologize if this is a duplicate.
I'm trying to use the local VS 2017 development process, so the function.json bindings should be generated automatically. The function signature is as follows:
[FunctionName("RequestNewPaladinInvitation")]
public static HttpResponseMessage Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")]HttpRequestMessage req,
[ServiceBus("thequeue")] ICollector<Invitation> invitationOutputQueue,
TraceWriter log)
{
//Do some stuff and write to the queue
invitationOutputQueue.Add(invite);
}
I get the following error when running the function locally.
Microsoft.Azure.WebJobs.Host: Error indexing method
'RequestNewPaladinInvitation.Run'. Microsoft.Azure.WebJobs.Host:
Cannot bind parameter 'invitationOutputQueue' to type ICollector`1.
Make sure the parameter Type is supported by the binding. If you're
using binding extensions (e.g. ServiceBus, Timers, etc.) make sure
you've called the registration method for the extension(s) in your
startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
[9/1/2017 5:42:49 PM] Error indexing method
'RequestNewPaladinInvitation.Run'
Both my host.json and local.settings.json are defined as follows:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "<MyStorageAccountInfo>",
"AzureWebJobsDashboard": "<MyDashboardInfo>",
"AzureWebJobsServiceBus": "<MyServiceBusConnectionString>"
}
}
I was under the impressing that defining the AzureWebJobsServiceBus value would make that the default ServiceBusAccount for any ServiceBus bindings throughout the function app.
I also tried explicitly pointing the ServiceBus binding to the connection string for the account with the following alternative attribute [ServiceBus("createpaladininvitation",Connection = "ServiceBus")]. My understanding of the convention is that the AzureWebJobs portion of the property should not be included. Just in case I misunderstood, I tried [ServiceBus("createpaladininvitation",Connection = "AzureWebJobsServiceBus")] as well. I even tried to decorate both the method and parameter with the following attribute, [ServiceBusAccount("ServiceBus")]. I also tried the same variations as with the Connection parameter for the ServiceBus attribute.
In all cases, I get the same function.json output, which shows no binding generated for the ServiceBus output binding.
Here's the function.json:
{
"generatedBy": "Microsoft.NET.Sdk.Functions-1.0.0.0",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"methods": [
"post"
],
"authLevel": "anonymous",
"name": "req"
}
],
"disabled": false,
"scriptFile": "..\\bin\\AzureFunctionsPoc.dll",
"entryPoint": "AzureFunctionsPoc.RequestNewPaladinInvitation.Run"
}
It feels like I'm missing something obvious.
[Update]
As I tried to continue to figure out what's going on, I ran the function locally and edited the generated function.json file and added the binding that I think should have been generated. The resulting manually edited function.json is:
{
"generatedBy": "Microsoft.NET.Sdk.Functions-1.0.0.0",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"methods": [
"post"
],
"authLevel": "anonymous",
"name": "req"
},
{
"type": "serviceBus",
"name": "invitationOutputQueue",
"queueName": "createpaladininvitation",
"connection": "ServiceBus",
"direction": "out"
}
],
"disabled": false,
"scriptFile": "..\\bin\\AzureFunctionsPoc.dll",
"entryPoint": "AzureFunctionsPoc.RequestNewPaladinInvitation.Run"
}
With those edits, the method works exactly as expected.
This feels even more like either a syntax or convention issue that I'm missing, or a tooling bug.
There is currently an outstanding tooling bug in regards to ServiceBus output triggers. It will work if you 'deploy' your app to Azure Functions, just not locally with the tooling
Please see relevant GitHub issues here: Service Bus output binding issue
and here: Latest v1.0.0 not working with ServiceBus. alpha 6 still works.
This is related to the lazy load. We're not picking up the service bus extension, hence the indexing error. (Azure/azure-webjobs-sdk-script#1637)
The reason for that is that ServiceBus extension is different than the others. We expect extensions to have a public parameterless config object that implements IExtensionConfigProvider.
SB is internal (https://github.com/Azure/azure-webjobs-sdk/blob/663a508e8a851629c26a51e7de3af36629dfd120/src/Microsoft.Azure.WebJobs.ServiceBus/Config/ServiceBusExtensionConfig.cs#L17 ) so our scan for ExportedTypes misses it (see https://github.com/Azure/azure-webjobs-sdk-script/blob/b1445485807bb190ba0716af1a8dc81a864b5228/src/WebJobs.Script/Host/ScriptHost.cs#L735) .
SB's config does not have a parameterless ctor, so the Activator.createInstance call will fail too.
This hotfix (which we made to script runtime) Azure/azure-webjobs-sdk-script#1804 would fix it; but that would need to be pulled to CLI.
I have a simple trigger based Azure function which connects to an Azure event hub and writes out a message each time one is received on the event hub.
I created this as a C# Web Application based on the below post and am trying to debug this function locally:-
https://blogs.msdn.microsoft.com/appserviceteam/2017/03/16/publishing-a-net-class-library-as-a-function-app/
Here is my function code:-
using Microsoft.Azure.WebJobs.Host;
using System;
using System.Threading.Tasks;
namespace FunctionLibrary
{
public class EventHubProcessorFunction
{
public static void Run(string myEventHubMessage, TraceWriter log)
{
log.Info($"C# Event Hub trigger function processed a Vineet message: {myEventHubMessage}");
}
}
}
Here is my function.json
{
"disabled": false,
"scriptFile": ".\\bin\\FunctionAsWebApp.dll",
"entryPoint": "FunctionLibrary.EventHubProcessorFunction.Run",
"bindings": [
{
"type": "eventHubTrigger",
"name": "myEventHubMessage",
"direction": "in",
"path": "edpvineethub",
"connection": "AzureWebJobsServiceBus"
}
]
}
My folder structure is as below:-I have included the following files in the web application project:-
bin\FunctionAsWebApp.dll
NameOfYourFunction\function.json
AnotherFunctionIfYouHaveOne\function.json
appsettings.json
host.json
However I am getting the below error message when trying to run locally;-
No job functions found. Try making your job classes and methods public. If you'r
e using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've call
ed the registration method for the extension(s) in your startup code (e.g. confi
g.UseServiceBus(), config.UseTimers(), etc.).
Any help would be appreciated.
Check that your folder structure looks like this:
bin\FunctionAsWebApp.dll
NameOfYourFunction\function.json
AnotherFunctionIfYouHaveOne\function.json
appsettings.json
host.json
And function.json should of course reference the binary accordingly
"scriptFile": "..\\bin\\FunctionAsWebApp.dll"
Your initialization is likely failing to perform a lookup on the SB connection string, as it expects an App Setting/Environment variable name and you have the actual connection string there.
Please update your function.json to use an App Setting name, defined in your appsettings.json locally and the Function App settings when hosted, with the connection string set as its value.
Important: Since you have your connection string pasted above, I strongly recommend resetting your credentials.
I've been trying to create a Azure function being triggered when I add a image to a container on my blob storage account.
The only thing that seems to work, is when I have a string parameter, but the files are images, so I have no use for a string containing the image data.
So I've been trying each and every example I can find online (not that many), and now I've tried the samples from the azure webjobs sdk - this isn't wokring either. So either I'm stupid, which I feel right now, I'm missing something obvious?
There are some of the errors I get:
Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.thumbnailgenerator'. Microsoft.Azure.WebJobs.Host: Can't bind BlobTrigger to type 'Microsoft.WindowsAzure.Storage.Blob.ICloudBlob'.
Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.thumbnailgenerator'. Microsoft.Azure.WebJobs.Host: Can't bind BlobTrigger to type 'Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob'.
Right now the function I'm trying out, is the one given in the sample above, and like so many others I've tried, it's not working with anything but strings.
So how should I create the function (with C#) and the function.json file, to make it work with a blob in and preferable a string in with the name of the blob. Either that or blob in and one out, where the name of the out blob is in a different container and the name is prefixed with a hardcoded string.
This is what I got now, and it's not running:
function.json
{
"bindings": [
{
"type": "blobTrigger",
"name": "blob",
"direction": "in",
"path": "kitimages/{name}.{ext}"
},
{
"type": "blob",
"name": "output",
"direction": "inout",
"path": "thumbnails/{name}_300_200.{ext}"
} ],
"disabled": false
}
run.csx
#r "Microsoft.WindowsAzure.Storage"
using System;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage.Blob;
public static void Run(CloudBlockBlob blob, CloudBlockBlob output, TraceWriter log)
{
log.Info($"C# Blob trigger function processed a blob. Blob={blob.Name}");
}
EDIT: Take a look here for the final solution to my question: Getting work done in the cloud
We need to improve the template here, this is a common pitfall you've run into (sorry about that!). We're fixing, see the GitHub issue: Make it easier for users to get started with binary blob triggers.
There's a built-in template that binds to streams. Go to New Function and select C# for language and Samples for Scenario.
For a more advanced sample that uses CloudBlockBlob bindings (which requires the InOut binding direction that is not yet documented), see the Functions sample in ContosoMoments: DeleteImages Function.
Note that you can browse all the templates in the GitHub repo: https://github.com/Azure/azure-webjobs-sdk-templates.
For anyone else stumbling upon this while seemingly having a correct setup as per above:
I got this message because I had a reference to WindowsAzure.Storage in my project.json file. Perhaps because it was referring to an older version (8.1.1) of the library.. I don't know. Removing it made my function work. Since it's a supported DLL you should just import it using #r..
I found my solution here (the last reply by Baudine).
I had a project that referenced WindowsAzure.Storage nuget directly and a function project that that project but also referenced WindowsAzure.Storage indirectly (through Microsoft.Azure.WebJobs.Extensions.Storage nuget). After reading Baudine's answer, I saw that the versions off (v9.3.3 vs v9.3.1).
So my fix was as Baudine suggested: I removed the WindowsAzure.Storage nuget from the project and added Microsoft.Azure.WebJobs.Extensions.Storage. My trigger looks like this:
public async Task Run([BlobTrigger("/files/{fileName}", Connection = "StorageConnectionString")]ICloudBlob blob, string fileName)