Hosting Angular Apps on Azure Storage with an Azure Functions Back-end

Recently I blogged hosting a Blazor App on Azure Storage. In the same way, any SPA application can be hosted on Azure Storage. Here, I’m showing hosting an Angular App. With Azure Storage, static website hosting can be used to host SPA applications. Hosting websites with Azure Storage is a cheap way for static website hosting. In the back-end, Azure Functions can be used – which offers a consumption based cost model.

Cloud Storage

Prepare Azure storage

First, let’s create a new Azure Storage account. After logging into the Microsoft Azure portal, you can create an Azure Storage account. To use static website hosting, the account needs to be a StorageV2 account.

Create Azure Storage

After creating this Azure Storage account, you can configure it to enable static websites. You can find this configuration in the Settings tab – select Static website, and click the button Enabled, and add an entry point for the application, e.g Index.html:

Configure Static Website

With the feature Static website enabled, you can see the the primary endpoint that can be used to access the website as soon as the needed files are deployed. A container named $web is created – you need to upload the files needed by the website into this container.

Primary Endpoint

Create a Angular project

I’m using the command line to create an Angular project. You can install the Angular CLI using

npm install -g @angular/cli

In case you do not have npm installed, get npm.

A new Angular project (without any ASP.NET Core backend) can be created with

ng new angularsample

This command creates a project structure and downloads a bunch of files from the NPM server.

After changing to the newly created directory

cd angularsample

you can start the test server coming with the packages with

ng serve --open

The --open argument starts the default browser, so the Angular app is opened. The serve command is specified in the file project.json to start the test-server locally.

Deployment of the Angular Project

To create the files for deployment, the build command can be used. An optimized build for production is created with the --prod flag. The flag --build-optimizer reduces the bundle sizes for the JavaScript and CSS files.

ng build --prod --build-optimizer

This build creates the dist folder that can be used to deploy the containing files.

To upload files to Azure Storage, multiple options exist, but with most options one by one file needs to be uploaded to the storage account. To upload multiple files at once, you can use Visual Studio Code. The extension Azure Storage allows to manage your Azure Storage Accounts, and to upload files to deploy the files for a static website. Be sure to select a subfolder in the dist directory containing the Index.html file as well as the JavaScript and CSS files.

After installing the extension Azure Storage vor Visual Studio Code, click on the Azure icon on the left, and then the upload button to upload the files. Because in the portal Azure Storage has been configured to enable static websites, the container named $web is created in the Azure Storage account. This is the container where the upload goes to.

The extension Azure Storage for Visual Studio Code s currently in preview. I’m using version 0.4. To enable the multi-file upload to static websites, you need to define the user setting “azureStorage.preview.staticWebsites”: true.

Upload files using Visual Studio Code

After deploying completes, you can access the Angular app using the link from the Azure Portal.

Angular App running in Azure Storage

Using Azure Functions

The Angular app is running. However, we don’t want to stop at this point. SPA applications without some functionality in the back-end are not that useful.

Using services hosted in Azure App Services is not really useful when saving money by hosting the Angular app with Azure Storage. In case you already use Azure App Services, you can also host the Angular website with the same hosting plan. Saving money using Azure Storage, you can also save money with the back-end services by not to reserving CPU and memory, but using a consumption plan instead, e.g. with Azure Functions.

Create Functions App using Azure Portal

With Function Apps you can choose between a Consumption Plan and an App Service Plan. Depending on the number of requests and the data you download, one or the other plan is the better option to use. If you don’t have continuous load on your service, the Consumption Plan can be the cheaper one. In case you already run an App Service Plan that is not fully busy, you can use it host your Functions there as well. With Azure Functions, you don’t need to change your API if the load changes, you can easily switch the Hosting Plan.

Using Visual Studio 2017, you can use a project template to create Azure Functions. With Azure Functions v2, a .NET Standard Library is created.

Azure Functions offer different ways to activate them. Calling it from the Angular app, an HTTP Trigger can be used to activate the Function App. With HTTP triggers, a Storage Account is not needed. I’m selecting access rights anonymous to allow anonymous users to access to the list of books returned from the function app.

Create Azure Functions with HTTP Trigger


public class Book
{
public Book() { }
public Book(int bookId, string title, string publisher)
=> (BookId, Title, Publisher) = (bookId, title, publisher);
public int BookId { get; set; }
public string Title { get; set; }
public string Publisher { get; set; }
public override string ToString() => Title;
}

view raw

Book.cs

hosted with ❤ by GitHub

The implementation of the Azure function returns a list of Book objects:


public static class BooksFunction
{
[FunctionName("BooksFunction")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequest req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
return new OkObjectResult(GetBooks());
}
public static IEnumerable<Book> GetBooks()
=> new List<Book>
{
new Book(1, "Enterprise Services with the .NET Framework", "Addison Wesley"),
new Book(2, "Professional C# 6 and .NET Core 1.0", "Wrox Press"),
new Book(3, "Professional C# 7 and .NET Core 2.0", "Wrox Press")
};
}

Configuring CORS with Azure Functions

What needs to be done with the Azure Function to enable it to be invoked from Angular is to configure CORS. You can configure CORS from the Azure Portal selecting the name of the Function App, and selecting the tab Platform features. From there, the API configuration CORS is available. You need to enter the URL used by the Angular app to allow the Angular app accessing the Azure Function.

Configure CORS

Call Azure Functions from Angular

To invoke the Azure Function from Angular, the Angular app is extended, and a component created to invoke the API service. You can create Angular components with the Angular CLI:

ng generate component books

With the BooksComponent component, the HttpClient component is injected in the constructor of the BooksComponent class. The BASE_URL is retrieved via dependency injection as well. When the result is received, it is written to the public Book[] named books. Using the TypeScript definition for an interface, the Book type is defined with members with the same property names as the JSON format is created from the Azure Function.


import { Component, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-books',
templateUrl: './books.component.html',
styleUrls: ['./books.component.css']
})
export class BooksComponent {
public books: Book[];
constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
http.get<Book[]>(baseUrl + 'api/BooksFunction').subscribe(result => {
this.books = result;
console.log("retrieved" + this.books);
console.log("title: " + this.books[0].title);
}, error => console.error(error));
}
}
interface Book {
bookId: number;
title: string;
publisher: string;
}

The user interface accesses the public member books, and shows its members in an HTML table using Angular data binding.


<h1>Books</h1>
<p *ngIf="!books"><em>Loading…</em></p>
<table class='table' *ngIf="books">
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Publisher</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let book of books">
<td>{{ book.bookId }}</td>
<td>{{ book.title }}</td>
<td>{{ book.publisher }}</td>
</tr>
</tbody>
</table>

Publishing and running the application, you can see the books returned from the Azure Function with the Angular app hosted in Azure Storage.

Summary

Why using Azure Storage instead of Azure App Services with static web content? It’s just a lot cheaper using Azure Storage instead of an App Service, and it scales big. With the backend, Azure Functions can be used – also offering a cheap variant compared to App Services, and this variant offers big scaling.

Static website hosting with Azure Storage is currently in preview – but it looks very promising.

More Information

Read chapter 32, Web API of my new book Professional C# 7 and .NET Core 2.0 on how to share code between an ASP.NET Core Web API project and an Azure Function app.

In another blog post I’ve shown the same Azure features with ASP.NET Core Blazor in the frontend: Hosting Blazor Apps on Azure Storage

Static website hosting in Azure Storage

Get the complete sample in the Azure folder from More Samples!

Enjoy programming and learning,
Christian

Advertisement

4 thoughts on “Hosting Angular Apps on Azure Storage with an Azure Functions Back-end

Leave a Reply to Jaroslav Jindřich (@jjindrich_cz) Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.