.net core, C# tip, MVC

Adding middleware to your .NET Core MVC pipeline to prettify HTML output with AngleSharp

I was speaking to a friend of mine recently about development and server side generated HTML, and they said that one thing they would love to do is improve how HTML code is when it’s rendered. Often when they look at the HTML source of a page, the indentation is completely wrong, and there are huge amounts of whitespace and unexpected newlines.

And I agreed – I’ve seen that too. Sometimes I’ve been trying to debug an issue in the rendered output HTML, and one of the first things I do format and indent the HTML code so I can read and understand it. And why not – if my C# classes aren’t indented logically, I’d find it basically unreadable. Why should my HTML be any different?

So it occurred to me that I might be able to find a way to write some middleware for my .NET Core MVC website that formats and indents rendered HTML for me by default.

This post is just a fun little experiment for me – I don’t know if the code is performant, or if it scales. Certainly on a production site I might want to minimise the amount of whitespace in my HTML to improve download speeds rather than just change the formatting.

Formatting and Indenting HTML

I’ve seen a few posts asking how to do this with HtmlAgilityPack – but even though HtmlAgilityPack is amazing, it won’t format HTML.

I’ve also seen people recommend a .NET wrapper for the Tidy library, but I’m going to use AngleSharp. AngleSharp is a .NET library that allows us to parse HTML, and contains a super useful formatter called PrettyMarkupFormatter.

var parser = new AngleSharp.Html.Parser.HtmlParser();
var document = parser.ParseDocument("<html><body>Hello, world</body></html>");
 
var sw = new StringWriter();
document.ToHtml(swnew AngleSharp.Html.PrettyMarkupFormatter());
 
var indentedHtml = sw.ToString();

And I can encapsulate this in a function as below:

private static string PrettifyHtml(string newContent)
{
    var parser = new AngleSharp.Html.Parser.HtmlParser();
    var document = parser.ParseDocument(newContent);
 
    var sw = new StringWriter();
    document.ToHtml(swnew AngleSharp.Html.PrettyMarkupFormatter());
    return sw.ToString();
}

Adding middleware to modify the HTML output

There’s lots of information on writing ASP.NET Core middleware here and I can build on this and the AngleSharp code to re-format the rendered HTML. The code below allows me to:

  • Check I’m in my development environment,
  • Read the rendered HTML from the response,
  • Correct the indentation using AngleSharp and the new PrettifyHtml method, and
  • Write the formatted HTML back to the Response.
if (env.IsDevelopment())
{
    app.Use(async (contextnext=>
    {
        var body = context.Response.Body;
 
        using (var updatedBody = new MemoryStream())
        {
            context.Response.Body = updatedBody;
 
            await next();
 
            context.Response.Body = body;
 
            updatedBody.Seek(0SeekOrigin.Begin);
            var newContent = new StreamReader(updatedBody).ReadToEnd();
 
            await context.Response.WriteAsync(PrettifyHtml(newContent));
        }
    });
}

And now the HTML generated by my MVC application is formatted and indented correctly.

Wrapping up

This post is really just a proof of concept and for fun – I’ve restricted the effect to my development environment in case it doesn’t scale well. But hopefully this is useful to anyone trying to format HTML, or intercept an HTML response to modify it.


About me: I regularly post about Microsoft technologies and .NET – if you’re interested, please follow me on Twitter, or have a look at my previous posts here. Thanks!

Continue reading

.net core, C# tip, MVC, Non-functional Requirements, Performance

Creating a RESTful Web API template in .NET Core 1.1 – Part #3: Improving the performance by using compression

One of the simplest and most effective improvements you can make to your website or web service is to compress the stream of data sent from the server. With .NET Core 1.1, it’s really simple to set this up – I’ve decided to include this in my template project, but the instructions below will work for any .NET Core MVC or Web API project.

Only really ancient browsers are going to have problems with gzip – I’m pretty happy to switch it on by default.

.NET Core 1.1 adds compression to the ASP.NET HTTP pipeline using some middleware in the Microsoft.AspNetCore.ResponseCompression package. Let’s look at how to add this to our .NET Core Web API project.

Step 1: Add the Microsoft.AspNetCore.ResponseCompression package

There’s a few different ways to do this – I prefer to add packages from within PowerShell. From within Visual Studio (with my project open), I open a Package Manager Console, and run:

Install-Package Microsoft.AspNetCore.ResponseCompression

(But it’s obviously possible to do this from within the NuGet package manager UI as well)

This will add the package to the Web API project, and you can see this in the project.json file (partially shown below).

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.1.0",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Mvc": "1.1.0",
    "Microsoft.AspNetCore.Routing": "1.1.0",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
    "Microsoft.Extensions.Configuration.Json": "1.1.0",
    "Microsoft.Extensions.Logging": "1.1.0",
    "Microsoft.Extensions.Logging.Console": "1.1.0",
    "Microsoft.Extensions.Logging.Debug": "1.1.0",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
    "Microsoft.AspNetCore.ResponseCompression": "1.0.0"
  },
  ...

Step 2: Update and configure services in the project Startup.cs file

We now just need to add a couple of lines to the Startup.cs project file, which will:

  • Add the services available to the runtime container, and
  • Use the services in the HTTP pipeline at runtime.

I’ve highlighted the lines that I added in bold red font in the code below.

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }
 
    public IConfigurationRoot Configuration { get; }
 
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCompression();
 
        // Add framework services.
        services.AddMvc();
    }
 
    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseResponseCompression();
 
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
 
        app.UseMvc();
    }
}

Now when I call my web service, all responses are zipped by default.

We can prove this by looking at the headers sent with the response – I’ve pasted a screenshot of the headers sent back when I call a GET method in my Web API service. There is a header named “Content-Encoding” which has the value “gzip” – this signals that the response has been zipped.

screenshot-1480371947

Wrapping up

This is a really easy way to improve the performance of your website or your web service – this is one of the first things I configure when starting a new project.

Continue reading

.net, C# tip, Clean Code, Dependency Injection, Inversion of Control, MVC, Solid Principles

How to use built-in dependency inversion in MVC6 and ASP.NET Core

I’ve previously posted about the new logging features in ASP.NET Core RC1 and MVC6. This time I’m going to write about how Microsoft now has dependency inversion baked into the new Core framework.

Dependency inversion is a well documented and understood principle – it’s what the D stands for in SOLID, and says that your code should only depend on abstractions, not concrete implementations. So plug your services into your application through interfaces.

ojfhi
No

In previous versions of MVC, I’ve needed to download a 3rd party library to assist with dependency inversion – these libraries are also sometimes called “containers”. Examples of containers I’ve used are NInject.MVC, Autofac, and Sprint.NET.

In MVC6, Microsoft has entered this field, by including a simple container in the new version of ASP.NET. This isn’t intended to replicate all the features of other containers – but it provides dependency inversion features which may be suitable for many projects. This allows us to avoid adding a heavyweight 3rd party dependency to our solution (at least until there’s a feature we need from it).

Getting started

For our example, first create the default MVC6 web application in Visual Studio 2015.

webapp1.png

Now let’s create a simple stubbed service and interface to get some users. We’ll save this in the “Services”folder of the project.

public interface IUserService
{
    IEnumerable<User> Get();
}

We’ll need a User object too – we’ll put this in the “Models” folder.

public class User
{
    public string Name { getset; }
}

Let’s create a concrete implementation of this interface, and save this in the “Services” folder too.

public class UserService : IUserService
{
    public IEnumerable<User> Get()
    {
        return new List<User>{ new User { Name = "Jeremy" } };
    }
}

Now modify the HomeController to allow us to display these users on the Index page – we need to change the constructor (to inject the interface as a class dependency), and to change the Index action to actually get the users.

public class HomeController : Controller
{
    private readonly IUserService _userService;
 
    public HomeController(IUserService userService)
    {
        _userService = userService;
    }
 
    public IActionResult Index()
    {
        var users = _userService.Get();
        return View(users);
    }
}

If we just run our project now, we’ll get an exception – the HomeController’s Index action is trying to get users, but the IUserService has not been instantiated yet.

error

We need to configure the services that the container knows about. This is where Microsoft’s new dependency inversion container comes in. You just need to add a single line of code in the ConfigureServices method in Startup.cs to make sure the controller is given a concrete instance of UserService when it asks the container “Can you give me something that implements IUserService?

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddTransient<IUserServiceUserService>();
}

If we run the project again now, we won’t get any exceptions – obviously we’d have to change the Index view to display the users.

Transient, Scoped, Singleton, Instance

In the example above, I used the “AddTransient” method to register the service. There’s actually 4 options to register services:

  • AddTransient
  • AddScoped
  • AddSingleton
  • AddInstance

Which option you choose depends on the lifetime of your service:

  • Transient services are created each time they are called. This would be useful for a light service, or when you need to guarantee that every call to this service comes from a fresh instantiation (like a random number generator).
  • Scoped services are created once per request. Entity Framework contexts are a good example of this kind of service.
  • Singleton services are created once and then every request after that uses the service that was created the first time. A static calculation engine might be a good candidate for this kind of service.
  • Instance services are similar to Singleton services, but they’re created at application startup from the ConfigureServices method (whereas the Singleton service is only created when the first request is made). Instantiating the service at startup would be useful if the service is slow to start up, so this would save the site’s first user from experiencing poor performance.

Conclusion

Microsoft have added their own dependency inversion container to the new ASP.NET Core framework in MVC6. This should be good enough for the needs of many ASP.NET projects, and potentially allows us to avoid adding a heavyweight third party IoC container.

.net, C# tip, Clean Code, Dependency Injection, Inversion of Control, MVC

How to use NLog or Serilog with C# in ASP.NET Core

ASP.NET core is still pretty new – at the time of writing, it’s still only at Release Candidate 1. I downloaded it for the first time a few days ago to play with the sample projects, and was surprised (in a good way) by how much has changed in the default project for MVC6. Of course the standard way of using Models, Views and Controllers is still similar to how it was in recent versions of MVC – but, the project infrastructure and configuration options are unrecognisably different (at least to me).

One of the first things I do when I set up a new project is configure the instrumentation – namely logging. I’d read a new feature of ASP.NET Core is that it provides built-in interfaces for logging – ILogger and ILoggerFactory.

This is a nice feature and provides me with an opportunity to write cleaner code. In previous versions of MVC, if I’d injected a logger interface into my controller classes, I still needed to introduce a dependency on a 3rd party library to every class that used this interface. So even though I’m injecting a dependency using an interface, if I changed logging library, I’d have to modify each of these classes anyway. Of course I could write a wrapper library for my 3rd party logging library, but I’d prefer not to have to write (and test) even more code.

Having the logging interface built into the framework gives me the opportunity to clean this up. So if I now want to add logging to my controller, I can write something like the code below. You can see this doesn’t have a dependency on a 3rd party library’s namespace – just a namespace provided by Microsoft.

using Microsoft.AspNet.Mvc;
using Microsoft.Extensions.Logging;
 
namespace WebApplication.Controllers
{
    public class HomeController : Controller
    {
        private ILogger<HomeController> _logger;
 
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }
 
        public IActionResult Index()
        {
            _logger.LogInformation("Home controller and Index action - logged");
            return View();
        }

For this post, I created a default MVC6 project, and modified the HomeController to match the code above – I just added the bold text.

So how can we integrate third party libraries into an MVC6 project?

Configure the default ASP.NET MVC6 project to use NLog

Let’s configure NLog first.

Install-package NLog.Extensions.Logging -pre
  • Then we need to add a configuration file – nlog.config – to the root of our project. You can get a perfect example from github here – just remember to change the file locations in this config file to directories that exist in your environment.
  • Finally, modify the Startup.cs file’s Configure method by adding a couple of lines of code.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddNLog();
    env.ConfigureNLog("nlog.config");

Now just run the project – notice I didn’t need to make any changes to my HomeController class. My project created a log file named “nlog-all-2016-03-27.log” which has the text:

2016-03-27 00:27:29.3796|WebApplication.Controllers.HomeController|INFO|Home controller and Index action - logged

Configure the default ASP.NET MVC6 project to use Serilog

Let’s say for whatever reason – maybe you want to use message templates to structure your logging data – you decide that you’d prefer to use the Serilog library instead of NLog. What changes do I need to make to my project to accommodate this?

Previously, if I’d wanted to change logging library, I’d have had to change every class that logged something – probably remove a namespace inclusion of “using NLog” and add a new one of “using Serilog”, and maybe even change the methods used to log information.

But with Asp.NET Core, I don’t need to worry about that.

  • First I need to install a pre-release nuget package for Serilog;
     Install-package Serilog.Sinks.File -pre
  • Next, I need to modify the Startup.cs file in a couple of places – the first change goes into the Startup method:
public Startup(IHostingEnvironment env)
{
    // For Serilog
    Log.Logger = new LoggerConfiguration()
        .WriteTo.File(@"C:\users\jeremy\Desktop\log.txt")
        .CreateLogger();

The next change goes into the Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddSerilog();

That’s it – after running the project again, I had logs written to the file at C:\users\jeremy\Desktop\log.txt, showing the entry:

2016-03-27 00:01:46.923 +00:00 [Information] Home controller and Index action - logged

Obviously I can also safely remove the NLog packages and configuration that this point.

Conclusion

So you can see the new ASP.NET Core framework has made it super easy to swap out logging library dependencies. A big advantage for me is that the logging interface used by each file is now part of the framework that Microsoft provide, which means my classes aren’t tightly coupled to an implementation.

.net, C# tip, IIS, MVC, Non-functional Requirements, Performance, Web Development

More performance tips for .NET websites which access data

I recently wrote about improving the performance of a website that accesses a SQL Server database using Entity Framework, and I wanted to follow up with a few more thoughts on optimising performance in an MVC website written in .NET. I’m coming towards the end of a project now where my team built an MVC 5 site, and accessed a database using Entity Framework. The engineers were all scarred survivors from previous projects pretty experienced, so we were able to implement a lot of non-functional improvements during sprints as we went along. As our site was data driven, looking at that part was obviously important, but it wasn’t the only thing we looked at. I’ve listed a few of the other things we did during the project – some of these were one off settings, and others were things we checked for regularly to make sure problems weren’t creeping in.

Compress, compress, compress

GZip your content! This makes a huge difference to your page size, and therefore to the time it takes to render your page. I’ve written about how to do this for a .NET site and test that it’s working here. Do it once at the start of your project, and you can forget about it after that (except occasionally when you should check to make sure someone hasn’t switched it off!)

Check your SQL queries, tune them, and look out for N+1 problems

As you might have guessed from one of my previous posts, we were very aware of how a few poorly tuned queries or some rogue N+1 problems could make a site grind to a halt once there were more than a few users. We tested with sample data which was the “correct size” – meaning that it was comparable with the projected size of the production database. This gave us a lot of confidence that the indexes we created in our database were relevant, and that our automated integration tests would highlight real N+1 problems. If we didn’t have “real sized data” – as often happens where a development database just has a few sample rows – then you can’t expect to discover real performance issues early.

Aside: Real sized data doesn’t have to mean real data – anonymised/fictitious data is just as good for performance analysis (and obviously way better from a security perspective).

Use MiniProfiler to find other ADO.NET bottlenecks

Just use it. Seriously, it’s so easy, read about it here. There’s even a nuget repository to make it even easier to include in your project. It automatically profiles ADO.NET calls, and allows you to profile individual parts of your application with a couple of simple lines of code (though I prefer to use this during debugging, rather than pushing those profile customisations into the codebase). It’s great for identifying slow parts of the site, and particularly good at identifying repeated queries (which is a giveaway symptom of the N+1 problem).

Reduce page bloat by optimising your images

We didn’t have many images in the site – but they were still worth checking. We used the Firefox Web Developer Toolbar plugin, and the “View Document Size” item from the “Information” menu. This gave us a detailed breakdown of all the images on the page being tested – and highlighted a couple of SVGs which had crept in unexpectedly. These were big files, and appeared in the site’s header, so every page would have been affected. They didn’t need to be SVGs, and it was a quick fix to change it to a GIF which made every page served a lot smaller.

For PNGs, you can use the PNGOut utility to optimise images – and you can convert GIFs to PNG as well using this tool.

For JPEGs, read about progressive rendering here. This is something where your mileage may vary – I’ll probably write more about how to do this in Windows at a future time.

Minifying CSS and JavaScript

The Web Developer Toolbar saved us in another way – it identified a few JavaScript and CSS files issues. We were using the built in Bundling feature of MVC to combine and minify our included scripts – I’ve written about how to do this here – and initially it looked like everything had worked. However, when we looked at the document size using the Web Developer Toolbar, we saw that some documents weren’t being minified. I wrote about the issue and solution here, but the main point was that the Bundling feature was failing silently, causing the overall page size to increase very significantly. So remember to check that bundling/minifying is actually working – just because you have it enabled doesn’t mean it’s being done correctly!

Remember to put CSS at the top of your page, and include JavaScript files at the bottom.

Check for duplicated scripts and remove them

We switched off bundling and minification to see all the scripts being downloaded and noticed that we had a couple of separate entries for the JQuery library, and also for some JQuery-UI files. These were big files and downloading them once is painful enough, never mind unnecessarily doing it again everytime. It’s really worth checking to make sure you’re not doing this – not just for performance reasons, but if you find this is happening it’s also a sign that there’s maybe an underlying problem in your codebase. Finding it early gives you a chance to fix this.

Do you really need that 3rd party script?

We worked hard to make sure that we weren’t including libraries just for the sake of it. There might be some cool UI feature which is super simple to implement by just including that 3rd party library…but every one of those 3rd party libraries includes page size. Be smart about what you include.

Tools like JQuery UI even allow you to customise your script to be exactly as big or small as you need it to be.

Is your backup schedule causing your site to slow down?

I witnessed this on a previous project – one of our team had scheduled the daily database backup to happen after we went home…leading to some of our users in the world in a later time zone to see a performance deterioration for about half an hour at the same time every day. Rescheduling the daily backup to later in the day caused us no problems and removed a significant problem for our users.

Is someone else’s backup schedule causing your site to slow down?

There’s a corollary to the previous point – if you’re seeing a mysterious performance deterioration at the same time every day and you’re absolutely sure it’s not something that you or your users are doing, check if your site is on shared hosting. When I contacted our hosts and requested that our company VMs were moved onto a different SAN, it miraculously cleared up a long-standing performance issue.

Summary

There’s a few tips here which really helped us keep our pages feeling fast to our users (and some other tips that I’ve picked up over the years). We didn’t do all of this at the end of the project, this was something we focussed on all the way through. It’s really important to make sure you’re checking these things during sprints – and part of your Definition of Done if possible.

.net, C# tip, MVC, Non-functional Requirements, Performance

Performance and MVC tip – Optimize your View Engines

A very quick tip to improve your MVC site’s performance…

If your application only uses one ViewEngine (e.g. Razor), then there’s no point in making MVC iterate through all its registered view engines every time to find a match, when you already know it only needs one.

So make sure you’re only using the Razor view engine by adding the code below to the Application_Start method in your Global.asax.cs file:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new RazorViewEngine());
This should shave a bit of time from your page loads – more in the link here.
C# tip, Clean Code, MVC, Non-functional Requirements, Performance

Performance in ASP.net and C# – Bundling and Minification – Part #2

This is a very quick follow up to my earlier post on bundling and minification – an issue we found and the solution.

While examining the content of the (supposedly) bundled and minified resources, I noticed one of my CSS files wasn’t minified. It had the error message at the top of the file:

/* Minification failed. Returning unminified contents.

(2628,2): run-time error CSS1031: Expected selector, found '@charset'

After some investigation, we found that our CSS files (originally generated using SASS) had a header at the top of each file saying “@charset = ‘utf-8′”.

Removing lines like this allowed the contents to be minified. Deleting the line was fine, as we had the charset defined in our layout page meta data, and therefore this was already in the HTTP Headers for the page.

Hopefully this helps someone out there who’s having the same issue.