Last updated on 2018-11-10
Previous Tutorial: Azure Functions – Part 3: Handling HTTP Query GET and POST Requests
While writing code directly in the Azure portal is awesome, the next step in a real-world developer experience is to have a local environment where we code, build, and test our functions, and from there sent them the cloud. And this is just the first step. A real-world development environment will implement CI where the code is automatically built, tested and deployed, but that is a completely different tutorial 😀. But let’s get started.
The first step of this tutorial is to start working in a real development environment – an IDE, and I chose Visual Studio Code. A couple of years ago thinking that Microsoft would build a free and open source IDE was considered crazy. Fast forward to 2018 and according to Wikipedia, Visual Studio Code is considered the most popular IDE of the year. My reason for choosing this IDE is that it is free (as an MS employee I have a full enterprise visual studio, but not everyone reading this article can afford one) and I assume that since it’s developed by Microsoft it will be highly integrated with Azure. Time will tell.
Setting up VSCode for use with Azure Functions is straightforward and the tutorial provided by Microsoft is pretty good. Just follow the instructions there and you will be up and running in no time. I’ll wait… You’re back? Good, let’s continue.
We’ll start by creating a new Azure Functions project and an HTTP triggered function (this will repeat some of what was shown in the linked tutorial for the sake of completeness). This is done by clicking on the “Create New Project” button in the Azure sidebar and selecting a new empty directory to store the project:
After this we are asked the language for the Function, and I’ll choose C#:
Finally, we add the project to the workspace:
I will not get here into the details of what is a workspace and what are the other options (mainly because I’m learning this myself), so for now just follow the instructions. This process will do a bunch of things and in my case it also told me that I had some unresolved dependencies, so I let the magic do its work by clicking on the “Restore” button:
And that’s it, we have an Azure Functions project and can start adding functions. Let’s create an HTTP triggered function by clicking on the “Create Function” button in the Azure sidebar:
The folder where the function is located is the folder of the project we created in the previous step:
The function will start with an HttpTrigger template:
I’ll call the function “SavingUserInput”
Give a name to the namespace:
And define the function’s access rights as Anonymous since we don’t want to get into authentication, which is a different level of complexity:
Finally! That took quite a number of steps but we are finished. This is how your environment should look if you click on the Explorer side bar:
This is a bit more complex than what we encountered working in the Azure portal. My assumption is that this setup allows for more customization that are not available in the portal, but it comes at the price of more complexity. So we are now ready to try the function. Let’s hit F5 to start debugging the function. The terminal will spit some output and finally show the local address of the function, like this:
To test the function we Ctrl-Click on the link in the terminal to open a browser window to the function. This is what we see:
And adding a query string with the name parameter gives:
Good. Now let’s get on to the next part of this tutorial: persistent data. This is a fancy way of saying that we are data that is stored long-term, so don’t get intimidated . There are some preparations steps for this:
- Make sure tha Azure Storage emulator on your computer is up and running. The emulator is part of the Azure SDK so you should already have it, but if not, download it from here.
- Download the Azure Storage Explorer. This is a great tool to explore Azure storage services and their contents. After installing it, open the storage explorer, navigate to the “Local & Attached” -> “Storage Accounts” -> “Emulator – Default Ports (Key) -> “Tables”, and try to expand it. If you get at error this means that the emulator is not working. Leave this window open as we’ll need it later in the tutorial.
Now let’s go back to VSCode. In this example we’ll be using Azure Tables for storage. For C# Azure Functions deployed to the Azure Functions runtime 2.x (the current default AFAIK) to work with Azure Tables we need to install the Microsoft.Azure.WebJobs.Extensions.Storage in the project (as documented here). Go to the terminal inside VSCode and write:
dotnet add package Microsoft.Azure.WebJobs.Extensions.Storage
Like this:
This will install the required dependencies and add them to the current project (you can see the new dependency in the .csproj
file.
Let’s start coding! One way to store a data in Azure Tables from an Azure Function is to define a new class that will represent a row of table data, and then modify the function so that it returns an instance of this class as an output parameter. There are other ways to do it and we’ll investigate them in the future. In the same file where the function is defined, add the definition of the UserData
class:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UserData | |
{ | |
public string PartitionKey { get; set; } | |
public string RowKey { get; set; } | |
public string Text { get; set; } | |
} |
Every row in an Azure Table has a Partition Key, a Row Key, and after this whatever data you want to add (you can read move about Azure Table storage here). We have added a single field called “Text” to store the text that the user sends. Now let’s modify the Azure Function so it reads the text sent by the user and also stores it in the database:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[FunctionName("SavingUserInput")] | |
public static IActionResult Run( | |
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, | |
[Table("UserData")] out UserData ud, | |
ILogger log) | |
{ | |
log.LogInformation("C# HTTP trigger function processed a request."); | |
string text = req.Query["text"]; | |
string requestBody = new StreamReader(req.Body).ReadToEnd(); | |
dynamic data = JsonConvert.DeserializeObject(requestBody); | |
text = text ?? data?.text; | |
ud = new UserData | |
{ | |
PartitionKey = "1", | |
RowKey = DateTime.Now.Ticks.ToString(), | |
Text = text | |
}; | |
return text != null | |
? (ActionResult)new OkObjectResult($"Hello, {text}") | |
: new BadRequestObjectResult("Please pass some text on the query string or in the request body"); | |
} |
There is a new output parameter to the function of type UserData
that is mapped to an Azure Table using the Table
attribute. After this the code is pretty straightforward – the text from the request is read (either GET or POST) and the value is stored in the output parameter. Lastly, we need to define a connection to the Azure Storage account. When working locally, this is done in the local.setting.json
file. The Azure Function runtime will search for a setting named AzureWebJobsStorage
if there is no other definition, and we’ll use it this way. To get the connection string to the local Azure Storage emulator, open the Azure Storage explorer and select the Emulator node inside Storage Accounts:
The connection string to the local emulator is located in the lower left corner of the screen. Copy the connection string value and paste is as the value for AzureWebJobsStorage
. The local.settings.json
file should look like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"IsEncrypted": false, | |
"Values": { | |
"AzureWebJobsStorage": "AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;", | |
"FUNCTIONS_WORKER_RUNTIME": "dotnet" | |
} | |
} |
Press F5 to start debugging and click on the link provided in the terminal window inside VSCode:
This will open a browser window and show the expected text:
And a new table will appear in the local Azure Table storage with a new row (right-click and select refresh on the Tables node if you don’t see the UserData table).
Since there was no value for text
, it was not added to the table. We’ll modify the URL and add a query string to it, like this: http://localhost:7071/api/SavingUserInput?text=hello%20world
, and will get this:
If we peek again into our table, we can see that a new column was created for the Text
property and a new row was added with the value “Hello World”:
So there you have it. An Azure Function that persists data.
I wanted to cover how to deploy the function to Azure, but this tutorial is already pretty long so I’ll wrap things up here and we’ll do that in the next one. Until then, happy coding!
Next Tutorial: Azure Functions – Part 5: Deploying to Azure from VSCode
Be First to Comment