Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support binding query parameters in HttpTriggers (C#) #7610

Open
Sti2nd opened this issue Jun 24, 2021 · 11 comments
Open

Support binding query parameters in HttpTriggers (C#) #7610

Sti2nd opened this issue Jun 24, 2021 · 11 comments
Assignees

Comments

@Sti2nd
Copy link

Sti2nd commented Jun 24, 2021

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.

@Sti2nd Sti2nd changed the title Support binding query parameters Support binding query parameters in HttpTrigger Jun 24, 2021
@v-anvari v-anvari self-assigned this Jul 5, 2021
@v-anvari
Copy link

v-anvari commented Jul 5, 2021

Hi @Sti2nd , Thank you for your feedback! We will check for the possibilities internally and update you with the findings.

@v-anvari
Copy link

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

@Sti2nd
Copy link
Author

Sti2nd commented Jul 27, 2021

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.

@Sti2nd Sti2nd changed the title Support binding query parameters in HttpTrigger Support binding query parameters from HttpTrigger attribute (C#) Jul 27, 2021
@Sti2nd Sti2nd changed the title Support binding query parameters from HttpTrigger attribute (C#) Support binding query parameters in HttpTriggers (C#) Jul 27, 2021
@v-anvari
Copy link

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

@Sti2nd
Copy link
Author

Sti2nd commented Jul 28, 2021

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

@v-anvari
Copy link

Thank you for your feedback! We will investigate this further and update as appropriate

@v-bbalaiagar
Copy link

Hi @Sti2nd, Transferring this issue to function host for further investigation.

@v-bbalaiagar v-bbalaiagar transferred this issue from Azure/Azure-Functions Aug 12, 2021
@ghost ghost assigned brettsam Aug 12, 2021
@TobiasBreuer
Copy link

TobiasBreuer commented Feb 5, 2022

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

@MO2k4
Copy link

MO2k4 commented Jul 15, 2022

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? :-)

@TobiasBreuer
Copy link

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 😉

@MO2k4
Copy link

MO2k4 commented Jul 15, 2022

I've opened in pr for this 😅 PR 787

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants