CloudWhile working with a Fortune 500 retail company a few months ago, my team needed to implement serverless architecture for a considerably large process, in terms of memory and CPU utilization. We made the decision to implement the process using PUB/SUB pattern with Azure service bus and functions. I will not get too much into the technical details of the architecture, but a good example for the pattern is basically creating applications that use service bus topics and subscriptions.

To move into the functions part of our work, at that time there wasn't a good pattern available for debugging and writing unit tests. We'd have to deploy the function resource into Azure every time and hope that it works.

Fast forward couple of months, I was at another client location where there was a need for work up with several hundred functions. This time we needed an efficient way to debug the functions. I was glad to know that it is possible to do it now using 'Azure precompiled functions' in combination with Azure-CLI and/or node.

Note: Things are about to get technical, so if you need a cursory read on what Azure functions are and how we can benefit from using them, an introduction to Azure functions on the official Microsoft document is a good starting point before proceeding further.

What are Azure precompiled functions?

Azure precompiled functions enable the use of .Net assemblies containing the function implementation. Visual Studio released a template to create a function app, but due to its dynamic nature debugging was a bit difficult. This post helps summarize the following aspects by setting up an example function which responds to webhooks (httpTriggers).

Setup / Project Structure

  1. Install Node by using one of the installers from Node.js download page.
  2. Install the azure-functions-cli module. I prefer to install all my reusable modules globally
npm i -g azure-functions-cli 
  1. Open Visual Studio and create a new class library project (This is just to get statrted with a simple structure)
  2. Name the project as AzurePrecompiledFunctions
  3. Create a new folder and name it fnHttpTrigger
  4. Under the folder add a function.json file and add the code below
{
	"scriptFile": ".\\bin\\AzurePrecompiledFunctions.dll",
	"entryPoint": "AzurePrecompiledFunctions.FnHttpTrigger.Run",
	"bindings": [
	 {
		"autheLevel": "function",
		"name": "req",
		"type": "httpTrigger",
		"direction": "in",
		"route": "GetName"
	 },
	 {
		"name": "$return",
		"type": "http",
		"direction": "out"
	 }
	],

	"disabled": "false"

}
  1. Add a new class and add the code below, a sample trigger code which responds to http requests when invoked in the right way. Install the following dependencies, needed via nuget Microsoft.AspNet.WebApi
public class CapTech {
public static async Task Run(HttpRequestMessage req) {
	string name = req.GetQueryNameValuePairs()
		.FirstOrDefault(q=> string.Compare(q.Key, "name", true) == 0);
	Dynamic data = await req.Content.ReadAsAsync();
	name = name ?? data?.name;

	return name = null
		? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass the query"
		: req.CreateResponse(HttpStatusode.OK, "Hello " + name);
}
}
  1. Within function.json file, notice the scriptFile and entryPoint attributes. Set themto below
    1. scriptFile: "..\\bin\\AzurePrecompiledFunctions.dll" (Output of the project)
    2. entryPoint: "AzurePrecompiledFunctions.FnHttpTrigger.Run" (Fully qualified name space to the actual function method name)
  2. The binding section from the json is where you configure both bindings and triggers. Following is a brief description of what each of configuration line means
    1. authLevel This determines if any keys need to be present on the request in order to invoke the function
    2. name: The name that is used for the bound data. This is usually an argument name
    3. type Binding type. Eg: httpTrigger
    4. direction'in', 'out'. Indicates whether the function is receiving data or sending the data
    5. route This defines a route template controlling to URL's, a function will respond
    6. disable Set this to enable or disable the function
  3. Add host.json file which should be on the root of the project. This is a metadata file that contains global configuration options affecting all the functions within the project. Suppose you have multiple (or single function) you can set up global configuration for functions like setting the function timeout, configure settings for http triggers etc. This file can be empty for our setup

Debug

  1. Build the project > open command prompt > navigate to root of the project and type func host start.
  2. The function app should now be running on port 7071. The following is what you should be seeing, if the steps are followed accurately

functiontrigger

  1. To verify this, open a rest client, postman and perform a GET operation against the Http Function fnHttpTrigger uri, http://localhost:7071/api/GetName

postman-response

Alternatively, you can change the project settings to launch azure-functions-cli when you hit F5, instead of launching IIS Express. Select the start external program and set the path to: c:\Users\User_Name\AppData\Roaming\npm\node_modules\azure-functions-cli\bin\func.exe and set the command line arguments.

commandline

When you run the application, the function application is hosted and you can set breakpoint wherever needed.

vs

Summary

Using Azure precompiled functions is great alternative to the existing Visual Studio templating structure to create a function app. Also, it provides an important way to debug the function locally, without having to worry too much about the dynamic nature. This also provides the ability to change the function code and deploy as needed to support a continuous integration and continuous deployment pattern (CI/CD). This is the approach we are confident about, for the product which we are building as of this writing. You can download the source code for this post on github: Creating and Debugging Azure Precompiled Functions.

Next Up

Since we have now discussed an approach to write and debug functions locally, in the next post I will enhance this foundation to configure the azure service bus bindings, discuss deployment options, and verify the function is up and running as intended.