Before you begin, confirm that you have Visual Studio 2017 version 15.4 installed; if not, download and install it. To do so, perform the following steps:
- Open the Visual Studio Installer, which will show you the version of Visual Studio that you have installed and allow you to select the Azure Workflow and install it, if it is missing, then update Visual Studio, if required, to latest version:
- Click on Modify, select the Azure development workload, and click on Modify again:
Refer to the complete code placed at Code/Serverless-Architectures-with-Azure/Lesson1/BeginningAzureServerlessArchitecture/BeginningAzureServerlessArchitecture.csproj.
Go to https://goo.gl/3gNQP4 to access the code.
Now, we'll create a new Azure Function as a part of our serverless architecture that listens to HTTP requests to a certain address. It will listen to HTTP requests to a certain address as its trigger. Let's begin by implementing the following steps:
- Create a new solution. The example is called BeginningAzureServerlessArchitecture, which is a logical wrapper for several functions that will get deployed to that namespace.
- Use the Visual C# | Cloud | Azure Function template. Select the Empty trigger type and leave the default options, but set storage to None. This will create a Function App, which is a logical wrapper for several functions that will get deployed and scaled together:
- You now have a solution with two files in it: host.json and local.settings.json. The local.settings.json file is used solely for local development, where it stores all of the details on connections to other Azure services.
When uploading something to a public repository, be very careful not to commit unencrypted connection settings—by default, they will be unencrypted. host.json is the only file required to configure any functions running as part of your Function App. This file can have settings that control the function timeout, security settings for every function, and a lot more.
- Now, right-click on the project and select Add New Item. Once again, choose the Azure Function template:
- On the next screen, select Http trigger with parameters and Access rights should be set to Anonymous. Right-click on your solution and select Enable NuGet Package Restore:
An important thing to remember is that this template is different from the first one you used, because it is inside the solution. Call it PostTransactions, or something similar.
- You will now have a C# file called PostTransactions.cs. It consists of a single method, Run, with an awful lot in the method signature: an attribute and an annotation. Some of this will be familiar to you if you are an experienced C# developer, and it is important to understand this signature.
Refer to the code for this example placed at Code/Serverless-Architectures-with-Azure/Lesson 1/BeginningAzureServerlessArchitecture/PostTransactionsExA.cs. Go to https://goo.gl/iCt7dG to access the code.
Configuration as code is an important modern development practice. Rather than having servers reconfigured or configured manually by developers before code is deployed to them, configuration as code dictates that all of the configuration required to deploy an application to production be included in the source code.
This allows for variable replacement by your build/release agent, as you will (understandably) want slightly different settings, depending on your environment.
Azure Functions implement this principle, with a configuration split between the host.json file for app-wide configurations and app settings, and the Run method signature for individual functions. Therefore, you can deploy an Azure Function to production with only the code that you find in the GitHub repository:
Outcome
You created an Azure Function, understood the roles the different files play, and learned about configuration as code.
The FunctionName annotation defines the name of the function within the Function App.
This can be used for triggering your function, or it can be kept separate. The first parameter is an HttpRequestMessage object with an HttpTrigger attribute. This is what varies when you choose different triggers (for example, a timer trigger will have an object with a TimerTrigger attribute).
This attribute has several arguments. The first is the authorization level. Do you remember setting this when you created the function? It was called Access rights in the template. This defines the level of authorization that the function will demand of HTTP requests. The five levels are shown in the following table:
Authorization level
|
Required information
|
Anonymous
|
No key required; anyone with the path can call it an unlimited number of times.
|
User
|
Need a valid token, generated by a user that has AD permission to trigger the Function App. Useful for high-security environments, where each service needs to manage its own security. Generally, token-based authentication is much more desirable than key-based.
|
Function
|
Need the function key—a unique key created for each function in a Function App upon deployment. Any host key will also work. The most common form of authorization for basic deployments.
|
System
|
Need the master key—a key at the Function App level (called a host key) that cannot be deleted, but can be renewed.
|
Admin
|
Need any host key.
|
One thing to bear in mind is that if you set a function to be high security and use System or Admin authorization, then any client that you give that key to will also be able to access any other functions in the Function App (if they can work out the path). Make sure that you separate high-security functions into different apps. An improved approach is discussed in the next chapter—using Azure Active Directory.
The next parameters are GET and POST, which define the HTTP verbs that will activate the function. Generally, from a microservices architecture point of view, you should only have one verb, to prevent you from having to do bug-prone switching logic inside of the function. You can simply create four separate functions if you want GET, POST, PUT, and DELETE on an artifact.
Finally, there is a string assigned to the property route. This is the only bit of routing logic that the function itself can see, and it simply defies the subpath from the Function App. It accepts WebAPI syntax, which you can see in the curly braces, / {name}. This will assign any text that appears where the curly braces are to a parameter called name.
This completes the HttpTrigger object. Other types of triggers, which we will touch on later, have different objects and different constructors. The three parameters left in the method signature are an HttpRequestMessage object, which allows you to access the HttpRequestMessage that triggered the function; a string parameter called name, which is what the string in the curly braces in the path will get bound to; and a TraceWriter for logging.
The current logic of the Function App can be seen in the following example, and you should see that it will take whatever name is put into it and send back an HTTP response saying Hello to that name. We will test this out in the next subtopic.