Is Attribute Routing possible in Azure Functions - azure

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

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

403 (Forbidden) while calling one azure function from another

I need to call an azure function; fn(b), from another azure function; fn(a).
fn(a) -> fn(b)
Both these functions are in same function app. The problem is whenever I try to call (b), I get 403-Forbidden "data at the root level is invalid".
Is it possible to call an azure function from another azure function within same function app?
Function 1
public static class Function1
{
[FunctionName("Function1")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
HttpRequestMessage req, TraceWriter log)
{
log.Info("---- C# HTTP trigger function 1 processed a request.");
UploadToF2(log);
return null;
}
private static IRestResponse UploadToF2(TraceWriter log)
{
SomeObject payload = new SomeObject();
payload.One = "One";
payload.Two = 2;
payload.Three = false;
payload.Four = 4.4;
var Fn2Url = Convert.ToString(ConfigurationManager.AppSettings["F2Url"]);
log.Info("Hitting F2 at " + Fn2Url);
var method = Method.POST;
var client = new RestClient(Fn2Url);
var body = JsonConvert.SerializeObject(payload);
var request = new RestRequest(method);
request.RequestFormat = DataFormat.Json;
request.AddHeader("Content-Type", "application/json");
request.AddBody(payload); // uses JsonSerializer
IRestResponse response = client.Execute(request);
return response;
}
}
class SomeObject
{
public string One { get; set; }
public int Two { get; set; }
public bool Three { get; set; }
public double Four { get; set; }
}
Function 2
public static class Function2
{
[FunctionName("Function2")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("---- C# HTTP trigger function 2 processed a request.");
string payload = await req.Content.ReadAsStringAsync();
log.Info("payload == "+payload);
return null;
}
}
Additional Information:
F2Url is a fully qualified url coming from config.
I tried running both functions in localhost. It works. I.e. fn(a) can call fn(b) in localhost. However when I host both of them in Azure, fn(b) is not callable from fn(a).
I tried a hybrid test too. I.e. I kept one function in local and another one in Azure. It works this way too. I.e. I kept fn(a) in local and fn(b) in Azure, fn(b) is callable.
I tried calling fn(b) directly from Postman and again it works.
authLevel is anonymous for both functions
I have IP restrictions (Platform features > Networking > IP restrictions) applied to the Function app. When I remove IP restrictions, Function1 is able to call Function2. However keeping IP restrictions, the call is not allowed.
The only condition when fn(a) cannot call fn(b) is when both these functions are hosted in Azure.
403 (Forbidden) while calling one azure function from another
If don't add the client Ip in the IP restrictions, then you test it in you client will get 403 error. Not only call on azure function from another ,but also all functions are restricted if you don't add the client IP in the IP restrictions.
In your case, you need to add your test client Ip in the IP restrictions, then it will work.
Update:
Add the test result.
Works locally through a GET to Function1 when using:
var Fn2Url = "http://localhost:7071/api/Function2";
What value are you using in your configuration?
Call Function #2 by its full URL, since there's a front end layer that gets hit first before the request makes it to your function app. This is true even for functions calling each other within the same function app.
GET https://{func-app-name}.azurewebsites.net/api/function2
If the authLevel is not anonymous in function.json, pass in the API key as ?code= —
https://{func-app-name}.azurewebsites.net/api/function2?code={API-key}
or as a header —
GET https://{func-app-name}.azurewebsites.net/api/function2
x-functions-key: {API-key}
When running locally (Visual Studio/func host start), the value of authLevel is ignored. Looking at your decorator, AuthorizationLevel.Anonymous is present so most probably that's not it.
More on authorization keys here.
On top of that, you could do better that returning null in Function #2: 200 OK, 202 Accepted, 204 No Content, all valid choices depending on what's supposed to happen next (async/sync processing).

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.

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