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.

Testing the model

The model part of ASP.NET MVC is best tested in conjunction with the database.

public class ShipRepository : IShipRepository
{
    private string ConnectionString;

    public ShipRepository()
    {
        ConnectionString = ConfigurationManager
            .ConnectionStrings["Database"].ToString();
    }

    public ShipRepository(string connectionString)
    {
        ConnectionString = connectionString;
    }

    public IEnumerable<Ship> GetList()
    {
        const string query = "SELECT Name FROM Ships";
        var ships = new List<Ship>();
        using (var connection = new SqlConnection(ConnectionString))
        {
            connection.Open();
            using (var command = new SqlCommand(query, connection))
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    ships.Add(new Ship { Name = reader.GetString(0) });
                }
            }
        }
        return ships;
    }

    public void Insert(Ship ship)
    {
        var ships = new List<Ship>();
        using (var connection = new SqlConnection(ConnectionString))
        {
            connection.Open();
            using (var command = new SqlCommand("spInsertShip", connection))
            {
                command.CommandType = CommandType.StoredProcedure;
                command.Parameters.AddWithValue("@Name", ship.Name);
                command.ExecuteNonQuery();
            }
        }
    }
}

This class uses the repository pattern to manage the model.

[TestClass]
public class ShipRepositoryTests
{
    [TestCleanup]
    public void Cleanup()
    {
        RunNonQuery("TRUNCATE TABLE Ships");
    }

    [TestMethod]
    public void GetListReturnsAllRows()
    {
        // Arrange
        RunNonQuery("INSERT INTO Ships (Name) VALUES ('Ship 1')");
        RunNonQuery("INSERT INTO Ships (Name) VALUES ('Ship 2')");
        var repository = new ShipRepository(GetConnectionString());

        // Act
        IEnumerable<Ship> ships = repository.GetList();

        // Assert
        Assert.AreEqual(2, ships.Count());
        Assert.IsTrue(ships.Select(s => s.Name).Contains("Ship 1"));
        Assert.IsTrue(ships.Select(s => s.Name).Contains("Ship 2"));
    }

    [TestMethod]
    public void InsertShipInsertsRow()
    {
        // Arrange
        var repository = new ShipRepository(GetConnectionString());

        // Act
        repository.Insert(new Ship { Name = "New Ship" });

        // Assert
        var shipNames = RunStringListQuery("SELECT Name FROM Ships");
        Assert.AreEqual(1, shipNames.Count());
        Assert.IsTrue(shipNames.Contains("New Ship"));
    }

    private string GetConnectionString()
    {
        return ConfigurationManager
            .ConnectionStrings["Test"].ToString();
    }

    private void RunNonQuery(string query)
    {
        using (var connection = new SqlConnection(GetConnectionString()))
        {
            connection.Open();
            using (var command = new SqlCommand(query, connection))
            {
                command.ExecuteNonQuery();
            }
        }
    }

    private IEnumerable<string> RunStringListQuery(string query)
    {
        var result = new List<string>();
        using (var connection = new SqlConnection(GetConnectionString()))
        {
            connection.Open();
            using (var command = new SqlCommand(query, connection))
            using(var reader = command.ExecuteReader())
            {
                while(reader.Read())
                {
                    result.Add(reader.GetString(0));
                }
            }
        }
        return result;
    }
}

These tests are run against a separate test database which is emptied after each test.

Testing the controller

The controller is the most straightforward part of ASP.NET MVC to test.

public class ShipController : Controller
{
    private readonly IShipRepository Repository;

    public ShipController() : this(new ShipRepository()) { }

    public ShipController(IShipRepository repository)
    {
        Repository = repository;
    }

    public ViewResult Index()
    {
        IEnumerable<Ship> ships = Repository.GetList();
        return View(ships);
    }

    public RedirectResult Create(Ship ship)
    {
        if (ModelState.IsValid)
        {
            Repository.Insert(ship);
        }
        return Redirect("/");
    }
}

The only thing this controller depends on is the repository which handles the model.

[TestClass]
public class ShipControllerTests
{
    [TestMethod]
    public void IndexReturnsAllShips()
    {
        var ships = new List<Ship>
            {
                new Ship { Name = "Ship 1"},
                new Ship { Name = "Ship 2"}
            };

        // Arrange
        var repository = Mock.Of<IShipRepository>(r => r.GetList() == ships);
        var controller = new ShipController(repository);

        // Act
        ViewResult result = controller.Index();

        // Assert
        Assert.AreEqual(ships, result.Model);
    }

    [TestMethod]
    public void CreateInsertsShip()
    {
        Ship ship = new Ship { Name = "New Ship" };

        // Arrange
        var repository = Mock.Of<IShipRepository>();
        var controller = new ShipController(repository);

        // Act
        controller.Create(ship);

        // Assert
        Mock.Get(repository).Verify(m => m.Insert(ship));
    }

    [TestMethod]
    public void CreateRedirectsToRoot()
    {
        Ship ship = new Ship { Name = "New Ship" };

        // Arrange
        var repository = Mock.Of<IShipRepository>();
        var controller = new ShipController(repository);

        // Act
        RedirectResult result = controller.Create(ship);

        // Assert
        Assert.AreEqual("/", result.Url);
    }
}

This is using Moq to replace the repository and the arrange-act-assert pattern to perform the tests.

SignalR: talk to your clients

In HTTP the browser is supposed to initiate all requests. This makes two way communication difficult. If the server wants to push data to the browser the browser has to poll for it. Possibly with the help of Server-sent events. There is a modern solution, however. It is called WebSocket. But even when it can be used all it provides is a low-level TCP connection.

SignalR takes care of both of these problems; It uses the best technology available and it provides a common easy-to-use interface regardless of the underlying connection. SignalR is intended to be used with ASP.NET and jQuery.

Counter: <span id="counter">-</span>
<button id="reset">Reset</button>

For this demonstration I want to have a counter that repeatedly counts up and a button to reset the it to zero. The magic is that the same number is to be displayed on all connected browsers.

<script src="~/Scripts/jquery.min.js"></script>
<script src="~/Scripts/jquery.signalR.min.js"></script>
<script src="~/signalr/hubs"></script>
[assembly: OwinStartup(typeof(SignalRTest.Startup))]

namespace SignalRTest
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

First there are some infrastructure on the browser and server that needs to be in place before SignalR can be used. The hubs script is created by SignalR, it does not exist physically.

$(function () {
    $.connection.counterHub.client.update =
        function (value) {
            $("#counter").html(value);
        };
    $("#reset").on("click", function () {
        $.connection.counterHub.server.reset();
    });
    $.connection.hub.start();
});

This is all the JavaScript necessary for this little demonstration. The first part defines an update function to be called from the server. The second part binds the button to a call to a reset method on the server.

public class CounterHub : Hub
{
    private static int value = 0;

    public void Reset()
    {
        Interlocked.Exchange(ref value, 0);
        Clients.All.writeTime(value);
    }

    public static void Increment()
    {
        Interlocked.Increment(ref value);
        IHubContext context = GlobalHost.ConnectionManager
            .GetHubContext<CounterHub>();
        context.Clients.All.update(value);
    }
}

On the server side is the reset method and a call to the update function. The update call is wrapped in a static method because it has to be called from outside the hub. This is the recommended way of doing it.

new Timer(o => CounterHub.Increment(), null, 0, 100);

I put this line in Application_Start in the Global.asax.cs file. It works for the demonstration. In a real scenario it should definitely be replaced with something more robust.