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.
Related
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.
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
Is it possible to invoke cosmos db trigger in azure pipeline? Pipeline is just copy data from azrue storage to cosmos db collection and it is necessary to invoke pre trigger. How to specify trigger id for copy activity?
From what you are saying, you might solve this by using Azure Functions with a Blob Trigger and a DocumentDB output binding.
With a functions.json similar to:
{
"disabled": false,
"bindings": [
{
"name": "myBlob",
"type": "blobTrigger",
"direction": "in",
"path": "<name-of-the-folder-where-files-get-uploaded>",
"connection":"MyStorageAccount"
},
{
"name": "documentToSave",
"type": "documentDB",
"databaseName": "MyDatabase",
"collectionName": "MyCollection",
"createIfNotExists": true,
"connection": "MyAccount_COSMOSDB",
"direction": "out"
}
]
}
And the function body could be something like:
// Blob trigger binding to a CloudBlockBlob
#r "Microsoft.WindowsAzure.Storage"
using Microsoft.WindowsAzure.Storage.Blob;
public static void Run(CloudBlockBlob myBlob, out object documentToSave, TraceWriter log)
{
// some logic to read the blob and parse it
documentToSave = new {
id = "some value",
.. other properties here
};
}
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.
Does anyone know why I'm getting this error?
Here is my SendGrid output binding:
{
"bindings": [
{
"name": "docId",
"type": "queueTrigger",
"direction": "in",
"queueName": "movedocument",
"connection": "cpoffice365_STORAGE"
},
{
"type": "sendGrid",
"name": "message",
"apiKey": "<MYSENDGRIDKEY>",
"from": "<MYFROMEMAIL>",
"direction": "out"
}
],
"disabled": false
}
My code compiles, but then it throws this error in the log:
Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.<MYFUNCTIONAME>'. Microsoft.Azure.WebJobs.Host: '<MYSENDGRIDKEY>' does not resolve to a value.
Statto,
Please make sure you define an app setting (Function app settings > App Settings) with the name matching what you've used for your binding configuration, where the value is your Sendgrid key.
The binding configuration expects that to be an app setting name, not the actual key.
Thanks!