Speedy mobile web pages with AMP

Accelerated Mobile Pages (AMP) is a technique for making fast rendering web pages on mobile devices. It is primarily intended for static and non-interactive content, such as articles.

AMP is written in AMP HTML, which is HTML with certain restrictions and additions. For example, custom JavaScript is banned, img tags are replaced with amp-img tags and all styling must be inside the head tag.

AMP HTML is interpreted partly by the web browser and partly by AMP JS. The latter is a JavaScript library that takes care of resource loading, layout calculations and implements custom tags. For example, for the amp-img tag AMP JS will:

  1. find the amp-img tag
  2. reserve space for the image in the layout
  3. load the image asynchronously
  4. add the image to the DOM

The great thing about AMP is that it is built entirely upon HTML standards and JavaScript. Therefore, AMP works natively in any web browser.

For a practical example, take a look at this ordinary static web page.

<!DOCTYPE html>
<html>
<head>

<title>Berries</title>
<link type="text/css" rel="stylesheet" href="style.css" />

</head>
<body>

<article>
    <img alt="Blueberries" src="Blueberries.jpg" />
    <h1>Forest food</h1>
    <p>
        The word berry is used for many different kinds of small fruits...
    </p>
</article>

</body>
</html>

Then check out this AMP version of the same page.

<!doctype html>
<html amp>
<head>

<meta charset="utf-8">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<title>Accelerated berries</title>
<link rel="canonical" href="index.html" />
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<style amp-boilerplate>
    body {-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;
             -moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;
              -ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;
                  animation:-amp-start 8s steps(1,end) 0s 1 normal both}
    @-webkit-keyframes -amp-start{from{visibility:hidden}to {visibility:visible}}
       @-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}
        @-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}
         @-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}
            @keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}
</style>
<noscript><style amp-boilerplate>
    body{-webkit-animation:none;
            -moz-animation:none;
             -ms-animation:none;
                 animation:none}
</style></noscript>
<style amp-custom>
    body{font-family: arial; font-size: 14px; background: maroon;}
    article{width: 700px; margin: 50px auto; background: white; padding: 0 0 15px 0;}
    h1{font-size: 1.5em; margin: 10px 20px;}
    p{margin: 5px 20px 5px;}
</style>

</head>
<body>

<article>
    <amp-img alt="Berries" src="Blueberries.jpg" height="500" width="700"></amp-img>
    <h1>Forest food</h1>
    <p>
        The word berry is used for many different kinds of small fruits...
    </p>
</article>

</body>
</html>

Note: The code shown above will not pass AMP validation because the validator is very pedantic about whitespace in the the amp-boilerplate style. I wanted it to be readable here. The code in the linked AMP page validates properly.

Translating Angular 2 with ASP.NET MVC

Angular 2 uses templates for the html. I would like to write my templates in Razor and have them processed on the server before they get to the client side. This way I can use resource files for translations.

Note: See my other blog post ‘Translating ASP.NET MVC with resource files’ for an explanation on how to use resource files and how to set the language on the server.

The core concept

The concept is simple, on the server I create a controller which has an action for each template. And each action has the template in its corresponding View. In Angular we simply specify the URL for the action as the URL for the template.

namespace AngularApplication.Controllers
{
    public class TemplateController : Controller
    {
        public ActionResult Welcome()
        {
            return View();
        }

        public ActionResult Locale()
        {
            return View();
        }
    }
}
@using AngularApplication.Resources
<h2>@WelcomeTexts.Welcome</h2>

<p>
    @WelcomeTexts.Introduction
</p>
import { Component } from '@angular/core';

@Component({
    selector: 'angular-application',
    templateUrl: '/Template/Welcome'
})
export class AppComponent {}

Switching languages

To switch language I create an Angular component and an Angular service. The component handles the interface for the user and the service sends the chosen language back to the server. After the user selects a new language the Angular application is reloaded.

import {Component} from '@angular/core';
import {LocaleService} from './locale.service';

@Component({
    selector: 'locale-switcher',
    templateUrl: 'Template/Locale'
})

export class LocaleComponent {
    constructor(private _localeService: LocaleService) {}

    switch(language: string) {
        this._localeService.switchLanguage(language);
    }
}
@using AngularApplication.Resources
<h2>@LocaleTexts.SwitchLanguage</h2>

<ul>
	<li><a (click)='switch("en")'>English</a></li>
	<li><a (click)='switch("sv")'>Svenska</a></li>
</ul>
import {Injectable, ApplicationRef} from '@angular/core';
import {Http, Response} from '@angular/http';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class LocaleService {
    constructor(private _http: Http) {}

    switchLanguage(language: string) {
        this._http
            .post('Locale/Switch', { language: language })
            .subscribe();

        // Must reload to change language in templates
        window.location.reload();
    }
}

But wait, there’s a cache!

While the above sounds good on paper it won’t work terribly well in practice. The content of the templates depend on the language, but this isn’t reflected in the URLs. Hence any caching going on in the browser will interfere when the user changes the language. And any caching on the server will interfere when there are users with different languages.

To fix this we must add the language to the template URLs.

namespace AngularApplication.Controllers
{
    [OutputCache(Duration = 604800, VaryByParam = "language")]
    public class TemplateController : Controller
    {
        public ActionResult Welcome(string language)
        {
            return View();
        }

        public ActionResult Locale(string language)
        {
            return View();
        }
    }
}

The browser then has to use these new URLs when getting the templates. Therefore, we need to send the language to the browser. We do this by adding it to the DOM and using a bit of JavaScript to get it into a global JavaScript variable.

<div style="display:none">
    <div id="language" data-language="@ViewBag.Language"></div>
</div>
window.onload = function() {
    document.language = document
        .getElementById('language')
        .dataset['language'];
};

Lastly, we must add the language to the template URL in the component. We also have to add a type definition for document, otherwise TypeScript will complain about it being an unknown type.

import { Component } from '@angular/core';

declare var document: any;

@Component({
    selector: 'angular-application',
    templateUrl: `/Template/Welcome?language=${document.language}`
})
export class AppComponent {}

Translating ASP.NET MVC with resource files

Resource files are the easiest way to translate ASP.NET MVC applications into multiple languages. They are XML files containing name-value pairs for a specific language.

The resource file editor in Visual Studio

WelcomeTexts.resx
WelcomeTexts.de.resx
WelcomeTexts.sv-SE.resx
WelcomeTexts.uz-Cyrl-UZ.resx

Above are examples of resource file names. The language of the resource file is denoted by a BCP 47 language tag. When .NET looks up a resource by name it will choose the most appropriate file available (e.g. using en if en-US doesn’t exist). The last resort is to use the resource file without a language identifier. This file must exist and it must contain all resource names you want to use or .NET will not find them.

Using the resource files

When you create a new resource file in Visual Studio it will also generate a .NET class with members for each name. The class is regenerated when you rebuild the project to keep up to date with the resource file.

Note: By default Visual Studio will set the access modifier of the class to Internal. To be able to use them in your Razor files you want to change this to Public. This can be changed in the GUI, just above the editor. Or you can change the Custom Tool property from ResXFileCodeGenerator to PublicResXFileCodeGenerator manually in the Properties.

I prefer to use the postfix Texts on all my resource files to keep the generated class names from clashing with my other classes.

@using TranslatedApplication.Resources
<!DOCTYPE html>
<html>
<head>
    <title>@WelcomeTexts.Welcome</title>
</head>
<body>
<h1>@WelcomeTexts.Welcome</h1>

<p>
    @WelcomeTexts.Introduction
</p>
</body>
</html>

Setting the language

.NET chooses which resource file to use based on the language of the current thread. Specifically, it looks at the CurrentUICulture of the thread. We must set it at the start of every HTTP request.

The user should be given the option to change the language. But I also like to start with an educated guess based on the user’s language settings, which are sent to us by the browser.

To set the language I recommend creating an action filter attribute that performs the necessary steps before each controller action executes.

namespace TranslatedApplication.Infrastructure.Attributes
{
    public class LocalizeAttribute : ActionFilterAttribute, IActionFilter
    {
        private readonly string[] SupportedLanguages = {"en", "sv"};
        private const string DefaultLanguge = "en";

        void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
        {
            string language = DefaultLanguge;

            HttpRequestBase request = filterContext.HttpContext.Request;

            HttpCookie cookie = request.Cookies["Language"];
            if(cookie != null && SupportedLanguages.Contains(cookie.Value))
            {
                language = cookie.Value;
            }
            else if(request.UserLanguages != null)
            {
                foreach(string userLang in request.UserLanguages)
                {
                    string lang = userLang;
                    if(lang.Length < 2) continue;
                    if(lang.Contains('-'))
                        lang = lang.Substring(0, lang.IndexOf('-'));
                    if(SupportedLanguages.Contains(lang))
                    {
                        language = lang;
                        break;
                    }
                }
            }

            CultureInfo culture = new CultureInfo(language);
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = culture;
        }
    }
}

To make the attribute apply to all controller actions, add it to the global filters in FilterConfig.cs. This file should be in the App_Start directory, create it if it doesn’t exist.

namespace TranslatedApplication
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new LocalizeAttribute());
        }
    }
}

Finally, make sure the following line is in the Application_Start method in Global.asax.

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

To let the user change the language themselves, add a controller action for it. The page has to be reloaded to reflect the change.

Note: Keep in mind that since we use a cookie to remember the user’s choice we must inform the user about it under EU law.

public class LocaleController : Controller
{
    public ActionResult Switch(string language)
    {
        Response.Cookies["Language"].Value = language;
        return Redirect("/");
    }
}

What’s with .NET nowadays?

I was a bit confused about the current state of .NET. So I put together this very simplified overview.

.NET Standard Library
The formal specification for .NET. Specifies a minimal set of APIs for a .NET implementation.

.NET Framework
The old .NET implementation from Microsoft. Proprietary license. For Windows only.

Mono (Xamarin)
A third party implementation of .NET. Open source. Cross-platform.

.NET Core
The new .NET implementation from Microsoft. Open source. Cross-platform.

ASP.NET
The old set of web frameworks for .NET. Open source. Runs on .NET Framework and Mono.

ASP.NET Core
The new set of web frameworks for .NET. Open source. Runs on .NET Framework and .NET Core.

Windows Forms
The old technology for desktop applications for Windows. Runs on .NET Framework.

Windows Presentation Foundation
The newer technology for desktop applications for Windows. Runs on .NET Framework.

Universal Windows Platform
The newest technology for applications for Windows and Windows Phone. Runs on .NET Framework and .NET Core.

Visual Studio
The IDE for .NET development. Proprietary license. For Windows only.

Visual Studio Code
An editor for .NET development. Open source. Cross-platform.

Making a user friendly web form

Here I have tried to put together a form that is simple, practical and adheres to user accessible guide lines.

A user friendly web form

Example of an accessible form field

<div class="field">
    <label for="temp">Title here <span class="required-star"></span></label>
    <input id="temp" class="js-required" type="text" name="temp"
            aria-required="true" placeholder="e.g. example here" />
    <span class="error js-required-error" style="display: none" role="alert">
        Error message here
    </span>
    <span class="note">
        Extra information here
    </span>
</div>
  • Red stars for required fields is a common convention
  • Examples as placeholders may occasionally be useful, but make sure they are understood as examples
  • The aria-required and role attributes are there to help screen readers
  • Error messages should appear when the user leaves the input (i.e. on blur), that way they appear as early as possible without being disruptive during typing
  • If there are errors when the user submits the form an error message should appear at the top in addition to the inline errors
  • Prefer radio buttons over select boxes when there are few options

Let Angular do the work

From the old battlefield of JavaScript frameworks for single page applications, two seem to be emerging victorious. Angular and React. With the former being the more popular of the two and with Angular 2 on its way, it’s worth to take a look at.

<!DOCTYPE html>
<html>
<head>
  <title>Minimal one file Angular 2 example</title>
  <script src="node/core-js/client/shim.min.js"></script>
  <script src="node/zone.js/dist/zone.js"></script>
  <script src="node/reflect-metadata/Reflect.js"></script>
  <script src="node/rxjs/bundles/Rx.umd.js"></script>
  <script src="node/@angular/core/bundles/core.umd.js"></script>
  <script src="node/@angular/common/bundles/common.umd.js"></script>
  <script src="node/@angular/compiler/bundles/compiler.umd.js"></script>
  <script src="node/@angular/platform-browser/bundles/platform-browser.umd.js"></script>
  <script src="node/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      ng.platformBrowserDynamic.bootstrap(ng.core
        .Component({
          selector: 'angular-app',
          template: '<h2>{{greeting}}</h2>'
        })
        .Class({
          constructor: function() {
            var thisClass = this;
            thisClass.greeting = 'Hello world';
            setTimeout(function() { thisClass.greeting = 'Cruel world' }, 1700);
          }
        }));
    });
  </script>
</head>
<body>
  <angular-app>Loading...</angular-app>
</body>
</html>

In practice Angular 2 consists of numerous JavaScript files compiled from TypeScript. Npm is used for getting these files to your computer. Which scripts you then use on your site depends on what you want to do. The set of scripts used in the example are taken from the official quickstart guide.

An Angular 2 application consists of a tree of components with one component at the top. The top component is then used to bootstrap the entire application. In the example there is only component defined directly into the bootstrap function.

Fix SQL Server login after backup

Ever had the scenario where there are two SQL servers, one production and one backup, then after backing up the databases to the backup server the logins don’t work anymore? This is because logins in SQL Server consists of two parts; one server login and one or more database users. After the backup the database users, coming from the production server, no longer matches the server logins, coming from the backup server.

To avoid this problem the backup server logins can be recreated (or created if they don’t exist yet) so that they match the production database users.

On the production server run the following query to find the name and SID (Security ID) of the login that you want to fix.

SELECT name, sid FROM sys.server_principals WHERE type = 's'

On the backup server start by removing the server login if it already exists.

DROP LOGIN Tusse

Then, on the backup server, create the user with the correct name, password and SID.

CREATE LOGIN Tusse WITH password = N'Pa$$w0rd', sid = 0x2D749BCC12...

Now the backup server logins will match the production database users even after future backups.

Data in a web page

There are several places to store data in an ASP.NET web page. These places are far from interchangeable. Careless placement of data can lead to a poor web page and bad user experience. The following are some guide lines that I consider appropriate.

URL

Use for: Data that defines the web page. Such as the ID for a product or the terms for search results.

Remember: This becomes permanent if the page is bookmarked. Don’t store temporary modifiers in the URL. For example, if the user bookmarks the login page after a failed login attempt they shouldn’t have to see the error message every time they return.

DOM

Use for: Data that makes up the web page. Apart from the obvious, text and HTML, this can include JSON to be used by JavaScript.

Remember: Data attributes are a good place to store data for use in JavaScript.

Global JavaScript variables

Use for: Keeping state in single page applications or other long lived web pages with lots of JavaScript.

Remember: In JavaScript all scripts share the same namespace. Take care that your variables don’t clash with other scripts, for example by putting all your global variables into one global object. There are other ways to handle this as well.

Local storage

Use for: Applications where you can’t or don’t want to store data server side.

Remember: This data is stored permanently in the browser. The data won’t be available if the user returns with a different browser or device.

Cookie

Use for: Remembering users across visits on web sites requiring login. Or remembering user settings on web sites that does not use logins.

Remember: Current EU law dictates that web sites targeting EU citizens must obtain user permission when setting cookies. Though there are some exceptions.

Session

Use for: Data related to the currently logged in user.

Remember: The session is controlled by a session cookie stored in the browser. ASP.NET takes care of this automatically. It is the browser that determines when the session ends by removing the cookie. Session cookies used for authentication purposes does not fall under the EU law described above.

TempData

Use for: Data you want to keep between page requests, but not longer. Good for showing the user that data has been saved for example.

Remember: This data is stored in the session but has the extra property that it disappears after being read.

Application data

Use for: As a cache for common data needed server side.

Remember: This data is common for all users and persists until the application reloads. The data must be handled in a thread safe manner.

Database

Use for: Everything that needs permanent storage.

Remember: Database design and management is a whole science in and of itself.

Web components of HTML

Web Components consists of four separate standards. Together they aim to facilitate the creation of reusable and self-contained pieces of HTML (with JavaScript and CSS). Browser support is lacking but can be polyfilled.

Templates

The template tag holds markup that can be used from JavaScript. It provides a browser native alternative to JavaScript templating libraries.

<div class="fact">All birds are animals</div>
<div class="fact">Some animals are dogs</div>

<template id="fact-box">
    <h1>Fact</h1>
    <p></p>
</template>

<script>
    var template = document.querySelector("#fact-box").content;
    var facts = document.querySelectorAll(".fact");
    [].forEach.call(facts, function(fact) {
        var clone = document.importNode(template, true);
        clone.querySelector("p").innerHTML = fact.innerHTML;
        fact.replaceChild(clone, fact.firstChild);
    });
</script>

Shadow DOM

The shadow DOM is a way to create nested DOMs. They can then be styled independently from the rest of the page. The content tag provides a way to enter content into the shadow DOM from the shadow root element.

<div class="fact">All birds are animals</div>
<div class="fact">Some animals are dogs</div>

<template id="fact-box">
    <h1>Fact</h1>
    <p><content></content></p>
</template>

<script>
    var template = document.querySelector("#fact-box").content;
    var facts = document.querySelectorAll(".fact");
    [].forEach.call(facts, function(fact) {
        var clone = document.importNode(template, true);
        fact.createShadowRoot().appendChild(clone);
    });
</script>

Custom elements

Creating custom elements allow us to name our pieces of HTML. To distinguish user made tags from official tags the former must always contain a hyphen.

<fact-box>All birds are animals</fact-box>
<fact-box>Some animals are dogs</fact-box>

<template id="fact-box">
    <h1>Fact</h1>
    <p><content></content></p>
</template>

<script>
    var template = document.querySelector("#fact-box").content;
    var prototype = Object.create(HTMLElement.prototype);
    prototype.createdCallback = function() {
        var clone = document.importNode(template, true);
        this.createShadowRoot().appendChild(clone);
    };
    document.registerElement("fact-box", {prototype: prototype});
</script>

HTML imports

Finally, with HTML imports, the finished web component can be placed in an HTML file and imported where it is needed.

<head>
    <link rel="import" href="fact-box.html">
</head>

<fact-box>All birds are animals</fact-box>
<fact-box>Some animals are dogs</fact-box>
<template id="fact-box">
    <h1>Fact</h1>
    <p><content></content></p>
</template>

<script>
    var thisDocument = document.currentScript.ownerDocument;
    var template = thisDocument.querySelector("#fact-box").content;
    var prototype = Object.create(HTMLElement.prototype);
    prototype.createdCallback = function() {
        var clone = document.importNode(template, true);
        this.createShadowRoot().appendChild(clone);
    };
    document.registerElement("fact-box", {prototype: prototype});
</script>

Testing the view

The view part of ASP.NET MVC is difficult to test in isolation. It is more commonly integration tested together with the rest of the system.

@model IEnumerable<ShipRegister.Models.Ship>
<!DOCTYPE html>

<html>
<head>
    <title>Ship register</title>
    <script src="~/Scripts/jquery-2.1.1.js"></script>
    <script>
        $(function () {
            $("li").on("click", function () {
                $(this).css("color", "red");
            });
        });
    </script>
</head>
<body>
    <h2>Ships</h2>
    <ul>
    @foreach (Ship ship in Model) {
        <li>@ship.Name</li>
    }
    </ul>

    <form action="/Ship/Create" method="post">
        <input type="text" name="Name" placeholder="Ship name" />
        <input type="submit" id="Button" value="Add" />
    </form>
</body>
</html>

The view also includes JavaScript which may be tested at the same time.

[TestClass]
public class ShipViewTests
{
    [TestMethod]
    public void WebRootShowsShipRegister()
    {
        using (IWebDriver driver = new FirefoxDriver())
        {
            // Arrange / Act
            driver.Navigate().GoToUrl("http://localhost:51794/");

            // Assert
            Assert.AreEqual("Ship register", driver.Title);
        }
    }

    [TestMethod]
    public void SubmitNewShipShowsNewShip()
    {
        string shipName = "Ship " + Guid.NewGuid();

        using (IWebDriver driver = new FirefoxDriver())
        {
            // Arrange
            driver.Navigate().GoToUrl("http://localhost:51794/");
            IWebElement textInput = driver.FindElement(By.Name("Name"));
            IWebElement submitButton = driver.FindElement(By.Id("Button"));

            // Act
            textInput.SendKeys(shipName);
            submitButton.Click();

            // Assert
            IWebElement ship = driver.FindElements(By.TagName("li")).Last();
            Assert.AreEqual(shipName, ship.Text);
        }
    }

    [TestMethod]
    public void ClickShipColorsShipRed()
    {
        using (IWebDriver driver = new FirefoxDriver())
        {
            // Arrange
            driver.Navigate().GoToUrl("http://localhost:51794/");
            IWebElement ship = driver.FindElements(By.TagName("li")).First();

            // Act
            ship.Click();

            // Assert
            Assert.AreEqual("color: red;", ship.GetAttribute("style"));
        }
    }
}

These tests are performed in Firefox with the help of Selenium. A new Firefox instance is opened for each test.