Setting Azure Function Service Bus Topic and Subscription Output Binding via C# - azure

I have a simple HTTP trigger Azure Function with multiple Service Bus output bindings. All the bindings are pointing to the same Topic, but they have different Subscriptions. If I was to set this function app through function.json it is pretty straightforward:
{
"bindings": [
{
"authLevel": "function",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"methods": [
"get",
"post"
]
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"type": "serviceBus",
"connection": "SERVICEBUS",
"name": "output",
"topicName": "outtopic",
"subscriptionName": "sub",
"direction": "out"
},
{
"type": "serviceBus",
"connection": "SERVICEBUS",
"name": "output",
"topicName": "outtopic",
"subscriptionName": "sub2",
"direction": "out"
}
],
"disabled": false
}
But I publish my functions via Visual Studio and therefore my Azure Functions are read only in the portal and function.json is automatically generated by VS upon publishing.
The problem is that I cannot figure out how do I setup multiple output bindings pointing to different subscriptions. Currently I have something like this:
[FunctionName("Function2")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
[ServiceBus("outtopic", entityType:EntityType.Topic)] IAsyncCollector<string> output,
[ServiceBus("outtopic", entityType: EntityType.Topic)] IAsyncCollector<string> output2,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
await output.AddAsync(requestBody);
return new OkObjectResult("OK");
}
As you can see output and output2 are pointing to the same Topic, but there is no option to specify Subscription.
At this point I am pretty confident that this has not been implemented yet. But I hope there is a workaround maybe?

Try this, add Connection property in the definition, per this example - if by subscription you mean on the azure subscription:
public static void Run([BlobTrigger("inputvideo/{customername}/{date}/{filename}", Connection = "AzureWebJobsStorage")]Stream myBlob,
string customername,
string date,
string filename,
[ServiceBus("detectobjectsqueue",EntityType.Queue, Connection="ServiceBusConnectionString")] IAsyncCollector<string> output,
ILogger log)
Update
Per your comment, I understood that by subscription you mean on topic subscription. In that case, the idea of topic is that all subscriptions receive the message. So you have one publisher, and whoever subscribes to the topic it will receive the message. If you would like to make sure that a specific subscriber receives the message, either implement message filtering(per type for example) on the receiving endpoint or use dedicated queue per subscriber.
Also, conceptually, the publisher should not know who are the subscribers, and the subscriber should not know who is the publisher. If you know who is the subscriber, why not use the REST call for example to the receiving endpoint?

It is not possible to directly put messages into a Topic Subscription, rather every message has to come through a Topic.
To make sure only a particular subscription receives a message, you need to configure the Topic Subscription rule. You can read more about rules in the blog post here.

Related

Azure Function not working with serviceBusTrigger NodeJs

I have been trying to put a message in azure service bus topic. My azure function test says that the message has been accepted(202). But there is no message on the subscription side, Could you please help me in this POC. Here is my code snippet. It's a sample that got generated from VS code, I am using serviceBusTrigger.
const { ServiceBusClient, ReceiveMode } = require("#azure/service-bus");
module.exports = async function(context, mySbMsg) {
context.log('JavaScript ServiceBus topic trigger function processed message', mySbMsg);
context.done();
};
Is there any way that I can check if the service bus topic is working as expected?
I do not see a connection string and a binding associated with the code, Inorder to save the message to the queue, you need to have the Queue connection strings in the settings file. Follow the docs,
{
"bindings": [
{
"schedule": "0/15 * * * * *",
"name": "myTimer",
"runsOnStartup": true,
"type": "timerTrigger",
"direction": "in"
},
{
"name": "outputSbQueue",
"type": "serviceBus",
"queueName": "testqueue",
"connection": "MyServiceBusConnection",
"direction": "out"
}
],
"disabled": false
}
Okay, So the thing was, I tried calling the function after pushing messages onto the topic. But the purpose of ServiceBusTriger is reverse. The function with this trigger processes the message when there is message on queue. There is no need to Call the function separately. Yeah, so basics, just create the function with your available topic and subscription, and then try putting message onto the topic. You can see the message in the log of the function.

Trying to upload a file with ftp using azure functions

I am trying to send a file using external file protocol and FTP api connection. The configuration and code is straight forwards and the app runs successfully however no data is sent to the FTP and I cannot see any trace that the function even tried to send data using ftp.... What is wrong? and more important; Where can i monitor the progress of the external file api?
My code follows (Note: I have tried Stream and string as input and output)
run.csx
public static void Run(Stream myBlobInput, string name, out Stream
myFTPOutput, TraceWriter log)
{
myFTPOutput = myBlobInput;
//log.Info($"C# Blob trigger function Processed blob\n Name:{name} \n Content:{myBlob}");
log.Info($"C# Blob trigger function Processed blob\n Name:{name} \n Size:{myBlobInput.Length} \n Content:{myBlobInput.ToString()}");
}
function.json
"bindings": [
{
"name": "myBlobInput",
"type": "blobTrigger",
"direction": "in",
"path": "input/{name}",
"connection": "blob_STORAGE"
},
{
"name": "myFTPOutput",
"type": "apiHubFile",
"direction": "out",
"path": "/output/{name}",
"connection": "ftp_FTP"
}
],
"disabled": false
}
I could make it working :
If we want to have same file content in the output FTP server and same file name ,then here is the code and function.json
public static void Run(string myBlob, string name, TraceWriter log , out string outputFile )
{
log.Info($"2..C# Blob trigger function Processed blob\n Name:{name} \n Size:{myBlob.Length} \n Content:{myBlob.ToString()}");
outputFile=myBlob;
}
Also here is the function.json
{
"bindings": [
{
"name": "myBlob",
"type": "blobTrigger",
"direction": "in",
"path": "myblobcontainer/{name}",
"connection": "AzureWebJobsDashboard"
},
{
"type": "apiHubFile",
"name": "outputFile",
"path": "LogFiles/{name}",
"connection": "ftp_FTP",
"direction": "out"
}
],
"disabled": false
}
the input binding should have a valid container name as in blob account here--:
blob container structure as path
Also in output binding for FTP, the path should be any folder in Root of FTP , what you see in FTP login UI/console and then filename , which in this case {name} ,which allows us to keep the same output file name as input blob name.
Ok, so I changed the ftp Connection to some other server and it work like a charm. That means that there were some firewall refusal from the Azure Function that triggered. The sad thing is that no error messages triggers that i can spot. Thanks for all support

Azure functions: how to bind query string parameters of http trigger function to SQL query of Cosmos DB

I am trying to run an http trigger Azure function with Cosmos DB input binding. I would like the url of the http trigger to include several parameters on the query string that become bound to the SQL query of the input Cosmos DB binding. I am trying the following bindings in function.json, but it does not work (the function does not even get triggered):
{
"direction": "in",
"type": "httpTrigger",
"authLevel": "anonymous",
"name": "req",
"methods": [ "get" ],
"route": "users/{age=age?}/{gender=gender?}"
},
{
"direction": "in",
"type": "documentDB",
"name": "users",
"databaseName": "Database",
"collectionName": "Users",
"sqlQuery": "SELECT * FROM x where x.age = {age} and x.gender = {gender}",
"connection": "COSMOSDB_CONNECTION_STRING"
},
According to this answer the route constraint users/{age=age?}/{gender=gender?} is valid for Web API, and according to the documentation you can use any Web API Route Constraint with your parameters. Ultimately I would to like make a GET request to the Azure function that looks like api/users?age=30&gender=male. How should this be done then?
I don't think you can configure a Cosmos DB binding to values defined in query parameters e.g. ?age=30. At least I haven't seen any examples like that in the functions documentation.
But you can bind them to the route parameters to achieve the same outcome, which you have pretty much done already.
Keeping that route of users/{age}/{gender}, your Cosmos SqlQuery will then pick up those route parameters when invoking a GET on http://yourfunctionhost/yourfunction/users/30/male
GET and POST parameter will be bound, so they can be used inside the sqlQuery without any additional configuration. Just give it a try, this has definitely changed in the past
You can bind the Query-Values to CosmosDB Input Binding:
Azure Cosmos DB input binding for Azure Functions 2.x and higher
[FunctionName("DocByIdFromQueryString")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
HttpRequest req,
[CosmosDB(
databaseName: "ToDoItems",
collectionName: "Items",
ConnectionStringSetting = "CosmosDBConnection",
Id = "{Query.id}",
PartitionKey = "{Query.partitionKey}")] ToDoItem toDoItem,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
if (toDoItem == null)
{
log.LogInformation($"ToDo item not found");
}
else
{
log.LogInformation($"Found ToDo item, Description={toDoItem.Description}");
}
return new OkResult();
}

Azure Function binding: get both EventData and strongly typed message

I have the following function definition.
Message type:
type MailboxItem = {
CustomerID: int
AssetID: int
}
Code:
let Run(item: MailboxItem, userNames: string, log: TraceWriter) =
log.Verbose("F# function executing for " + item.AssetID.ToString())
And function.json:
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "item",
"direction": "in",
"path": "eventhubpath",
"connection": <connection>,
"consumerGroup": "$Default"
},
{
"type": "blob",
"name": "userNames",
"path": "blobpath/{CustomerID}-{AssetID}",
"connection": <connection>,
"direction": "in"
}
],
"disabled": false
}
As you can see, I'm using properties of the incoming message to bind an input blob from Blob Storage.
Now, I need to extend my function to access some metadata of the incoming message via EventData class (e.g. sequence number). Is it possible to add EventData parameter but also keep the binding to properties of the message body?
No not currently, unfortunately, though this is a common ask and something we're tracking in our repo here and will hopefully get to soon. Until we do, it is an either/or - you can bind to EventData or your custom POCO.

AzureFunctions binding to SendGrid

Trying to figure out how to use SendGrid from an azure function. Not much docs to find, but this is what I've tried:
#r "SendGrid"
using SendGrid.Helpers.Mail;
using System;
public static void Run(string myQueueItem, out Mail message, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {myQueueItem}");
message=new Mail();
}
I've hardcoded to, from, subject and body, together with api key in the integrate output section. This is my function.json:
{
"bindings": [
{
"name": "myQueueItem",
"type": "queueTrigger",
"direction": "in",
"queueName": "send-email-request",
"connection": "myStorage"
},
{
"type": "sendGrid",
"name": "message",
"apiKey": "SG.xxxxxxxxxxx",
"direction": "out",
"to": "me#gmail.com",
"from": "me#gmail.no",
"subject": "hardcoded",
"text": "test213"
}
],
"disabled": false
}
I get the following error:
Function ($SendEmailOnQueueTriggered) Error: Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.SendEmailOnQueueTriggered'. Microsoft.Azure.WebJobs.Host: 'SG.xxxxxx' does not resolve to a value.
Session Id: 9426f2d7e4374c7ba7e0612ea5dc1814
Timestamp: 2017-01-07T12:18:01.930Z
I've granted the Apikey full access in SendGrid. Any ideas what I've missed?
Larsi
The ApiKey field is not the actual ApiKey, it should instead be the name of an AppSettings key defined in the "functions app settings".
Adding "AzureWebJobsSendGridApiKey" in your AppSettings via local.settings.json and in Configuration -> Application Setting via Azure Portal will work.

Resources