How to bind to ICloudBlob or some other (not string) type - azure

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)

Related

'No storage connection string found.' when trying to list durable function instances from azure functions core tools

I am currently trying to list all instances of an activity function and the orchestrator function using azure function core tools. The application synchronizes data from different sources into a centralized location.
The setup is as follows:
TimerTrigger -> Durable Orchestrator -> Multiple Activity Functions
In my concrete example, it is like this:
Start Synchronization -> Orchestrate Synchronizations -> Synchronize Source
So we start the synchronization process which starts the orchestrator. The orchestrator then starts multiple different synchronizations, one for each source. The problem though is that I cannot seem to get the azure function core tools to list me all instances of the functions I am interested in.
Unfortunately, I would really prefer not to have to use the REST api to query for this information. The setup really complicates things with IP restrictions and managed identity authentication. I think I can correct the setup to get things to work from my network + user, if really needed, but I think that will take way longer than required.
I have tried running the following command:
func durable get-instances
in a directory with a file called host.json with the following contents:
{
"version": "2.0",
"AzureWebJobsStorage":"DefaultEndpointsProtocol=https;AccountName=Name;AccountKey=Key;EndpointSuffix=core.windows.net",
}
I have also tried where the contents of the file are as follows:
{
"version": "2.0",
"extensions": {
"durableTask": {
"storageProvider": {
"connectionStringName": "DefaultEndpointsProtocol=https;AccountName=Name;AccountKey=Key;EndpointSuffix=core.windows.net"
}
}
}
}
I have tried calling the func durable get-instances with and without the --connection-string-setting parameter, with the values 'AzureWebJobsStorage' and 'extensions:durableTask:storageProvider:connectionStringName', but nothing seems to work. I keep getting the error No storage connection string found.
I know that the connection string is correct. I have pulled it directly from the storage account 'Access keys' blade.
Is there anything I am missing? What am I doing wrong?
Thanks to #juunas, I got it to work. I edited the host.json file to have the following content:
{
"version": "2.0"
}
and created another file called local.settings.json with the following contents:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=Name;AccountKey=Key;EndpointSuffix=core.windows.net",
}
}
Running func durable get-instances now works and returns a continuation token, but an empty list. I was not expecting that, but I can now start exploring and understanding here what is going on.

NuGet Packages do not compile Azure CSX

I have included a NuGet Package in an Azure Function app that I downloaded to work on in Visual Studio. I have added it to the project.json and I still get "error CS0246: The type or namespace name 'NetTopologySuite' could not be found (are you missing a using directive or an assembly reference?)". I've read through microsoft's documentation and cannot find what I could be doing wrong.
Here is a sample of what my csx looks like:
#r "System.Data"
using System;
using System.Data;
using System.Data.SqlClient;
using System.Net;
using NetTopologySuite;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
\\ Code to retrieve data from database and turn it into an array
\\ of GeoJSON features called DataFromDatabase not shown
NetTopologySuite.Features.Feature[] TrailSegments = DataFromDatabase;
HttpResponseMessage resp = req.CreateResponse(HttpStatusCode.OK);
resp.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(DataFromDatabase), System.Text.Encoding.UTF8, "application/json");
return resp;
}
Here is my project.json:
{
"frameworks": {
"net46": {
"dependencies": {
"NetTopologySuite.IO.GeoJSON": "1.14.0"
}
}
}
}
Does anyone have more experience with this that could offer a little more than what's in the documentation?
"FUNCTIONS_EXTENSION_VERSION": "~1"
"WEBSITE_NODE_DEFAULT_VERSION": "6.5.0"
If you do upload the project.json file to your function folder(not function app folder), what you have done is exactly right. I have followed your steps and things work fine on my side.
Nuget restoring for function editable online is not so sensitive, so you may wait for a while(you can do some edit in function code and click save or directly restart whole function app).
After that, you can see a project.lock.json under the function folder. It means the package has been installed successfully. Then everything goes well.
Update for multiple functions sharing reference.
One function package restore can't be used by others. So we have to upload dlls manually if you don't want to add project.json to every function. See shared assemblies.
Download NetTopologySuite.IO.GeoJSON.
Find four dlls(NetTopologySuite.dll/NetTopologySuite.IO.GeoJSON.dll/GeoAPI.dll/PowerCollections.dll) in package and upload them to a bin folder under function app folder.
Add four assemblies in code like #r "..\bin\NetTopologySuite.IO.GeoJSON.dll". You may also need add #r "Newtonsoft.Json" as it's one dependency in that package.
If you use the dll with namespace like NetTopologySuite.Features.Feature[], you don't have to import namespaces. And vice versa.
If you know those dependencies clearly, you can only upload and reference dlls you need.
I see that you are using 3rd party library which is widely available in Nuget official repository. In such cases, you need to let Azure know which Nuget repository your package, 'NetTopologySuite' resides in..
Github: https://github.com/NetTopologySuite/NetTopologySuite
NuGet v3: https://www.myget.org/F/nettopologysuite/api/v3/index.json
NuGet v2: https://www.myget.org/F/nettopologysuite/api/v2
Create Nuget.config file
Add the following contents in that file and re-configure it for your environment.
Nuget.config content - you can find exhaustive file online.

Output binding and generation of function.json

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.

How to make Azure Function code readable in Azure ARM json template

I have an Azure Resource group that contains an Azure Logic App that calls into an Azure Function.
I exported this Resource Group as an ARM template so I can re-import the resources to another Azure Subscription. This works fine, but the problem is, the Azure Function Code (100+ line c# file) is all included on one line of the JSON ARM template file. This makes is really hard to read or modify the Azure Function from the template itself.
Is there an easy way to work around this? Ideally my Azure Function would be in it's own file (run.csx), and the Azure JSON ARM template would just reference that external file.
Here is my JSON blob for the Function Resource in the ARM template. The line that contains run.csx for a key is my concern, how can I make this code more readable and easy for devs to edit?
{
"apiVersion": "2015-08-01",
"name": "[concat(parameters('test_site_name'),'\/ProvisionUser')]",
"type": "Microsoft.Web\/sites\/functions",
"properties": {
"config": {
"bindings": [
{
"authLevel": "function",
"name": "req",
"type": "httpTrigger",
"direction": "in"
},
{
"name": "return",
"direction": "out",
"type": "http"
}
]
},
"files": {
"run.csx": "LOTS OF C# CODE HERE - LOTS OF C# CODE HERE FROM MY AZURE FUNCTION - LOTS OF C# CODE HERE FROM MY AZURE FUNCTION - LOTS OF C# CODE HERE FROM MY AZURE FUNCTION - LOTS OF C# CODE HERE FROM MY AZURE FUNCTION - LOTS OF C# CODE HERE FROM MY AZURE FUNCTION - LOTS OF C# CODE HERE FROM MY AZURE FUNCTION - ",
"project.json": "{\r\n \"frameworks\": {\r\n \"net46\": {\r\n \"dependencies\": {\r\n \"Microsoft.IdentityModel.Clients.ActiveDirectory\": \"3.13.8\",\r\n \"Newtonsoft.Json\": \"10.0.2\",\r\n \"Microsoft.Sdk.CoreAssemblies\" : \"8.2.0.2\"\r\n }\r\n }\r\n }\r\n}"
}
}
}
You have some options:
Quick fix to your question: Run your ARM template through some code formatter. You may be in luck if you try copy-paste the template in to a json file in Visual Studio and then CTRL-K,CTRL-D to auto format it. I have not tried this but it may work. You can also cut the code out and format it using any one of a number of online formatting tools or using Visual Studio.
Deploy your functions from a source control system. Treat your infrastructure and code separately. I.e. Create your functions PaaS service from your ARM templates, but then use a CI/CD process to deploy your code and configuration (the functions).
Wrap your code in to an assembly, deploy the assembly to your function host and reference it in your function. This is called an external reference (documentation here) and will limit the amount of code in your function to plumbing, with your logic kept in a separate assembly. You will still need to work out how to deploy the assembly through script or your CI/CD process.
In short, and in line with the comments on your question, you need to support your Azure function development with a little more diligence from a development process perspective. This becomes even more critical if you will have a number of developers working on your functions.
Good luck!

Debugging Azure function as a C# Web Application

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.

Resources