Welcome to todays post.
In today’s post I will be discussing and showing how to create an Azure Serverless Function.
I will also be showing how to add Function security to the serverless function.
The implementation will initially be within a local development environment, which will allow you to develop and test the function and ensure it can run before migrating it to Azure. I will explain migration to Azure in the next post.
Also, before you can develop and test the Azure functions locally, you should install and enable the Azure Storage Emulator, which is allows your locally hosted Azure functions to access storage. More details on how to obtain, install and setup the Azure Storage Emulator within your local development environment are in one of my posts. There is also additional documentation on the storage emulator in the Microsoft Azure site.
I will first show how to create an Azure Serverless Function in Visual Studio in the first section. I will also how to setup the storage account and resource groups that are required for the serverless function storage in Azure.
Creating an Azure Serverless Function in Visual Studio
Creating a serverless Azure function can be done using two different publishing tools:
- Visual Studio Code
- Visual Studio
I will show how to create then publish an Azure serverless function using Visual Studio.
To start off, we first create a new project.
In the New Project dialog that opens, select the Azure Functions template as shown from the Cloud template category:
Click Ok.
In the next screen under the panel Azure Functions v2 (.NET Core), select HttpTrigger.
You will see the drop-down list parameters Storage Account and Access Rights appear:
Browse the selections within the Storage Account drop-down list.
There are options:
None
Storage Emulator
Browse..
The last option means that you can select from an existing storage account in Azure.
Select the Browse.. option.
The Storage Account dialog that opens will show the following parameters:
Subscription
View
Search
Selecting the Search allows you to search for an existing Azure resource group. Alternatively, you can create a new resource group with the New… option as shown below:
I already have an existing resource group, so I select it as shown below:
The next parameter is the Access rights. There are three options:
Function
Anonymous
Admin Select the Function access rights:
Note: Even if you selected the Anonymous security option to test in the local environment, once you deploy your serverless function to Azure, the authentication will be enforced.
After the project is created, the following skeleton code is generated:
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;
namespace BookLoanOverdueFunctionApp
{
public static class Function1
{
[FunctionName("Function1")]
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = new StreamReader(req.Body).ReadToEnd();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
}
In the next section, I will show how to call the serverless function, and use call routing for more advanced parametrization.
Making Requests to the Serverless Function
In this section, I will show how to call your Azure serverless function and execute calls with additional parameters.
By default, the route to call the function is of the form:
http://<app name >.azurewebsites.net/api/<function name>
If we wish to add extra routing or a parameter to allow more complexity on the function, we can use routing. This is done by creating a route within the binding for the http trigger definition by replacing the Route attribute within the HttpTrigger binding with a route definition for the HttpRequest parameter from:
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req
to:
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "Loan/{id?}")]HttpRequest req
With the parameter routing change, the resulting function looks like:
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;
namespace BookLoanOverdueFunctionApp
{
public static class OverdueBookFunction
{
[FunctionName("OverdueBookFunction")]
public static IActionResult Run(
[HttpTrigger(
AuthorizationLevel.Function, "get", "post",
Route = "Loan/{id?}")]HttpRequest req,
int? id,
TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
int? loanId = id ?? 0;
return id != null
? (ActionResult)new OkObjectResult($"The Loan {id} is overdue. Processing notice for borrower.")
: new BadRequestObjectResult("Please pass in a valid Loan ID.");
}
}
}
For the above function, after applying this route, the new route will be:
http://<app_name>.azurewebsites.net/api/Loan/{id}
In the next section, I will show how to modify the binding configuration for the serverless function to include the route.
Modifying Trigger Binding with Updated Function Routing
For this routing to take effect, the project must be built and the updated function.json that holds the updated trigger binding will be generated in the bin\Debug\netstandard2.0\[function]\ folder.
Then function.json will then be updated with the following binding configuration:
{
"generatedBy": "Microsoft.NET.Sdk.Functions-1.0.13",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"route": "Loan/{id?}",
"methods": [
"get",
"post"
],
"authLevel": "function",
"name": "req"
}
],
"disabled": false,
"scriptFile": "../bin/BookLoanOverdueFunctionApp.dll",
"entryPoint": "BookLoanOverdueFunctionApp.OverdueBookFunction.Run"
}
If the routing is not correctly defined and is null in the Run() parameter list and an attempt is made to use the routing during an call to the azure function, then the following error will display:
[7/01/2020 4:32:15 AM] The following 1 functions are in error:
[7/01/2020 4:32:15 AM] Run: Microsoft.Azure.WebJobs.Host: Error indexing method 'OverdueBookFunction.Run'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'id' to type Nullable`1. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
If the routing parametrization is invalid, such as being defined as “id: int?” instead of “id?” then the following error will display by the host during runtime:
[7/01/2020 6:57:31 AM] A ScriptHost error has occurred
[7/01/2020 6:57:31 AM] Microsoft.AspNetCore.Routing: An error occurred while creating the route with name 'OverdueBookFunction' and template 'api/Loan/{ id: int?}'. Microsoft.AspNetCore.Routing: The constraint entry ' id' - ' int' on the route 'api/Loan/{ id: int?}' could not be resolved by the constraint resolver of type 'DefaultInlineConstraintResolver'.
[7/01/2020 6:57:31 AM] Stopping Host
The function server local host will run under a console as shown:
The function host will listen to the port showing.
To test the function, copy the URL in green:
Paste the URL into a browser with the {id} string replaced with an integer.
After submitting, you will hit the breakpoint as shown in VS 2017 IDE:
After continuing, the following will be output to the console:
Now check the browser and the response output will show:
It’s working!
We have a working Azure serverless function.
We have seen how to create, configure, and run an Azure serverless function from our local development environment with the dependent resources within Azure.
We have also seen how to add more flexibility and complexity to our serverless function by including an additional extra routing on the function input parameters. This was done by creating a route within the binding for the http trigger definition and within the trigger binding configuration.
Our next goal will be to deploy this to Azure, which is what I will show in the next post.
That is all for today’s post.
I hope that you have found this post useful and informative.
Andrew Halil is a blogger, author and software developer with expertise of many areas in the information technology industry including full-stack web and native cloud based development, test driven development and Devops.