Programmatically get function app url from event grid triggered function - azure

In an HTTP triggered azure function we can get the url as follows
public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, Microsoft.Azure.WebJobs.ExecutionContext executionContext, ILogger log)
{
string url = req.Scheme + "://" + req.Host + $"/api/AnotherFunctionOnTheApp";
}
But how do we do it in an event grid triggered function where we do not have the HTTPRequest object?
public static void Run([EventGridTrigger]EventGridEvent eventGridEvent, ILogger log)
{
}
The objective is to call an HTTP triggered function on the same functionapp from the event grid triggered function.

A simple example to get the url of the httptrigger:
string url = "https://" + Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME") + "/api/AnotherFunctionOnTheApp";
(Azure will offer a secure domain by default. So we can use 'https'.)

Related

Azure Function Optional Query Parameter

is there a way to set optional query parameters in Azure Functions? The parameter should not be set as route parameter.
To get the query parameters i use following code snipped
IDictionary<string, string> queryParams = req.GetQueryParameterDictionary();
Methode signature is following:
public async Task<IActionResult> Function(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
[DurableClient] IDurableOrchestrationClient starter
)
If you don't want to set it as the route parameter, you can use like below:
string param = req.Query["param"];
if (string.IsNullOrEmpty(param)) {
//do nothing.
} else {
//do something.
}

FromQuery support in Azure Functions v3

I am trying to use [FromQuery] with Azure Function v3 but I am getting the following error:
Cannot bind parameter 'search' to type String.
For the following method:
[FunctionName("GetObjects")]
public ActionResult<IActionResult> QueryObjects(
[HttpTrigger(AuthorizationLevel.Function, "GET", Route = "objects")]
HttpRequest req,
ILogger log,
[FromQuery] string search = null)
{
//do some stuff
}
Is [FromQuery] not supported?
Should I use req.Query["search"] to get the query parameter?
From functions.desp.json
Related to binding
"Microsoft.Extensions.Configuration.Binder/3.1.1": {
"dependencies": {
"Microsoft.Extensions.Configuration": "3.1.2"
},
"runtime": {
"lib/netcoreapp3.1/Microsoft.Extensions.Configuration.Binder.dll": {
"assemblyVersion": "3.1.1.0",
"fileVersion": "3.100.119.61404"
}
}
},
This is what you face now:
Method signatures developed by the azure function C # class library can include these:
ILogger or TraceWriter for logging (v1 version only)
A CancellationToken parameter for graceful shutdown
Mark input and output bindings by using attribute decoration
Binding expressions parameters to get trigger metadata
From this doc, it seems that it is not supported. You can create your custom binding like this, and dont forget to register it in the startup.
If you want to bind it directly, it's not possible. So you could try to change your route like Function1/name={name}&research={research} then bind it to string parameter.
Below is my test code:
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route="Function1/name={name}&research={research}")] HttpRequest req,
String name,
String research,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
log.LogInformation(research);
string responseMessage = $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}

Call another Azure Function from timer triggered one

I want to call another (not timer triggered) azure function from my timer triggered azure function.
It compiles but during runtime I get the error:
System.ArgumentException: 'The function 'HelloWorld' doesn't exist, is disabled, or is not an orchestrator function. Additional info: No orchestrator functions are currently registered!'
I reduced it to this tiny code snippet.
[FunctionName("HelloWorld")]
public static string HelloWorld([ActivityTrigger] string name, ILogger log)
{
return $"Hello {name}!";
}
[FunctionName("DownloadLiveList")]
public async void DownloadLiveList([DurableClient] IDurableOrchestrationClient client, [TimerTrigger("0 0 0 * * *", RunOnStartup = true)]TimerInfo myTimer, ILogger log)
{
await client.StartNewAsync<string>("HelloWorld", "Magdeburg");
}
As I took the idea from the official Microsoft example for that kind of azure function cascading, I've no clue, why the function "HelloWorld" is not registered. After uploading into azure, the function is visible in the azure portal as all other functions from the class.
Your time trigger function needs to invoke the start function written with Durable Function Framework. Here's a sample:
[FunctionName("Function1")]
public async Task Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
var url = "http://localhost:7071/api/Durable_Starter";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
using (HttpWebResponse response = (HttpWebResponse) await request.GetResponseAsync())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
var html = reader.ReadToEnd();
log.LogInformation(html);
}
}
[FunctionName("Durable_Starter")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]HttpRequest req, [DurableClient] IDurableClient starter, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string instanceId = await starter.StartNewAsync("Durable_Orchestrator");
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
var checkStatusResponse = starter.CreateCheckStatusResponse(req, instanceId);
return checkStatusResponse;
}
[FunctionName("Durable_Orchestrator")]
public async Task RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
{
var message = await context.CallActivityAsync<string>("HelloWorld", "Thiago");
log.LogInformation(message);
}
[FunctionName("HelloWorld")]
public string HelloWorldActivity([ActivityTrigger] string name)
{
return $"Hello {name}!";
}

azure function: set blob filename from http request

I am trying to set an azure function to upload a blob from an HTTP request to a blob.
I was able to use the following for uploading a file with a static filename:
public static class Uploader
{
[FunctionName("Uploader")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequest req,
[Blob("hello/uploaded.jpg", FileAccess.Write)]Stream writer,
TraceWriter log
)
{
log.Info("trigger for image upload started...");
if (!req.ContentType.Contains("multipart/form-data") || (req.Form.Files?.Count ?? 0) == 0)
{
log.Warning("no images found on upload attempt");
return new BadRequestResult();
}
foreach (var file in req.Form.Files)
file.CopyTo(writer.);
return new OkObjectResult("Done!");
}
}
Is there any way I could alter Blob("hello/uploaded.jpg") into something like Blob("hello/{fileName}" to get the name dynamically the HTTP request. I don't mind if it's anywhere from the head or body. I am trying to not use the whole GetBlockBlobReference process just for the dynamic file name alone.
Update
I am not sure if I am missing something or looking at this problem the wrong way. For a serverless set up with a blob storage isn't an HTTP upload supposed to be an obvious and common scenario? How come there aren't any examples for this?
The option suggested by #RomanKiss should work. Alternatively, if you want you can put filename into the function URL template:
[FunctionName("Uploader")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "uploader/{filename}")]
HttpRequest req,
string filename,
[Blob("hello/{filename}", FileAccess.Write)] Stream writer,
TraceWriter log)
{
//...
}
the following is an example with both an HttpRequestMessage and a POCO binding:
[FunctionName("Uploader")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] Info input, HttpRequest req,
[Blob("hello/{FileName}", FileAccess.Write)]Stream writer,
TraceWriter log
)
{
//...
}
public class Info
{
public string FileName { get; set; }
//...
}
Update:
The following snippet shows an example for using an expanding HttpTrigger binding data support with a well-known properties such as headers and query, more details here:
[FunctionName("Uploader")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)HtpRequest req,
[Blob("hello/{query.filename}", FileAccess.Write)] Stream writer,
// [Blob("hello/{headers.filename}", FileAccess.Write)] Stream writer,
TraceWriter log)
{
//...
}
sample of url:
http://localhost:7071/api/Uploader?filename=uploaded.jpg

Can an azure job with a HTTP Trigger return a http response body?

I have an azure function like this:
[FunctionName("DoStuff")]
[return: Queue("stuff-queue")]
public static async Task<StuffContext> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
var context = await req.Content.ReadAsAsync<StuffContext>();
context.TransactionId = Guid.NewGuid();
return context;
}
It listens on a https url, deserializes the request body, and send body to the queue. Can I also have it return something (the transaction id in this case) as part of the http response.
Can I also have it return something (the transaction id in this case) as part of the http response.
Using [return: Queue("stuff-queue")] will return the information to the queue. But it could not return a response and add the information to the queue at the same time.
If you want to do, you could refer to my code.It works fine on my side.
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post")]HttpRequestMessage req,
TraceWriter log,
[Queue("stuff-queue")] IAsyncCollector<string> outputQueue)
{
log.Info("C# HTTP trigger function processed a request.");
string yourinfo = "yourinfo";
await outputQueue.AddAsync(yourinfo);
return req.CreateResponse(HttpStatusCode.OK, yourinfo);
}
For more details, you could refer to this article.

Resources