Serverless with Azure Functions
I set out to learn about Azure Functions and this is the knowledge I have gathered so far.
To have something to work with, I decided to migrate the ASP.NET Core Web API for “My latest online activities” to Azure Functions.
As background, refer to these related blog posts:
- Getting started with React
- Continuous Delivery with Visual Studio Team Services
- Introducing CommandQuery
To get some basic understanding, read the introduction over at Microsoft Docs:
You can create your functions in the browser on the Azure Portal, but I find it to be a bit cumbersome. My approach is to use the Azure Functions CLI tool to scaffold a project, put it on GitHub and deploy to Azure Functions with continuous deployment.
Azure Functions CLI
Command line tool for Azure Function
The Azure Functions CLI provides a local development experience for creating, developing, testing, running, and debugging Azure Functions.
Read the docs at:
Install:
npm i -g azure-functions-cli
Install globally
Create Function App:
func init
Create a new Function App in the current folder. Initializes git repo.
Create Function:
func function create
Create a new Function from a template, using the Yeoman generator
Run:
func host start
Launches the functions runtime host
So that is what I did when I created the latest-functions
project. I’ll come back to that later.
First let’s talk about my CommandQuery
package.
CommandQuery
Command Query Separation (CQS) for ASP.NET Core and Azure Functions
CommandQuery now has support for both #AspNetCore and #AzureFunctionshttps://t.co/qd8QHljnfx#CQS
— Henrik Lau Eriksson (@hlaueriksson) April 30, 2017
Remember the background:
To migrate the ASP.NET Core Web API project to a Azure Functions app, I first needed to extend the CommandQuery
solution.
As a result I ended up with three packages on NuGet:
CommandQuery
- Common base functionality
CommandQuery.AspNetCore
- Command Query Separation for ASP.NET Core
CommandQuery.AzureFunctions
- Command Query Separation for Azure Functions
In this blog post I will cover the CommandQuery.AzureFunctions
package:
Provides generic function support for commands and queries with HTTPTriggers
To get more information about the project, read the documentation over at the GitHub repository.
Get started:
Sample code:
When I was writing the code specific to Azure Functions, I needed to add dependencies. It makes sense to depend on the same assembly versions as the Azure Functions hosting environment use. Therefore, I ended up creating a project to gather that information.
AzureFunctionsInfo
⚡️ Information gathered on Azure Functions by executing Azure Functions ⚡️
I created a project to get information about available Assemblies and Types in #AzureFunctionshttps://t.co/L9aSd7NZ2h@AzureFunctions
— Henrik Lau Eriksson (@hlaueriksson) April 30, 2017
I basically wanted to get information about available Assemblies
and Types
in the Azure Functions hosting environment.
The code and all the information gathered can be viewed at:
For example, this is some important information I found out:
"Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed"
"System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
The type TraceWriter
comes from:
latest-functions
Okay, so now it is time to cover the actual Azure Functions app I created. The code was migrated from an existing ASP.NET Core Web API project.
Remember the background:
The app has one query function to get data on my latest:
- Blog post
- GitHub repo and commit
- Instagram photo
The source code is available at:
The project was created with the Azure Functions CLI tool:
- Language:
C#
- Template:
HttpTrigger
- Name:
Query
After the scaffolding, the generated code needed to be modified.
This is the end result:
function.json
Defines the function bindings and other configuration settings
- authLevel set to
anonymous
- No API key is required
- route
query/{queryName}
added- How to customize the route: Customizing the HTTP endpoint
- method
post
added- Array of the HTTP methods to which the function will respond
project.json
To use NuGet packages in a C# function, upload a project.json file to the function’s folder in the function app’s file system.
- Only the .NET Framework 4.6 is supported, specify
net46
CommandQuery.AzureFunctions
, version0.2.0
- This will make the use of queries and query handlers possible in the function
bin
folder
If you need to reference a private assembly, you can upload the assembly file into a
bin
folder relative to your function and reference it by using the file name (e.g.#r "MyAssembly.dll"
).
- The queries and query handlers used in this function are located in
Latest.dll
- Code: Latest
Make sure that private assemblies are built with <TargetFramework>net46</TargetFramework>
.
run.csx
This is the code for the actual function. Written in scriptcs, you can enjoy a relaxed C# scripting syntax.
- The
#r "Latest.dll"
directive reference the query assembly from thebin
folder - Import the namespaces
System.Reflection
andCommandQuery.AzureFunctions
- Create a static instance of
QueryFunction
and inject aQueryProcessor
with the queryAssembly
. This will make IoC container find the correct query handlers for the queries. - Add the
string queryName
argument to the function signature so the correspondingroute
will work - Let the
QueryFunction
handle the query and return the result
When the code is done, only four things remains to get it running in the cloud:
- Push to GitHub, Bitbucket or Visual Studio Team Services
- Log in to the Azure portal
- Create a function app
- Set up continuous deployment
The end result of all this can be viewed at:
The code for the SPA that uses the function:
Testing
While building your functions, you want to test early and often.
Run the functions locally with the command:
func host start
If you need to specific CORS origins use something like:
func host start --cors http://localhost:3000
When the functions are running locally you can manually test them with tools like Postman or curl.
Advice from Microsoft:
Postman
The Postman collection for this function:
- latest-functions.postman_collection.json
- With both local and cloud endpoints
curl
Commands for this function hitting the cloud endpoints:
curl -X POST http://latest-functions.azurewebsites.net/api/query/BlogQuery -H "content-type: application/json" -d "{}"
curl -X POST http://latest-functions.azurewebsites.net/api/query/GitHubQuery -H "content-type: application/json" -d "{'Username': 'hlaueriksson'}"
curl -X POST http://latest-functions.azurewebsites.net/api/query/InstagramQuery -H "content-type: application/json" -d "{}"
Resources
Other people are testing the functions with code:
- Testing Azure Functions in Emulated Environment with ScriptCs
- Testing Precompiled Azure Functions
- Building, testing and deploying precompiled Azure Functions
If you are using CommandQuery
together with Azure Functions you can unit test your command and query handlers.
For example like this:
(Yeah, I know! Not really unit testing, but you get the point)