Blog

I clearly remember when I started my first job way back almost 30 years ago. At that time, computers didn’t have such a major role in the work environment. Although I was always into software development, there were a lot of engineering jobs. So that’s what I ended up doing. I worked for a telephone company, and the first task I was given was cleaning this thing from used wires so that it can be reused again:

That’s called a distribution frame, and what I had to do is to pull out the wires with a hook. These boxes were used in pairs, one for connecting the telephone system and one for the actual distribution to each telephone. Each 2-wire point was connected from one distribution box to the other to make a path from the system to the actual phone.

And we were instructed to wire everything neatly. And we used colour coding as well, so the same coloured wires would be always in the same spot for all installations, and it would be easy to spot mistakes and to maintain. Sometime later, patch leads with plastic (RJ11) connectors became the norm. And after spending a day patching the system we used to be proud of our work. A cabinet such as this one is such a joy to behold:

A neat installation

We often suggested to our clients to invest in proper cabinets with cable trays and room to work properly. However I also know that it costs money and is not always easy to justify the spending against cheaper alternatives. I remember this one time when we provided a quote which was double that of our competitor. The labour cost of our competitor was almost non-existent, and the customer chose the cheaper option.

When the work was finished it looked like this:

A messy installation

Of course, everything worked initially and the competitor was promptly paid. The problems started after some time when trying to patch a phone to a new location required hours of work trying to find the correct patch lead and untangle it from the rest. Eventually, it got out of control, our competitor admitted that they focused on installations rather than maintenance work and suggested that the customer gets in touch with us.

We were happy to help, and the customer, in the end, was happy too. Although we did charge extra for cleaning the existing installation on top of the original quote.

I did write a lot of software during the next few years, both for the telephone company as well as a freelancer. Fast forward some more years and I wanted to find a full-time development job. You know, I thought programmers are cool and earn big bucks, but mostly I wanted to do it to gain experience. I wanted to learn how the pros write their software and I wanted to become one of them.

That’s when I realised that a lot of the software industry just tries to earn a quick buck by delivering stuff quickly (and breaking things along the way). It reminds me of the wiring incident all those years before. Since then I have been looking for information about writing clean code. Code that does not only work well the first time but also after every time it needs modifications.

I have been following a number of people who have been trying to teach us what it means to be a professional coder. People like Martin Fowler, Uncle Bob, Kevlin Henney, and recently Kate Gregory to name a few. If you have never done so before, I suggest that you take your time to discover and realise what writing good code means. And how it will benefit the long term health of your project. This is much more important than learning the next big language or framework that can do this and that other new thing. This is about tidiness in your work, and going back home at the end of the day with something that you are proud with.

So the moment that I was waiting for has finally arrived. I picked up my courage and pressed the publish button of the .NET Core project. Then soon after, this happened:

The main message from this chart is that before publishing this version, the average response time of the site running on ASP.NET MVC 5 was between 90 and 100ms. With ASP.NET Core 2.2 we can see that the average is now around the 20ms mark.

That’s an improvement factor of 5X, and the best part of it is that there is minimal change in code. And this code is mainly updating references from System.Web to Microsoft.AspNetCore (see my previous blog entries to know more about these tweaks). And I also have to admit that this is running on the smallest paid tier.

So now the fun part starts, trying to improve the performance even further through my own changes.

As promised last time, I’m going to talk about HTML helpers on ASP.NET Core. If you’ve never heard about helpers before you may be thinking about another kind of helper perhaps:

However, I’m talking about the kind of helper which helps you write code once and re-use it in multiple places. The two biggest advantages with helpers are that they keep the page output consistent and when the time comes to change something you only need to change it in one place. Code repetition is not good and never fun.

Tag helpers seem to be the cool thing to do with .NET Core, but remember that I am looking to convert the site from MVC 5 with minimal changes and if possible do everything without touching the views.

The first required adjustment was to change the helper type to IHtmlHelper and the return type to IHtmlContent. That is good since in both cases the change is minimal, and because by using interfaces the helper is not directly dependant on any particular type as long as the type implements the interface.

The major problem that I faced was with the TagBuilder’s InnerHtml property: it’s readonly. No big worries though. Once I noticed that this was a dead end, changing the helper to build the content via a StringBuilder instead proved to be very easy. The last fix was to change the return object from MvcHtmlString to HtmlString.

Once that was done, it was just a case of running the solution and this permitted me to confirm that everything was actually working as wanted.

One final step that I want to sneak in is adding Application Insights to the solution. We are almost done with the changes, so adding monitoring to start gathering some data makes sense at this point. There is also tooling in Visual Studio to help with this. The easiest way is to right-click on the project and Add > Application Insights. Since I was already using Insights on the previous solution, this was also detected and the existing instrumentation key was easily picked up and configured by the editor. Next time, let’s get ready to publish the changes!

After migrating the layout page, it’s time to start working on the individual pages. I will start with the About page since it is the easiest and contains just a view with some static text. It’s all a matter of copying the controller and the view from the MVC5 solution to the new one.

Next I’ll work on the software details page. I did plan to start originally with the software overview page, but since that page makes use of a custom HTML helper I have decided to keep that for the next post.

So again, I copy over the controller code and this time the view model as well. Inside the view, we need to change the reference to Microsoft.AspNetCore.Mvc instead of System.Web.Mvc. Everything else stays the same, apart from the response caching part, which in my case I had to change this:

[OutputCache(Duration = 3600, VaryByParam = "softwareId")]

to this:

[ResponseCache(Duration = 3600, VaryByQueryKeys = new string[] { "softwareId" })]

As with mostly everything else, every feature that we want to use needs to be declared explicitly in .Net Core. For caching we need to reference Microsoft.AspNetCore.ResponseCaching and set it up in the Startup class. Add app.UseResponseCaching(); before app.UseMvc... and services.AddResponseCaching(); before services.AddMvc().

Since I am also reading data from the data provider class, I will also need to add the required dependency injection configuration.

services.AddTransient<ISoftwareProvider, EFSoftwareProvider>();

Finally, I copy the views and notice that everything looks ok. It has to work, but then I realise that I did not set up the route to handle this detail page. However, adding a route is just as simple as it ever was:

routes.MapRoute(
                    "Software details", 
                    "Software/{softwareId}/{title?}",
                    new { controller = "Software", action = "Details" });

And once again, I managed to migrate a page in a few easy steps.

In my last post, I left with the solution running an ASP.Net Core page which showed some information by calling the data libraries which were previously used by a MVC5 solution. That solution was using the standard out-of-the-box layout, so now the next step for me is to copy the layout from the old site and see what modifications need to be done in order to get it running.

The easiest part is copying the _Layout.cshtml file, since the path is the same (Views/Shared).

The first difference that we encounter is in the location of the CSS and Javascript files. The CSS files are moved from the Content folder into the wwwroot/css folder, whilst Javascript files must be copied from the Scripts folder into the wwwroot/js folder.

The next difference again is related to these files. The old default way of bundling assets was to configure everything in the App_Start/BundleConfig.cs file. The required files would then be bundled and minified at runtime. The .Net Core way of handling this is to pre-compile the bundling and minification process, and is configured inside the bundleconfig.json file. This is the file as I currently set it up:

[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/css/todc-bootstrap.css",
      "wwwroot/css/site.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    },
    "sourceMap": false
  }
]

Since the process is different, the link to the file itself is modified as well. Note below the option to add the version number to the file is now part of the framework, whereas before I had to write this functionality myself. Adding the version number makes sure that the latest CSS is always read from the server when there is a change rather than from cache.

<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />

There is also the possibility to link to the source paths directly when debugging during the development process. This can be done with the Environment tag helper. In the first case below, the unminified file is used during development and the minified version during testing/production:

<environment include="Development">
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>

For Javascript files, there is also additional functionality out of the box in the shape of a CDN fallback mechanism. In this way, there is an attempt to fetch the file from CDN first, test by confirming that a particular object was correctly initialised (in this case window.jQuery), and in case of failure fall back to fetching the file locally.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
</script>

Those were the most interesting parts, the remaining change was not strictly related to the migration. Since there are known security issues on using Bootstrap 3.3.7, I upgraded to the latest 3.4.0 package. That’s it, the site is now running with the migrated layout.

running the solution with the new layout