Friends Don’t Let Friends Swallow NullReferenceException
Friends Don’t Let Friends Swallow NullReferenceException
If you are using ASP.NET MVC, Core or non-Core, chances are you are swallowing NullReferenceException without you even noticing.
You can see the screenshot of this repro in my previous post (see: Sixth, fixed null model)
How I Boosted 3.3 Minutes Slow ASP.NET MVC 5 Web App Startup to 3 Seconds
Yes, you’re h̸o̸l̸d̸i̸n̸g̸ ̸i̸t̸ ̸w̸r̸o̸n̸g̸ reading it right.
はい、読み間違いではない。
medium.com
But, let’s reproduce this using simple ASP.NET MVC Core program.
First, just create a normal MVC application. Then, add the following action:
public IActionResult Sample()
{
return View();
}
Also, add this new ModelView class.
public class PantsViewModel
{
public string FancyPants { get; set; }
}
Yeah, fancy pants ala Scott Hanselman. I’m a huge fan of his!!
He is amazing! Also, check this out:
I'm Scott Hanselman, ask me anything!
My name is Scott Hanselman. I'm a programmer, teacher, and speaker. I work in Open Source on ASP.NET and the Azure…dev.to
Oh, back to the topic…
Add a new View using Visual Studio dialog, use “Create” as Template, and then choose our newly created SampleViewModel as the Model class, like this:
The result should be like this:
Nothing special here.
It’s just an ordinary View, without those shared layout applied, just for the sake of simplicity. Now press F5 and try to access the page.
There is no exception. Of course.
Now turn on this setting in Visual Studio:
and also this one:
Now, try to access the page again.
NullReferenceException occurred, but it’s swallowed by the framework silently. It is hidden away from us. Even your dog won’t notice it.
We all know that throwing exception is expensive…
Let’s dive into the source code.
Yes, you can see the ASP.NET MVC framework source code by enabling these options:
Restart the debugger by pressing Ctrl+Shift+F5.
Here we go.
Model accessor is trying to access a null container, guarded by catch NullReferenceException clause.
To avoid this hidden NullReferenceException, pass our PantsViewModel to the view, like so:
Wonder what’s PVM? Notice Visual Studio highlights the PantsViewModel? Now I believe you got the idea. Pretty cool, heh? Don’t tell your Mom that I use it a lot.
After specifying our PantsViewModel explicitly, fire our lovely debugger again.
No more exception. We don’t really use the model in this case, but we avoid throwing and catching the exception that takes place behind the scenes. We save a few milliseconds CPU time, resulting in a slightly faster page load.
Quick Benchmark
I did a quick benchmark to see how bad it is to throw an exception. I used this super magnificent awesome splendid wonderful library:
http://benchmarkdotnet.org/
The result:
Obviously, we can see that the winner is DontThrowNRE, both in terms of execution speed and memory allocation that contribute to GC pressure.
So the question is, why the framework is swallowing NullReferenceException?
No null checking?
Is it by design? It’s been there for years since non-Core era. So there must be a reason behind this.
Summary
ASP.NET MVC framework is swallowing NullReferenceException without you even noticing. While it might slow the page load a little bit, it is not that significant. Instead of null, consider to pass your ViewModel object to the view to avoid this problem.
[Update: I asked this on https://github.com/aspnet/Mvc/issues/7378; it is scheduled to be fixed on 2.2.0 milestone]