Dusted Codes

Programming adventures

Thank you Microsoft for being awesome

OK so I have to admit that I can have a pretty big mouth sometimes, which is certainly not a good quality to have. I don't shy away to be (overly) critical if things annoy me:

tweet-0

As you can see, about a year ago I was a little bit upset that a great new product received a not so great new name. I really hoped that ASP.NET Core would have been named something much "cooler" for my taste.

So my frustration continued...

tweet-1

(Let's be honest, it is probably a good thing that I don't have many Twitter followers.)

And even a year later I feel like I am still suffering sometimes:

tweet-2

But I don't care about the name anymore.

Because the product is actually really good.

Yes, the name is still an issue when you google for stuff, and yes, the tooling is still in preview, and yes, the support for F# is not even in RC yet, and yes, there's still lots of other little annoyances which would be nice to have fixed soon, but when I look past all that for a moment then I have to admit that the product is actually really freaking nice.

Being harsh is easy

Often it is very easy to be very quickly critical, but much harder to acknowledge someone's good work. It's already an effort to think about praising people who did a great job at work, let alone praising some third party who you are not even directly related to.

But I think as someone who depends a lot on these third parties, corporations like Microsoft, who own a lot of the tech which I love and use every day, and other contributors from the open source community, then it's important to give back to these people as well.

Particularly with companies like Microsoft many people feel entitled to be overly rude or critical if things don't work out immediately the way they want it to be (and not just Microsoft but really any company of similar size). It is so easy to forget good manners when one is thinking of a big company logo rather than actual human beings, because it is much easier to throw dirt at a logo than a person.

Microsoft_logo

But behind these logos there is still human beings working hard on the products which we use every day and they are not any different from us. Women and men who got into software development and IT for the same good reasons as we did, who share the same passion as we do and who make the same mistakes as us, even when they have only the best in their intention.

Microsoft has made a lot of mistakes in the past (Vista, Windows 8, Silverlight, Windows Phone, Skype, you name it!) and we've not come short to let them know how much these products sucked, but in most recent years they've actually done an amazing turnaround and even taken the lead in some of the most exciting innovations of our field and I am certainly not the only one who has noticed it.

Awesome things by Microsoft

Here's a list of a some of the many awesome things that happened at Microsoft in recent years (in no particular order):

This is a lot of (radical) positive change in a comparatively short amount of time when you think about the size of the company!

For example, check out the Surface Studio introduction video which demonstrates 3D drawing on a Surface Studio:

surface-studio-3d-drawing

You have to admit that this is awesome. I mean I am not even a designer and I get a watery mouth by looking at it.

To be honest the whole Microsoft Surface product series is awesome and I speak from personal experience. Last Black Friday I bought my partner a new Surface Pro 4 (I accidentally spilled a drink over her old laptop) and boy was I impressed with her new device. It's slick, it's fast and when I tried out the drawing with the pencil then my jaw dropped and I was left with pure jealousy (and I say that even though I have a Lenovo Yoga 900 which is a pretty neat device itself).

But that is not even why I am so pleased with Microsoft in recent days. As a .NET developer I am mostly impressed by the work the teams have put into .NET Core, ASP.NET Core, C#, F# and the tooling around it.

.NET Core, ASP.NET Core, F# and Open Source

Especially the ASP.NET Core team led by Scott Hanselman and Damian Edwards is an excellent example of how well Microsoft functions today. Don't get me wrong, I know that ASP.NET Core is still far away from being perfect and that there's still loads of stuff that needs to be done before everyone can use it, but I am still amazed by how far this team has come today.

They have taken a 10+ year old technology, completely revamped it and transitioned from an entirely closed and proprietary product team to one of the most approachable open source contributors that I have ever seen. Not only is their code on GitHub, but they are putting an immense amount of time and effort into keeping a close relationship to the .NET community. They are active on GitHub, Slack, Gitter, Twitter and heck they even live stream a weekly standup where they demo the latest stuff hot from the press, answer live questions to the community, give updates on the current development status and talk about the roadmap. They even spend time going through blog posts written by non-Microsofties where Jon Galloway presents a whole list of community written content at the beginning of each standup. This has become a nice ritual where the Microsoft team gives back to other open source contributors and help nourish a friendly and healthy community.

I find this is amazing work. I don't know many other teams in the world who put this much effort into their open source work.

This is not Microsoft trying to put some code on GitHub and then turning on the #OpenSource marketing machinery. No, this is Microsoft showing the rest of the world how open source is done right (and I am not trying to undermine the open source work by others here, just trying to highlight how well it's done at MSFT).

Also I'd like to point out that this team is doing the difficult balancing act of developing a completely new technology which is supposed to entertain an already existing (and very spoiled) community as well as trying to attract new programmers from the open source field. I guess this is much harder than just launching a new product into the market like Go, Rust or Node.js which didn't have an existing developer base to please.

FSharp

I have been a C# developer for almost the entirety of my professional career and only in the last year I really fell in love with functional programming and F#. For me F# is probably one of the most powerful languages on the market right now. It has the horse power of .NET under the hood with the beauty of a modern functional language on the surface and it has been open source, cross platform compatible and community driven from the very beginning of its time.

So with all of that I've got something to say which was overdue for a while now:

Thank you Microsoft for being awesome!

Seriously, a special thanks to all of the Microsoft teams who work on .NET Core, ASP.NET Core, Visual Studio, Visual Studio Code, C#, F# and the entire goodness around it!!! Your products are awesome and because of your great work I enjoy working in the .NET eco-system more than ever before!

This is not me being sarcastic, I am dead serious, so thank you guys!

I hope when you read this then you know that despite all the negativity that Microsoft has to suck up every now and then that there's also a lot of developers who think you are doing an amazing job and that without you we would be probably some poor suckers who would have to work with Node.js or some other soul destroying technology!

Join me in saying thank you

If you are a .NET developer who loves working with C# or F#, who thinks that Visual Studio (Code) is one of the best IDEs, who thinks that ASP.NET Core and .NET Core are awesome new development stacks then please join me in saying thank you to these guys so that they know that all of their hard work is paying off.

Oh and before someone labels me a Microsoft fanboy or thinks that there's a hidden agenda behind this blog post then let me tell you this:

Sometimes is just feels damn good to be nice.

...something which I would wish programmers would do much more to each other, particularly in such divisive times like today.

Comments

Error Handling in ASP.NET Core

Almost two years ago I wrote a blog post on demystifying ASP.NET MVC 5 error pages and error logging, which became one of my most popular posts on this blog. At that time of writing the issue was that there were an awful lot of choices on how to deal with unhandled exceptions in ASP.NET MVC 5 and no clear guidance or recommendation on how to do it the right way.

Fortunately with ASP.NET Core the choices have been drastically reduced and there is also a much better documentation on the topic itself. However, there's still a few interesting things to consider which I wanted to point out in this follow up blog post and clear up any remaining questions on ASP.NET Core error handling.

ASP.NET Core <> MVC

First I thought it's worth mentioning that the relationship between ASP.NET Core and ASP.NET Core MVC hasn't changed much since what it used to be in Classic ASP.NET.

ASP.NET Core remains the main underlying platform for building web applications in .NET Core while MVC is still an optional web framework which can be plugged into the ASP.NET Core pipeline. It's basically a NuGet library which sits on top of ASP.NET Core and offers a few additional features for the Model-View-Controller design pattern.

What that means in terms of error handling is that any exception handling capability offered by MVC will be limited to MVC. This will become much more apparent when we look at the ASP.NET Core architecture.

ASP.NET Core middleware

ASP.NET Core is completely modular and the request pipeline is mainly defined by the installed middleware in an application.

For better demonstration let's create a new boilerplate MVC application and check out the void Configure(..) method inside the Startup.cs class file:

public void Configure(
    IApplicationBuilder app,
    IHostingEnvironment env,
    ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseIdentity();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Because that is a lot of boilerplate code for a simple web application I'll trim it down to the main points of interest:

app.UseExceptionHandler("/Home/Error");
app.UseStaticFiles();
app.UseIdentity();
app.UseMvc(routes => ...);

What you can see here is fairly self explanatory, but there's a few key things to understand from this code. The app.Use...() (extension-) method calls are enabling several middleware by registering them with the IApplicationBuilder object. Each middleware will be made responsible for invoking the next middleware in the request pipeline, which is why the order of the app.Use...() method calls matter.

For example this is a rough skeleton of the StaticFileMiddleware:

public StaticFileMiddleware(RequestDelegate next, ...)
{
    // Some stuff before

    _next = next;

    // Some stuff after
}

public Task Invoke(HttpContext context)
{
    // A bunch of code to see if this middleware can
    // serve a static file that matches the HTTP request...

    // If not the code will eventually reach this line:
    return _next(context);
}

I cut out some noise to highlight the usage of the RequestDelegate variable.

As you can see each middleware must accept a RequestDelegate object in the constructor and each middleware must implement a method of type Task Invoke(HttpContext context).

The RequestDelegate is, as its name suggest, a delegate which represents the next middleware in the lifecycle. ASP.NET Core defers the responsibility of invoking it to the current middleware itself. For example if the StaticFileMiddleware is not able find a static file which matches the incoming HTTP request then it will invoke the next middleware by calling return _next(context); at the end. On the other hand if it was able to find the requested static file then it will return it to the client and never invoke the next or any subsequent middleware anymore.

This is why the order of the app.Use...() method calls matter. When you think about it the underlying pattern can be seen a little bit like an onion:

aspnet-core-middleware-onion-architecture

A HTTP request will travel from the top level middleware down to the last middleware, unless a middleware in between can satisfy the request and return a HTTP response earlier to the client. In contrast an unhandled exception would travel from the bottom up. Beginning at the middleware where it got thrown it would bubble up all the way to the top most middleware waiting for something to catch it.

In theory a middleware could also attempt to make changes to the response after it has invoked the next middleware, but this is normally not the case and I would advise against it, because it could result in an exception if the other middleware already wrote to the response.

Error handling should be the first middleware

With that in mind it is clear that in order to catch any unhandled exception an error handling middleware should be the first in the pipeline. Only then it can guarantee a final catch if nothing else caught the exception before.

Because MVC is typically registered towards the end of the middleware pipeline it is also clear that exception handling features (like the infamous ExceptionFilters) within MVC will not be able to catch every exception.

For more information on middleware please check out the official documentation.

Custom Exception Handlers

Now that middleware and exception handling hopefully makes sense I also wanted to quickly show how to create your own global exception handler in ASP.NET Core.

Even though there is already quite a few useful exception handlers in the Microsoft.AspNetCore.Diagnostics NuGet package available, it still might make sense to create your own one as well. For example one might want to have an exception handler which logs critical exceptions to Sentry by using Sentry's Raven Client for .NET or one might want to implement an integration with a bug tracking tool and log a new ticket for every NullReferenceException that gets thrown. Another option would be an integration with elmah.io.

There is many good reasons why someone might want to create additional exception handlers and it might even be useful to have multiple exception handlers registered at once. For example the first exception handler logs a ticket in a bug tracking system and re-throws the original exception. Then the next exception handler could log the error in ELMAH and re-trigger the original exception again. The final exception handler might catch the exception and return a friendly error page to the client. By having each exception handler focusing on a single responsibility they automatically become more re-usable across multiple projects and it would also enable to use different combinations on different environments (think dev/staging/production).

A good example of writing your own exception handling middleware is the default ExceptionHandlerMiddleware in ASP.NET Core.

A default exception handler boilerplate would look like this:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace SomeApp
{
    public sealed class CustomExceptionHandlerMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;

        public CustomExceptionHandlerMiddleware(
            RequestDelegate next,
            ILoggerFactory loggerFactory)
        {
            _next = next;
            _logger = loggerFactory.
                    CreateLogger<CustomExceptionHandlerMiddleware>();
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                try
                {
                    // Do custom stuff
                    // Could be just as simple as calling _logger.LogError

                    // if you don't want to rethrow the original exception
                    // then call return:
                    // return;
                }
                catch (Exception ex2)
                {
                    _logger.LogError(
                        0, ex2, 
                        "An exception was thrown attempting " + 
                        "to execute the error handler.");
                }

                // Otherwise this handler will
                // re -throw the original exception
                throw;
            }
        }
    }
}

In addition to the RequestDelegate the constructor also accepts an ILoggerFactory which can be used to instantiate a new ILogger object.

In the Task Invoke(HttpContext context) method the error handler basically does nothing other than immediately calling the next middleware. Only if an exception is thrown it will come into action by capturing it in the catch block. What you put into the catch block is up to you, but it would be good practice to wrap any non trivial code in a second try-catch block and default back to basic logging if everything else is falling apart.

I hope all of this made sense and that this blog post was useful again. Personally I find it extremely nice to see how well ASP.NET Core has evolved from its predecessor. If you have any more questions just drop me a comment below.

Comments

Older Posts Newer Posts