Azure Functions SDK - c#

After upgrading to 1.0.1 CLI tools without any code changes, I suddenly started to get the following error:
ResizeImage: Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.ResizeImage'.
Microsoft.Azure.WebJobs.Extensions.DocumentDB:
'Id' is required when binding to a DocumentClient property.
The following code:
[FunctionName(nameof(ResizeImage))]
public static async Task RunAsync([BlobTrigger("profile-pictures/{name}")] CloudBlockBlob myBlob, string name, [DocumentDB(databaseName: "x", collectionName: "UserProfile", CreateIfNotExists = true)] DocumentClient client, [Blob("profile-pictures/resized-{name}", FileAccess.ReadWrite)] CloudBlockBlob resizedBlob, TraceWriter log)
I thought Id is optional? At least that's what the docs says.
According to the docs:
The properties id and sqlQuery cannot both be specified. If neither id
nor sqlQuery is set, the entire collection is retrieved.
The generated json:
{
"bindings": [
{
"type": "blobTrigger",
"path": "profile-pictures/{name}",
"direction": "in",
"name": "myBlob"
},
{
"type": "documentDB",
"databaseName": "x",
"collectionName": "UserProfile",
"createIfNotExists": true,
"direction": "out",
"name": "client"
},
{
"type": "blob",
"path": "profile-pictures/resized-{name}",
"direction": "inout",
"name": "resizedBlob"
}
],
"disabled": false,
"scriptFile": "..\\X.Functions.dll",
"entryPoint": "X.Functions.ResizeImage.RunAsync"
}
I'm using 1.0.0 SDK

I thought Id is optional? At least that's what the docs says.
Yes, id is optional. But according to the document of Azure Functions Cosmos DB bindings. We need to use IEnumerable<dynamic> as the binding type. Please change your code as following.
[DocumentDB(...)] IEnumerable<dynamic> documents
You will get all the documents from the collection. I tested it and it worked fine on my side.
In addition, the direction should be changed to in if you want to get data from DocumentDB.
"direction": "in"

Related

Azure deployment via SDK

I'm running out of time to get this done, but I just can't seem to find my issue.
I'm trying to deploy an ARM template that creates a new MCA subscription. The template works when deployed via Azure PowerShell, but when using the Azure SDK it gives the following error:
Microsoft.Rest.Azure.CloudException: 'Deployment template validation failed: 'The resource 'Microsoft.Subscription/aliases/devtestdeployasp22' referenced in output is not defined in the template. Please specify resource identifier and api version if the resource is outside of the template. Please see https://aka.ms/arm-template-expressions/#reference for usage details.'.'
var subscription = azure.Deployments
.Define("deployment_temp")
.WithNewResourceGroup("temprg", Region.USEast)
.WithTemplate(Utils.GetArmTemplate("<path_to_file_removed_for_privacy>"))
.WithParameters("{}")
.WithMode(Microsoft.Azure.Management.ResourceManager.Fluent.Models.DeploymentMode.Incremental)
.Create();
The template used with this contains:
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"subscriptionAliasName": {
"type": "string",
"metadata": {
"description": "Provide a name for the alias. This name will also be the display name of the subscription."
}
},
"billingScope": {
"type": "string",
"defaultValue": "<Removed>",
"metadata": {
"description": "Provide the full resource ID of billing scope to use for subscription creation."
}
},
"mgName": {
"type": "string",
"defaultValue": "mg-mission-default-dev",
"metadata": {
"description": "management group name"
}
}
},
"variables": {
"mgId": "[concat('Microsoft.Management/managementGroups/',parameters('mgName'))]"
},
"resources": [
{
"scope": "[variables('mgId')]",
"name": "[parameters('subscriptionAliasName')]",
"type": "Microsoft.Subscription/aliases",
"apiVersion": "2021-04-01",
"properties": {
"workLoad": "Production",
"displayName": "[parameters('subscriptionAliasName')]",
"billingScope": "[parameters('billingScope')]"
}
}
],
"outputs": {
"subscriptionID": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Subscription/aliases', parameters('subscriptionAliasName'))).subscriptionId]"
}
}
}
Any help would be appreciated, or even an alternate path I could take but the goal is to create a new MCA subscription (with some resources) using C#.
You need to fetch the Subscription ID by using tenantResourceId -
tenantResourceId - Returns the unique identifier for a resource deployed at the tenant level.
"outputs": {
"subscriptionId": {
"type": "string",
"value": "[reference(tenantResourceId('Microsoft.Subscription/aliases', parameters('subscriptionAliasName'))).subscriptionId]"
}
}
Please refer this documentation.

How to represent an array of longs as a query parameter in Swagger 2.0?

I am having a hard time figuring out what would be the correct Swagger 2.0 spec for the case where I am expecting a parameter in the query to be a list of long (C#). This is what I tried based on seeing examples where the parameter being passed in query is simple datatypes like int or boolean. But this does not seem to work. It does not look like it is getting parsed correctly.
My URI is somethng like this :
https://.../testinstance/FeatureTexts?api-version=2016-09-13&featureIds=1629988727&featureIds=1924980024
And in my API-level test it does not gets resolved to anything similar after the part api-version=2016-09-13&featureIds=
"get": {
"tags": [
"FeatureText"
],
"operationId": "RenderFeatureTexts",
"description": "The operation to get feature texts for specified features",
"parameters": [
{
"name": "featureIds",
"in": "query",
"required": true,
"schema": {
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "integer",
"format": "int64"
}
},
.......
C# code generated by Swagger Codegen:
public static async System.Threading.Tasks.Task<object> ListFeatureTextsAsync(this IAgentClient operations, object featureIds, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
using (var _result = await operations.ListFeatureTextsWithHttpMessagesAsync(featureIds, null, cancellationToken).ConfigureAwait(false))
{
return _result.Body;
}
}
Change the parameter definition as shown below, that is, move type, items and collectionFormat out of schema. In OpenAPI 2.0, schema is only used for body parameters, and other parameter types use type etc. directly.
"parameters": [
{
"name": "featureIds",
"in": "query",
"required": true,
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "integer",
"format": "int64"
}
You can easily catch syntax errors like this by pasting your spec into Swagger Editor.

Service Bus Output Bindings Throwing Error in both Azure and Local Testing

So I have the following function header:
[FunctionName("listenServiceBus")]
public static void Run([ServiceBusTrigger("metadataingest", AccessRights.Manage, Connection = "ServiceBus")]string mySbMsg,
ExecutionContext context, [ServiceBus("successqueue", Connection = "DEVservicebus", EntityType = Microsoft.Azure.WebJobs.ServiceBus.EntityType.Queue)]out string outputSuccess,
[ServiceBus("failqueue", Connection = "DEVservicebus", EntityType = Microsoft.Azure.WebJobs.ServiceBus.EntityType.Queue)]out string outputFailure, ILogger Log)
Where I bind to two separate Service Buses for input and outputs of the function. My function.json file looks like the following:
{
"bindings": [
{
"type": "serviceBusTrigger",
"connection": "ServiceBus",
"queueName": "metadataingest",
"accessRights": "manage",
"name": "mySbMsg"
},
{
"name": "outputSuccess ",
"type": "serviceBus",
"queueName": "successqueue",
"connection": "DEVservicebus",
"direction": "out"
},
{
"name": "outputFailure",
"type": "serviceBus",
"queueName": "failqueue",
"connection": "DEVservicebus",
"direction": "out"
}
],...
I am getting the following errors:
No job functions found. Try making your job classes and methods public. 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.).
And:
listenServiceBus: The binding name outputSuccess is invalid. Please assign
a valid name to the binding.
I am currently running .Net.Sdk.Function 1.0.12.Anyone know any workarounds?
See "name": "outputSuccess ", in your bindings, looks like there is an extra space after outputSuccess. You should delete it and try again.

Adding to an Azure CosmosDB from inside an Azure Function

I've created a CosmosDB DB, with a single table, called MyTable. My idea is that I want to insert into this table from an Azure function. Having had a look around, I've come up with this function:
public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log, out object tableOutput)
{
log.Info("C# HTTP trigger function processed a request.");
// parse query parameter
string field1 = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "field1", true) == 0)
.Value;
string field2 = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "field2", true) == 0)
.Value;
var item = new
{
field1 = field1,
field2 = field2
};
tableOutput = item;
return req.CreateResponse(HttpStatusCode.OK);
}
The error that I get is this:
2017-12-07T15:52:44.066 Exception while executing function:
Functions.MyFunc. Microsoft.Azure.WebJobs.Host: Error while handling
parameter tableOutput after function returned:.
Microsoft.Azure.WebJobs.Extensions.DocumentDB: The collection
'tableOutput' (in database 'myCosmosDB') does not exist. To
automatically create the collection, set 'CreateIfNotExists' to
'true'. Microsoft.Azure.Documents.Client: Message: {"Errors":["Owner
resource does not exist"]}
I have set-up the output parameter, and I have seen the checkbox mentioned here (CreateIfNotExists); however, I have an existing Cosmos table set-up, and would like to write to that; so my question is, how can I access that table from within an Azure function?
The function.json is below:
{
"bindings": [
{
"authLevel": "function",
"name": "req",
"type": "httpTrigger",
"direction": "in"
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"type": "documentDB",
"name": "outputDocument",
"databaseName": "mycosmosdb",
"collectionName": "tableOutput",
"createIfNotExists": false,
"connection": "mycostmosdb_DOCUMENTDB",
"direction": "out"
}
],
"disabled": false
}
EDIT:
Two people have implied that for the purposes of this question the terms Table and Collection are synonymous. If I have understood correctly, then this appears to not be the case, as even when I change the collection name in the function.json to match the name of the table that I created, I get the same error.
To clarify the CosmosDB table configuration, I am seeing, inside data explorer, a node entitles TablesDB, which has a sub-node of the table that I've created.
You need to update the Function.json with the correct "collectionName" value for your Cosmos DB Collection you're trying to save the new Document to. Currently, you do NOT have a Collection in your Cosmos DB Database ("mycosmosdb") with the name "tableOutput".
Also, if you'd wish for the Azure Function Output binding to automatically create the Collection if it doesn't exist, then set the Function.json property "createIfNotExists" to "true" and it'll create the Collection if it doesn't exist.
Either approach will get your code working without error, but you'll need to make sure the "collectionName" is set to the correct name of your Cosmos DB Collection you have set up.
For example, try changing your Function.json to the following:
{
"bindings": [
{
"authLevel": "function",
"name": "req",
"type": "httpTrigger",
"direction": "in"
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"type": "documentDB",
"name": "outputDocument",
"databaseName": "mycosmosdb",
"collectionName": "MyTable",
"createIfNotExists": true,
"connection": "mycostmosdb_DOCUMENTDB",
"direction": "out"
}
],
"disabled": false
}
Make sure this is the value of your existing collection:
(you mention MyTable but it says tableOutput)
"collectionName": "tableOutput",
Make sure the names are identical. Collection names are case sensitive. "mytable" and "myTable" are different collections

How to copy a file from azure blob to on-premises file system using azure blob trigger using C#?

I am trying to create an azure blob trigger to copy the file uploaded to the azure blob to the on-premises file system. Can anyone please provide the steps for the same?
What I have tried:
I created a blob trigger and bound its output parameter to external file(preview) and selected the File System API. It asks for Display name, root folder, username and password. What goes here and how to connect azure to my machine's file system?
This is my function.json file.
{
"bindings": [
{
"name": "myBlob",
"type": "blobTrigger",
"direction": "in",
"path": "input/{name}",
"connection": "connection_Name"
},
{
"type": "apiHubFile",
"name": "outputFile",
"path": "outout/{name}",
"connection": "file_system_connection_name",
"direction": "out",
"typeProperties": {
"host": "HostName",
"userid": "userid",
"password": "userpassword",
"gatewayName": "gatewayName"
}
}
],
"disabled": false
}
This is my run.csx file.
public static void Run(Stream myBlob, string name, TraceWriter log,Stream outputFile)
{
myBlob.CopyTo(outputFile);
}

Categories