Vainolo's Blog

Archive for the ‘programming’ tag

Azure Functions – Part 2: Serving HTML Pages with Azure Functions

leave a comment

Previous Tutorial: Azure Functions – Part 1: Getting Started

In the last tutorial we created a simple Azure Function that returned a value. I’m going to improve on that project and return an HTML page from the function. As this turned out to be a lot simpler that I though, I’m spicing this up by adding not only one way but three different ways to return a web page – first, a static hard-coded page; second, a page that is stored as part of the Azure Function code; and third, a page that is stored in an Azure storage blob.

We’ll start with a simple C# Azure Function with no authentication as we did last time. I’ll call it “HelloWorldHTML”. If you are following with me, this is what you should have on your screen:

clip_image001

Let’s start by returning a static hard-coded page. Just delete all the code in the function and replace it with the following code:

using System.Net;
using System.Net.Http.Headers;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
  log.Info("C# HTTP trigger function processed a request.");
  
  // Option 1, coded HTML
  var response = req.CreateResponse(HttpStatusCode.OK, "Hello ");
  response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
  return response;
}

As I said, very simple. There are two new things here. First, we need to declare that we are using the System.Net.Http.Headers namespace because we the MediaTypeHeaderValue class in that namespace. Second, we are adding the ContentType header to the request, which tells the browser that we are returning HTML and should renter it as such. Save the Function and click on the “Get function URL” link to get the direct URL to the function, open a new browser window and paste the function’s URL. You should see this nice HTML page in your browser window:

clip_image002

You can obviously return any HTML here, but as I’m lazy, this is what I did :-).

The second option is to create an HTML file in the function’s code and load it from there. To create a new file, click on the “View files” text on the right of the screen to open up the files that make up the function:

clip_image003

This opens a list as shown below:

clip_image004

You can add a new file or upload an existing one. I’ll click on “Add” and create a new file named “hello.html”. Your list should look like this:

clip_image005

Let’s add some simple HTML code to this file, like this:

<html>
  <head>
    <title>Hello</title>
  </head>
  <body>
    World
  </body>
</html>

Save the file, and return to the run.csx file where the function’s code resides. Comment the original code (everything below “Option 1”) and add the following code:

// Option 2, read from local file
var response = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(@"d:\home\site\wwwroot\HelloWorldHTML\hello.html", FileMode.Open);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return response;

We are reading a file from the local storage using a Stream, and setting this file as the response to the request. We still need to tell the browser that the content is HTML otherwise it may decide to interpret it as something else (like in the previous tutorial). Save the file and navigate again to the function’s URL. You should now see this nice web page:

clip_image006

Looks different from the previous right, one? This means the code works :-).

Now the third and final option. I’m not going to go into the details of how to create an Azure Storage Blob and how to upload a file to that storage, so I’ll leave that to you to investigate (typical sentence of my university professors when they needed to explain something long and tedious in class but were too lazy to do so…). I’ll just assume that you have created it, that you have a blob container named “site” where you have a file named “hello.html”, and that you know how to fetch the connection string for the Storage Account. Many assumptions, but that is how you move forwards.

Going back to the code, change the first part of the file (the imports section) as follows:

#r "Microsoft.WindowsAzure.Storage"

using System.Net;
using System.Net.Http.Headers;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;

The first line tells the Azure Function runtime that this function is referencing an external assembly (a class library) that is not part of the standard runtime. Azure Storage is one of the special assemblies that can be referenced by name without more work, but in case you need to reference other assemblies, it is also possible as explained here. We then also declare that we are using the Microsoft.WindowsAzure.Storage and Microsoft.WindowsAzure.Storage.Blob namespaces, so our code looks nicer.

Now comment all the code below “Option 2” in your Function file and add the following code:

// Option 3, read from external blob
var storageAccount = CloudStorageAccount.Parse("<your azure storage connection string>");
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("site");
var blob = container.GetBlockBlobReference("hello.html");
string text = "";
using (var memoryStream = new MemoryStream())
{
  blob.DownloadToStream(memoryStream);
  text = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
} 
var response = req.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(text);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return response; 

This code connects to the Azure Storage Account using a CloudBlobClient, fetches the Blob container called “site”, and from the container fetches the file. We download the file into a MemoryStream and make the Stream the content of the Function’s response. Now save the file and navigate again to the Function’s URL endpoint. You should see something like this:

clip_image007

Awesome, right? WordPress beware, we are right behind you :-).

Hope you enjoyed this tutorial, and hope you learned as much as I did. I have some ideas on where to go next but I’m happy to explore more things, so leave your ideas in the comments and I’ll see what I can do.

Have a great what’s left of your day 🙂

Written by vainolo

March 17th, 2018 at 7:18 pm

%d bloggers like this: