azure-functions-host
azure-functions-host copied to clipboard
Support binding query parameters in HttpTriggers (C#)
The HttpTrigger already supports binding route parameters to variables in C# and it would be nice if it supported binding query parameters as well.
Related info: ASP.NET Core supports binding query parameters using the FromQuery attribute
UserVoice link. Probably isn't needed since Microsoft will stop using UserVoice.
Hi @Sti2nd , Thank you for your feedback! We will check for the possibilities internally and update you with the findings.
Hi @Sti2nd , To use query parameter, if the query is coming from a query string then you can use query.id instead of id. Where id is the query string name.
{ "type": "table", "direction": "in", "name": "product", "partitionKey": "products", "tableName": "products", "rowKey": "{id}" }
Sorry, I don't understand where this JSON is coming from? Developing Azure Functions in Visual Studio there are no JSON. I want to specify that this feature request is about having the abilitiy to bind query parameters to variables in the C# programming language 😊 I updated the title and my first post slightly.
Hi @Sti2nd , Here is how you can Add bindings to Azure Functions in visual studio - https://docs.microsoft.com/en-us/azure/azure-functions/functions-develop-vs#add-bindings
Here is how you can add the bindings in C# language - https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-example#c-script-example
As of today, Query parameters can be passed using Query.id
Here is one more example - https://docs.microsoft.com/en-us/azure/azure-functions/functions-add-output-binding-storage-queue-vs
Thank you @v-anvari ,
Unfortunately, I don't have the knowledge nor time to implement this change in Azure Functions. I kindly ask someone else (Microsoft) to do it.
This feature request is about Microsoft to implement output binding of query parameters in HttpTriggers from C# as it already does for route parameters and request body (payload). More generally this feature request is about making it just as easy to retrieve query parameters as route parameters. It is already relatively easy with HttpRequest.Query["key"], I just figured something like the following would be nice to have as well:
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "users/{id}")] HttpRequest req,
string id,
[FromQuery] string name)
{
Notice the [FromQuery] attribute instead of doing req.Query["name"] later
Thank you for your feedback! We will investigate this further and update as appropriate
Hi @Sti2nd, Transferring this issue to function host for further investigation.
Not sure if following information is helpful to @Sti2nd but for anyone reaching here due to a "Binding not supported" exception when using [FromQuery] in Azure functions triggered by HTTP:
Being used to that syntax from ASP.Net Web APIs, my expectation was that this is by default supported by Azure Functions as well (HTTP-Trigger based functions).
First approach using this attribute on a parameter of my function leads to an exception during startup of the function stating something like:
Cannot bind parameter 'foo' to type Foo. Make sure the parameter Type is supported by the binding.
After some googling, I was about to loose all hope because all references (at least those that I found) state that it is either not possible or they simply expect you to either use route configuration or fetch the query parameter from the request object or instead of using GET use a POST request and pass what you want to be passed as part of the request body...
Since all of that was not really satisfying, I was about to implement my own custom BindingProvider for the POCO objects I wanted to use in my GET requests to the function...
Then I had a closer look at the source of azure-webjobs-sdk-extensions and found this: HttpDirectRequestBindingProvider
From the comment on that class:
// support allowing binding any non-attributed HttpRequest parameter to the incoming http request.
// Foo([HttpTrigger] Poco x, HttpRequest y);
~~❗ Please note, that order is really important here ❗~~
The following signature is approved to work (.Net 6.0 /Azure Functions v4 - did not test former versions) - ~~but the Poco object (in my case the PaginationFilter has to be the first parameter of the function! Moving it to some other location (e.g. between principal and cancellatioToken, will raise the original binding exception again)~~:
Order of course matters only in that sense, that your Poco object needs to be decorated with the [HttpTrigger] attribute, so as long as this relation is given, you can also put both at the end of your parameter list.
public async Task<IActionResult> Foo([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
PaginationFilter paginationFilter, HttpRequest req, ClaimsPrincipal principal, CancellationToken cancellationToken)
And the paginationFilter is properly filled with provided (or default values) values when calling the endpoint like
http://localhost:7071/api/Foo?Limit=50&Page=1
or
http://localhost:7071/api/Foo?Limit=50
or
http://localhost:7071/api/Foo?Page=1
or
http://localhost:7071/api/Foo
Note: The usage of FromQuery attribute is optional. You can put it (it will do no harm but maybe adds some clarification for the reader of your code) or you can leave it out. The functionality is not affected by that.
Also see my answer to a related issue on StackOverflow
Thanks @TobiasBreuer, thats a great example on how data passed to the functions should be handled. I am trying to wrap a different query parameter name like value_id to ValueId, but i can't seem to get it working. I tried [FromQuery(Name = "value_id")] and also DataMember, but nothing seems to work.
Do you have a solution for this too? :-)
Hi @MO2k4, when given as QueryString parameter, for GET requests I don't know of any build-in functionality to perform such a mapping when the names differ.
Depending on the type of request your are performing I see two options:
In case it is a GET, you'll have to either use the Route parameter or access the query parameter the classic way like req.Query["value_id"]
In case it is a POST, and ValudId is a property of your DTO object, please note that the runtime is using JSON as serialization mechanism, so you can attribute your DTO property accordingly:
// POCO Object:
public class ValueDto
{
[JsonProperty("value_id")]
public Int32 ValueId { get; set; }
public String Value { get; set; }
}
// Function definition:
[FunctionName(nameof(TestDto))]
public static IActionResult TestDto(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] ValueDto valueDto, HttpRequest req, ILogger log)
{
log.LogInformation($"ID: {valueDto.ValueId}");
log.LogInformation($"Value: {valueDto.Value}");
return new OkObjectResult("Thanks for flying with Azure Functions ;-)");
}
// POST Request Body:
{
"value_id": 42,
"value": "Hello World!"
}
// The output will then be
[2022-07-15T08:18:07.341Z] ID: 42
[2022-07-15T08:18:07.342Z] Value: Hello World!
[2022-07-15T08:18:07.360Z] Executed 'TestDto' (Succeeded, Id=92127abd-cfcf-4523-9193-3d1ec6d60716, Duration=74ms)
Hope this helps 😉
I've opened in pr for this 😅 PR 787