FromQuery support in Azure Functions v3 - azure

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);
}

Related

Is it possible to define Azure Functions in an external project, referenced by the Function App?

I am trying to have some durable functions defined in separate projects, as I want to start them as suborchestrations from a root orchestration in my 'root project'.
However, it seems the actual Functions are not found, as they are part of the external project. Is this is known limitation? (I could not find this documented)
The exception that is thrown is the following: The function 'TestFunction' doesn't exist, is disabled, or is not an orchestrator function. Additional info: No orchestrator functions are currently registered!
For your interest, some code (but nothing special):
Functions project
[FunctionName("TestFunction_HttpStart")]
public static async Task<HttpResponseMessage> HttpStart(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]
HttpRequestMessage req,
[OrchestrationClient] IDurableOrchestrationClient starter,
ILogger log)
{
// Function input comes from the request content.
string instanceId = await starter.StartNewAsync("TestFunction", null);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
Referenced project
public class FunctionDefinitions
{
[FunctionName("TestFunction")]
public static async Task<List<string>> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var outputs = new List<string>();
// Replace "hello" with the name of your Durable Activity Function.
outputs.Add(await context.CallActivityAsync<string>("TestFunction_Hello", "Tokyo"));
outputs.Add(await context.CallActivityAsync<string>("TestFunction_Hello", "Seattle"));
outputs.Add(await context.CallActivityAsync<string>("TestFunction_Hello", "London"));
// returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
return outputs;
}
[FunctionName("TestFunction_Hello")]
public static async Task<string> SayHello([ActivityTrigger] string name, ILogger log)
{
log.LogInformation($"Saying hello to {name}.");
return $"Hello {name}!";
}
}
I did a test, and found it can't refer external orchestrator functions. I got the same error message as you, and it prompted me Additional info: The following are the known orchestrator functions: 'Function1'., Function1 is defined in the same project.
I have referenced the external project in the csproj file, but it still can't detect external orchestrator functions.
So, I suggest you define all durable function in the same Function app project.

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.
}

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

Is Attribute Routing possible in Azure Functions

I am trying to enforce a route parameter to be guid but getting below error
"Exception while executing function: GetUser -> One or more errors
occurred. -> Exception binding parameter 'req' -> Invalid cast from
'System.String' to 'System.Guid'."
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Admin, "get", Route = "GetUser/{userId:guid}")] HttpRequestMessage req,
Guid userId, ILogger log)
{
}
The request i am making is http://localhost:7071/api/GetUser/246fb962-604d-4699-9443-fa3fa840e9eb/
Am i missing some thing? Cannot we enforce route parameter to be guid ?
Invalid cast from 'System.String' to 'System.Guid'
I can reproduce same issue when use Route constraint {userId:guid} in Azure httptrigger function on my side, you can try to open an issue to give a feedback.
Besides, if possible, you can try to call Guid.TryParse method to convert the string back to Guid value in function code, the following code is for your reference.
public static string Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "GetUser/{userId:guid}")]HttpRequestMessage req, string userId, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
Guid newGuid;
var resmes = "";
if (Guid.TryParse(userId, out newGuid))
{
resmes = "userid: " + newGuid;
}
else {
resmes = "error";
}
return resmes;
}

Why do I need to add an out parameter to my output bindings?

Suppose I have this signature for my Azure Function:
[FunctionName("DoStuff")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
TraceWriter log,
[Queue("output-queue")] string outputQueue)
{
}
This method only works for me if I add an out parameter to the output binding, outputQueue. I'm using VS 2017.3.2
The Microsoft examples DO NOT use the out parameter. Why do I need to add the out parameter?
You need to use 'out' when your function is doing an assignment to one of the parameters. For example if your parameter is a string, or a byte[], or a poco, you'll need to do an assignment.
Here's one example from the documentation where out is required:
#load "..\shared\order.csx"
using System;
public static void Run(Order myQueueItem, out Order outputQueueItem,TraceWriter log)
{
log.Info($"C# Queue trigger function processed order...");
log.Info(myQueueItem.ToString());
outputQueueItem = myQueueItem;
}
You don't need to use out if your function is calling methods on the parameter. Stream, ICollector and IAsyncCollector all fall in this category. Here are two examples:
public async static Task ProcessQueueMessageAsync(
string blobName,
Stream blobInput,
Stream blobOutput)
{
await blobInput.CopyToAsync(blobOutput, 4096, token);
}
And:
#load "..\shared\order.csx"
using System.Net;
public static async Task<HttpResponseMessage> Run(Order req, IAsyncCollector<Order> outputQueueItem, TraceWriter log)
{
log.Info("C# HTTP trigger function received an order.");
log.Info(req.ToString());
log.Info("Submitting to processing queue.");
if (req.orderId == null)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
else
{
await outputQueueItem.AddAsync(req);
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
You mentioned that your example code had a problem with your IAsyncCollector parameter. As mentioned by others, it looks like the problem is you're missing your [Queue(..)] attribute.
That documentation which you are referring might be old.
Here is why out is needed.
I want to pass set of inputs to function, (Multiple Triggers) and set of outputs from a function (Send data to Queue, Output Reference of completion)
We need an indication what needs to be passed and what needs to be sent out of the function.
function(Class1 i, Class2 j, out Class3 k, out Class4 l) {
}
out refers to the reference of the object that is sending out of function and does not need deserialization of the object during the call.
while i and j in the above needs deserialization, while Class3 and Class4 are not.
There need to be extra cycle need to determine the mapping and auto recognize whether it is in or out parameters.
Having an 'out' make the process simple and helps to execute the code quicker.
I believe you are rather missing an attribute to denote the type of your output binding. For instance, if you want to use a Storage Queue, declare your function as
[FunctionName("DoStuff")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
TraceWriter log,
[Queue("my-out-queue")] IAsyncCollector<DetailInfo> outputQueue)
{
}

Resources