Prettier + Format On Save = Never worry about formatting JavaScript again

Last updated: 2019-5-13

In my last post, I mentioned a tip to using the Format on Save option in VS Code.  I’d like to take that one step further and mention how you can combine that with the Prettier – Javascript Formatter plugin for VS Code to make a really nice editing experience.

What is Prettier?

Prettier is an open source project (originally started by James Long) that is an opinionated JavaScript formatter.  Prettier takes JavaScript code in, runs some of its formatting rules against it, and then spits out that JavaScript code with its formatting rules applied.

One of the things I love about it is it’s not completely rigid with its rules.  It makes some “logical” choices that I would make myself.  For instance, Prettier will make a short const array declaration a one liner, but a declaration with a bunch of items in the array, it will split out into multiple lines to avoid horizontal scrolling (see demo GIF at the end).  I love that.

While I only mentioned JavaScript so far, technically Prettier can do more than just JavaScript.  It can do CSS, LESS, SASS, TypeScript, JSX, Markdown, and more as well.

VS Code Integration

The Prettier -JavaScript Formatter plugin for VS Code simply shells out to Prettier.  It also respects the Format on Save option I mentioned in my last blog post.

Note: Make sure you have prettier installed in the project you’re working in or globally via npm install prettier -g

Format on Save in VS Code

To enable Format on Save in VS Code:

  1. File
  2. Preferences
  3. Settings
  4. Search for Format On Save and check the box

formatOnSave

Overriding Prettier settings

By default Prettier uses 2 spaces for your tab width for indenting your code.  You can increase that to the VS Code default of 4 if you want extremely easily.

  1. Add a .prettierrc file in the root of your project next to your package.json
  2. Add a new object with a tabWidth property and a value of 4
    1. prettierrc
  3. Note how VS Code gives autocompletion for the different settings within Prettier.  How awesome is that!?!
  4. Now start saving your files and watch Prettier in action.

Note: you can configure these settings directly in VS Code as well without a config file, but I think it’s better to use a .prettierrc file, especially when you’re on a team.  That way anytime you or someone else works on that codebase, everyone is using the same settings.

The rest of the Prettier configuration options can be found here.

Formatting is something I never worry about anymore

I find when using Prettier, along with the Format On Save option in VS Code, I don’t think about how to format my code anymore.  I don’t ever wonder “oh should I put this on multiple lines or keep it all in one line?”  Instead, I focus on solving my problem, hit Save and let Prettier do the rest.  It’s shocking how liberating this is.  I end up with consistent formatting across my entire project instead of just doing whatever I felt was best at the time.

Prettier in Action

Prettier

Enforcing Prettier

If you’d like to learn more about how to enforce Prettier via git commit hooks, checkout my blog post on Husky and Lint Staged with Prettier that even works with nested folders.

Quick Visual Studio Tip – Delete to End of Line

There are tons of times where you want to delete from the right of your cursor, while preserving everything to the left of your cursor.

Today the most common way is to do SHIFT + END to highlight it all and then hit DEL, such as below.

endoflinedelete

However, there’s a way to delete to the end of the line by binding a keyboard shortcut to Edit.DeleteToEOL.  By default this is not bound to any keyboard shortcut, so you’ll have to pick one.

If you haven’t overrode a keyboard shortcut before, you can go to Tools => Options => Keyboard, and then type Edit.DeleteToEOL in the “Show commands containing” text box.  You can then type a keyboard

I removed all previous bindings to CTRL + L and bound Edit.DeleteToEOL to that, but you can pick whatever you want.

2017-05-29_14-37-42

Now when I hit CTRL + L it removes everything after my cursor, saving me some keyboard strokes.

endoflinedelete2

Hope this helps.

Using the Microsoft.AspNetCore.HealthChecks Package

Updated 7/17/2018: This package will be released in ASP.NET Core 2.2 which is going to come out in Q4 2018 currently.

CAVEAT: This is pre-released software.  There isn’t even a NuGet package for it yet.  The GitHub repo lives here – https://github.com/dotnet-architecture/HealthChecks that I cloned and manually added a project reference to a new demo app.  There is a plan for it to get made into a NuGet package, but that hasn’t happened yet.

With that said – I will keep this post updated as I see changes being made, and will eventually remove the Caveat above.

tldr;

Register your Health Checks in your ConfigureServices method.


public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks(checks =>
{
checks.AddUrlCheck("https://github.com");
checks.AddSqlCheck("Local DB Check", "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplication1;Trusted_Connection=True;MultipleActiveResultSets=true");
});
services.AddMvc();
}

view raw

Startup.cs

hosted with ❤ by GitHub

Inject in an IHealthCheckService and call CheckHealthAsync to run all your Health Checks, or another method like RunCheckAsync or RunGroupAsync to run a subset of the Health Checks you registered in ConfigureServices.


[Route("api/[controller]")]
public class HealthCheckController : Controller
{
private readonly IHealthCheckService _healthCheckService;
public HealthCheckController(IHealthCheckService healthCheckService)
{
_healthCheckService = healthCheckService;
}
[HttpGet]
public async Task<IActionResult> Get()
{
// Can also call RunCheckAsync to run a single Heatlh Check or RunGroupAsync to run a group of Health Checks
CompositeHealthCheckResult healthCheckResult = await _healthCheckService.CheckHealthAsync();
bool somethingIsWrong = healthCheckResult.CheckStatus != CheckStatus.Healthy;
if (somethingIsWrong)
{
// healthCheckResult has a .Description property, but that shows the description of all health checks.
// Including the successful ones, so let's filter those out
var failedHealthCheckDescriptions = healthCheckResult.Results.Where(r => r.Value.CheckStatus != CheckStatus.Healthy)
.Select(r => r.Value.Description)
.ToList();
// return a 500 with JSON containing the Results of the Health Check
return new JsonResult(new {Errors = failedHealthCheckDescriptions}){ StatusCode = StatusCodes.Status500InternalServerError };
}
return Ok();
}
}

What is a Health Check?

Health Checks are pretty much what the name implies.  They are a way of checking to see if your application is healthy.  Health Checks have become especially critical as more and more applications are moving to a microservice-style architecture.  While microservice architectures have many benefits, one of the downsides is there is a higher operations overhead to ensuring all of these services are running.  Rather than monitoring the health of one majestic monolith, you need to monitor the status of many different services, which are usually responsible for one thing and one thing only.  Health Checks are usually used in combination with a service discovery tool such as Consul that monitor your microservices for when they become healthy and unhealthy.  If you use Consul for service discovery as well, Consul will automatically route traffic away from your unhealthy microservices and only serve traffic to your healthy microservices… which is awesome.

 

How do I implement a Health Check?

There are a few different ways to do Health Checks, but the most common way is exposing an HTTP endpoint to your application dedicated to doing Health Checks.  Typically you will return a status code of 200 if everything is good, and any non-2xx code means something went wrong.  For example, you might return a 500 if something went wrong along with a JSON payload of what exactly went wrong.

 

Common scenarios to Health Check

What you Health Check will be based on what your application/microservice does, but some common things:

  • Can my service connect to a database?
  • Can my service query a 3rd party API?
    • Likely making some read-only call
  • Can my service access the file system?
  • Is the Memory and/or CPU above a certain threshold?

 

Looking at the Microsoft.AspNetCore.HealthChecks package

Microsoft is on the verge of shipping a set of Health Check packages to help you solve this problem in a consistent way.  If you look in the GitHub repo you will notice there is also a package for ASP.NET 4.x as well under the Microsoft.AspNet.HealthChecks namespace.  There is a samples folder on that GitHub repo that contains how to wire that up if you’re interested in ASP.NET 4.x.  I’m going to focus on the ASP.NET Core package for this blog post.

The Microsoft.AspNetCore.HealthChecks package targets netcoreapp1.0, but I suspect this will change to be either netcoreapp2.0 or netstandard2.0 by the time this RTM’s.  The ASP.NET 4 project targets net461, and all the other libraries target netstandard1.3which works with both .NET Core and Full Framework.

 

Getting Started

The basic flow is that you register your health checks in your IoC container of choice (such as the built-in Microsoft one, although I prefer SimpleInjector due to the fantastic feature set, blazing speed, and ridiculously good documentation, but I’ll just use the built-in one for these demos).  You register these Health Checks via a fluent HealthCheckBuilder API in your Startup‘s ConfigureServices method.  This HealthCheckBuilder will build a HealthCheckService and register it as an IHealthCheckService​ in your IoC container.

That looks something like this:


public void ConfigureServices(IServiceCollection services)
{
// Creates a HealthCheckBuilder and registers an IHealthCheckService in the IServiceCollection/IoC Container
services.AddHealthChecks(checks =>
{
// Register health checks here
});
services.AddMvc();
}

view raw

Startup.cs

hosted with ❤ by GitHub

 

So to run your Health Checks you inject in an IHealthCheckService into your Controller and then call CheckHealthAsync.


[Route("api/[controller]")]
public class HealthCheckController : Controller
{
private readonly IHealthCheckService _healthCheckService;
public HealthCheckController(IHealthCheckService healthCheckService)
{
_healthCheckService = healthCheckService;
}
[HttpGet]
public async Task<IActionResult> Get()
{
// Can also call RunCheckAsync to run a single Heatlh Check or RunGroupAsync to run a group of Health Checks
CompositeHealthCheckResult healthCheckResult = await _healthCheckService.CheckHealthAsync();
bool somethingIsWrong = healthCheckResult.CheckStatus != CheckStatus.Healthy;
if (somethingIsWrong)
{
// healthCheckResult has a .Description property, but that shows the description of all health checks.
// Including the successful ones, so let's filter those out
var failedHealthCheckDescriptions = healthCheckResult.Results.Where(r => r.Value.CheckStatus != CheckStatus.Healthy)
.Select(r => r.Value.Description)
.ToList();
// return a 500 with JSON containing the Results of the Health Check
return new JsonResult(new {Errors = failedHealthCheckDescriptions}){ StatusCode = StatusCodes.Status500InternalServerError };
}
return Ok();
}
}

 

There are a few things to note here:

  1. You get back a CompositeHealthCheckResult which is a summary of all of your health checks that you registered in your AddHealthChecks method in your Startup class.
  2. That CompositeHealthCheckResult class has a CheckStatus property which is an enum.  That enum has 4 options – Healthy, Unhealthy, Warning, and Unknown. You can determine what you want to do with each of those.  In my simple example above, I consider anything other than Healthy to be a problem and return a 500 if it’s not Healthy.

 

You can also loop over the results of the CompositeHealthCheckResult by looking at the Results property and get even more detail about what exactly happened.

You can optionally run a single Health Check by calling RunCheckAsync and supplying the name of the Health Check that you registered in your ConfigureServices method (more on that later).

 

Out of the box Health Checks

Microsoft ships quite a few Health Checks out of the box that fit into the Common Scenarios section above.  They are:

  • URL Health Check via AddUrlCheck
  • SQL Server Health Check via AddSqlCheck
  • PrivateMemorySizeCheck via AddPrivateMemorySizeCheck
  • VirtualMemorySizeCheck via AddVirtualMemorySizeCheck
  • WorkingSetCheck via AddWorkingSetCheck
  • A few Azure Health Checks (such as BLOB Storage, Table Storage, File Storage, and Queue storage).

Let’s take a look at the URL Health Check and the SQL Server Health Check.

 

URL Health Checks

The URL Health Check lets you specify a URL and then it will execute a GET to that URL and see if the URL returns a Success Status Code or not (any 2xx Status Code like 200).

You can register the URL Health Check by adding this.


public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks(checks =>
{
// First parameter is the URL you want to check
// The second parameter is the CacheDuration of how long you want to hold onto the HealthCheckResult
// The default is 5 minutes, and in my case, I don't really want any cache at all
// because I don't want to wait up to 5 minutes if my service goes down to be notified about it
checks.AddUrlCheck("https://github.com&quot;, TimeSpan.FromMilliseconds(1));
});
services.AddMvc();
}

view raw

Startup.cs

hosted with ❤ by GitHub

Then you inject your IHealthCheckService and call CheckHealthAsync as shown above.  If you want to just run this single Health Check, and not others you may have registered, you’ll need to know that the name is not configurable.  The name will be UrlCheck(https://github.com)​.  So you would run that single check with  RunCheckAsync("UrlCheck(https://github.com)").

Another thing to note, that second parameter where I’m passing TimeSpan.FromMilliseconds(1) is the CacheDuration of the HealthCheckResult.  The default is 5 minutes.  So if you have some other service (like Consul) pinging your Health Check endpoint every minute, the HealthCheckResult will be the same for 5 minutes until the CacheDuration expires.  To me, that doesn’t make a ton of sense, and I don’t want to risk an up to 5 minute delay on being notified when my service becomes unhealthy.  So by only adding a 1 millisecond cache, I’m effectively adding no caching at all.

There is also another parameter to the AddUrlCheck method where you can pass a Func to the URL Checker.  This is nice in scenarios such as:

  • You want to execute something other than a GET.
  • You need to do something special with the HttpRequest in general such as add Auth Headers or something.
  • You want to validate the response’s Content contains some specific words or HTML.

So the URL Check should satisfy just about any Web check you could possibly want to do with that flexibility.

 

Built-in SQL Server Health Checks

The SQL Check lets you specify a name and a connection string to connect to.


public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks(checks =>
{
// Local DB Check is just the name of the Health Check. You can call it whatever you want.
checks.AddSqlCheck("SQL DB Check", "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplication1;Trusted_Connection=True;MultipleActiveResultSets=true");
});
services.AddMvc();
}

view raw

Startup.cs

hosted with ❤ by GitHub

The first parameter, “SQL DB Check”, is just the name I chose.  You can make it whatever makes sense to you.  To run this check, as mentioned above, you would call this from IHealthCheckService.

 

Making your own custom Health Check

You can of course make your own custom Health Check.  For me, most of my use cases are solved by the built-in ones, as I’m usually checking if an API is available (which I could do with the URL Check and overriding the checkFunc parameter) or I’m checking to see if a SQL Server is available.  But you could implement your own if you are missing some functionality that you need such as checking if another DB store is available or how much free space a drive has.

To do that, derive from IHealthCheck and implement the interface.  Below is an example of one that checks to make sure the C drive has at least 1 GB of free space.


public class CDriveHasMoreThan1GbFreeHealthCheck : IHealthCheck
{
public ValueTask<IHealthCheckResult> CheckAsync(CancellationToken cancellationToken = default(CancellationToken))
{
long freeSpaceinGb = GetTotalFreeSpaceInGb(@"C:\");
CheckStatus status = freeSpaceinGb > 1 ? CheckStatus.Healthy : CheckStatus.Unhealthy;
return new ValueTask<IHealthCheckResult>(HealthCheckResult.FromStatus(status, $"Free Space in GB: {freeSpaceinGb}"));
}
private long GetTotalFreeSpaceInGb(string driveName)
{
foreach (DriveInfo drive in DriveInfo.GetDrives())
{
if (drive.IsReady && drive.Name == driveName)
{
return drive.TotalFreeSpace / 1024 / 1024 / 1024;
}
}
throw new ArgumentException($"Invalid Drive Name {driveName}");
}
}

Then in your ConfigureServices method, register the custom Health Check with the lifestyle that makes sense for the Health Check (Singleton, Scoped, Transient, etc.) and then add it to the AddHealthChecks registration that we’ve done before.


public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<CDriveHasMoreThan1GbFreeHealthCheck>();
services.AddHealthChecks(checks =>
{
checks.AddCheck<CDriveHasMoreThan1GbFreeHealthCheck>("C Drive has more than 1 GB Free");
});
services.AddMvc();
}

view raw

Startup.cs

hosted with ❤ by GitHub

That’s it!

 

Group your health checks together

You can group your health checks together in a HealthCheckGroup if you want (such as all performance checks like CPU, Memory, Disk Space, etc. go under a group called “performance”) or you can let them live on their own and mix and match.


public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<CDriveHasMoreThan1GbFreeHealthCheck>();
services.AddHealthChecks(checks =>
{
checks.AddUrlCheck("https://github.com&quot;)
.AddSqlCheck("Local DB Check", "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplication1;Trusted_Connection=True;MultipleActiveResultSets=true")
.AddHealthCheckGroup("performance",
group => group.AddPrivateMemorySizeCheck(1000)
.AddVirtualMemorySizeCheck(1000)
.AddWorkingSetCheck(1000)
.AddCheck<CDriveHasMoreThan1GbFreeHealthCheck>("C Drive has more than 1 GB Free"),
CheckStatus.Unhealthy
);
});
services.AddMvc();
}

view raw

Startup.cs

hosted with ❤ by GitHub

This enables you to do things like only call that Group of Health Checks via the RunGroupAsync method off of IHealthCheckService.

 

Security

Reminder – this is demo code.  Some flaws include that my Health Check endpoint is unsecured and anyone can hit the endpoint.  You will likely want to secure your Health Check endpoint, especially if it is on the Internet, so someone doesn’t spam your Health Check endpoint.  There are many ways to do this, but are outside the scope of this blog post.

 

Some Feedback on the Design

Overall I think this abstraction is really useful, and I will use it myself once it RTM’s.  The built-in health checks are nice, so that you don’t have to write that logic yourself.  I’m all about punting as much logic onto someone else as possible.

There are some little things I wish were a little easier though.

  1. It seems like the HealthCheckResult.CheckStatus == CheckStatus.Healthy code  is going to be extremely common.  It’d be nice if there was a helper prop off of HealthCheckResult like HealthCheckResult.IsHealthy which does that computation for you.  Much like HttpResponseMessage has a IsSuccessStatusCode property which is super useful.  Although, I understand that “Healthy” is a relative term that’s tough to globally define.  Some people might think that the CheckStatus.Warning would qualify as being Healthy and others wouldn’t.  Ubiquitous languages are hard.
  2. I wish there was a way you could override the name for the built-in Health Checks.  Like the URL Health Check automatically takes on the Name UrlCheck(yourUrlHere) such as UrlCheck(http://google.com).  You’ll need this name if you want to pull out the specific results of a Health Check.  I had expected to be able to specify the name of each Health Check and store it in something like a HealthCheckConstants class for easily retrieval.  Instead, I need to follow this convention when using the constants class, which isn’t the end of the world, but being able to override the name would be nice.
  3. When calling the RunGroupAsync method, I wish you could just specify the group name rather than the HealthCheckGroup instance and let the RunGroupAsync method handle getting the HealthCheckGroup instance.
  4. There should be no Cache Duration on the URL Check.  5 minutes is just too long of a default, and IMO there should be no Cache Duration at all on the URL Check.  I control the frequency of how often my Health Check monitoring service hits my health check endpoint.  If I want it to check my service every minute, then I’d probably expect the Health Check result to be fresh every time and not be cached.

 

Overall, I really like this package, and it seems like it’s going to be really useful.   I plan on using this when it RTM’s, so I’ll keep this post up to date when I see they make changes to this package.

How to troubleshoot: “An error occurred while starting the application” in ASP.NET Core on IIS

The Problem

If you’ve ever seen this message when hitting your ASP.NET Core app:

“An error occurred while starting the application.  .NET Framework <version number> | Microsoft.AspNetCore.Hosting version <version number> | Microsoft Windows <version number>”

It looks a little something like this:

2017-04-07_15-20-55

 

What Happened?

It basically means something really bad happened with your app.  Some things that might have gone wrong:

  1. You might not have the correct .NET Core version installed on the server.
  2. You might be missing DLL’s
  3. Something went wrong in your Program.cs or Startup.cs before any exception handling kicked in

 

Event Viewer (probably) won’t show you anything

If you’re running on Windows and behind IIS, you might immediately go to the Event Viewer to see what happened based on your previous ASP.NET knowledge.  You’ll notice that the error is not there.  This is because Event Logging must be wired up explicitly and you’ll need to use the Microsoft.Extensions.Logging.EventLog package, and depending on the error, you might not have a chance to even catch it to log to the Event Viewer.

 

How to figure what happened (if running on IIS)

Instead of the Event Viewer, if you’re running behind IIS, we can log the request out to a file.  To do that:

  1. Open your web.config
  2. Change stdoutLogEnabled=true
  3. Create a logs folder
    1. Unfortunately, the AspNetCoreModule doesn’t create the folder for you by default
      1. If you forget to create the logs folder, an error will be logged to the Event Viewer that says: Warning: Could not create stdoutLogFile \\?\YourPath\logs\stdout_timestamp.log, ErrorCode = -2147024893.
    2. The “stdout” part of  the value “.\logs\stdout” actually references the filename not the folder.  Which is a bit confusing.
  4. Run your request again, then open the \logs\stdout_*.log file


Note – you will want to turn this off after you’re done troubleshooting, as it is a performance hit.

So your web.config’s aspNetCore element should look something like this

 <aspNetCore processPath=”.\YourProjectName.exe” stdoutLogEnabled=”true” stdoutLogFile=”.\logs\stdout” />

 

Doing this will log all the requests out to this file and when the exception occurs, it will give you the full stack trace of what happened in the \logs\stdout_*.log file

2017-04-07_15-35-45.png

 

2017-04-07_15-42-40.png

 

 

Hope this helps.  This happened to me a friend of mine.  A friend.  Yep.  Definitely not me.  My apps would never bomb.

Error Upgrading to Visual Studio 2017 15.1 Unable to do .NET Core/ASP.NET Core Development

UPDATE: Looks like this was fixed on 4/10/17 in the Update 1 26403.03 Release Notes.  I would just upgrade to get the fix.

I got an error when upgrading to Visual Studio 2017 15.1 where it wouldn’t install the .NET Core workload.  This prevented me from opening ASP.NET Core projects.

The product failed to install the listed workloads and components due to one or more package failures.

Incomplete workloads .NET Core cross-platform development (Microsoft.VisualStudio.Workload.NetCoreTools,version=15.0.26323.1) ASP.NET and web development (Microsoft.VisualStudio.Workload.NetWeb,version=15.0.26323.1)

Incomplete components .NET Core 1.0 – 1.1 development tools (Microsoft.NetCore.ComponentGroup.Web,version=15.0.26208.0) .NET Core 1.0.1 development tools (Microsoft.Net.Core.Component.SDK,version=15.0.26208.0) Container development tools (Microsoft.VisualStudio.Component.DockerTools,version=15.0.26323.1)

You can search for solutions using the information below, modify your selections for the above workloads and components and retry the installation, or remove the product from your machine.

Following is a collection of individual package failures that led to the incomplete workloads and components above. To search for existing reports of these specific problems, please copy and paste the URL from each package failure into a web browser. If the issue has already been reported, you can find solutions or workarounds there. If the issue has not been reported, you can create a new issue where other people will be able to find solutions or workarounds.

Package ‘Microsoft.Net.Core.SDK,version=15.0.26323.1,chip=x64’ failed to install. Search URL: https://aka.ms/VSSetupErrorReports?q=PackageId=Microsoft.Net.Core.SDK;PackageAction=Install;ReturnCode=1638 Impacted workloads .NET Core cross-platform development (Microsoft.VisualStudio.Workload.NetCoreTools,version=15.0.26323.1) ASP.NET and web development (Microsoft.VisualStudio.Workload.NetWeb,version=15.0.26323.1) Impacted components .NET Core 1.0 – 1.1 development tools (Microsoft.NetCore.ComponentGroup.Web,version=15.0.26208.0) .NET Core 1.0.1 development tools (Microsoft.Net.Core.Component.SDK,version=15.0.26208.0) Container development tools (Microsoft.VisualStudio.Component.DockerTools,version=15.0.26323.1) Log C:\Users\scotts\AppData\Local\Temp\dd_setup_20170406164409_003_Microsoft.Net.Core.SDK.log Details Command executed: “C:\ProgramData\Microsoft\VisualStudio\Packages\Microsoft.Net.Core.SDK,version=15.0.26323.1,chip=x64\dotnet-dev-win-x64.1.0.2.exe” “C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise” /log “C:\Users\scotts\AppData\Local\Temp\dd_setup_20170406164409_003_Microsoft.Net.Core.SDK.log” /quiet /norestart Return code: 1638 Return code details: Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove Programs on the Control Panel.

 

I ended up fixing this by:

  1. Repairing Microsoft Visual C++ 2017 x64, then rebooting.
  2. Repairing Microsoft Visual C++ 2017 x86, then rebooting.
  3. Installing the missing features by opening up a ASP.NET Core project and right-clicking and clicking “Install Missing Features.”  I’m sure you can get there by “modifying” the VS 2017 installation as well.

 

Hope this helps someone.

Quick xUnit Test Tip – Use xunit.methodDisplay to Clean Up Your Test Results

I recently discovered an xUnit configuration value that was super helpful, so thought I’d write up a quick blog post.

Out of the box, xUnit results look like this in Visual Studio Test Explorer:

xUnitBefore

 

About half of that is noise, specifically the namespace (xUnitDemo) and the class name (DrivingServiceIsValidAgeToDrive).  The namespace isn’t really relevant to the test, and the class name is already available as the parent node above all the tests.

Solution

A simple change to your app.config will make this much easier to read.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="xunit.methodDisplay" value="method"/>
  </appSettings>
</configuration>

 

Now when we run we get this:

xUnitAfter

Much cleaner.

 

As an aside.  I prefer the naming convention of:

  • Test Class Name: <ClassYou’reTesting><MethodYou’reTesting>
    • Example above, DrivingService is the class and IsValidAgeToDrive is the method
  • Test Method Name: Does<Something>_Given<Scenario>
    • Example above, DoesReturnTrue_GivenAgeIs16OrOlder

 

I’ve found this helps make it crystal clear what you’re testing.  As a bonus, it makes it fairly easy to show the names to a BA/Stakeholder to make sure you’re covering all their scenarios.

Adding Global Error Handling and Logging in ASP.NET Core with IExceptionHandlerPathFeature

tldr;

In ASP.NET Core you can hook up a route to be your global exception handler.  Simply add the ExceptionHandler middleware to your Startup.cs Configure method:


// when an exception occurs, route to /Home/Error
app.UseExceptionHandler("/Home/Error");

view raw

Startup.cs

hosted with ❤ by GitHub

In your HomeController’s Error action, add this code to get the exception that was raised, as well as the route that caused the exception, and then you can do something with it (log to a database, send an email/text/fax/carrier pidgeon).


using System;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
namespace GlobalExceptionHandling.Controllers
{
public class HomeController : Controller
{
public IActionResult Error()
{
// Get the details of the exception that occurred
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionFeature != null)
{
// Get which route the exception occurred at
string routeWhereExceptionOccurred = exceptionFeature.Path;
// Get the exception that occurred
Exception exceptionThatOccurred = exceptionFeature.Error;
// TODO: Do something with the exception
// Log it with Serilog?
// Send an e-mail, text, fax, or carrier pidgeon? Maybe all of the above?
// Whatever you do, be careful to catch any exceptions, otherwise you'll end up with a blank page and throwing a 500
}
return View();
}
}
}

You can checkout this GitHub commit if you’d prefer to see it that way.

 

The start of the non-tldr;

No ELMAH in ASP.NET Core… yet

In pre-Core versions of ASP.NET, ELMAH was a popular library for doing Global Exception Handling.  When unhandled exceptions occurred, it let you do things like log them to a database, send an e-mail, etc. automagically.  Unfortunately, ELMAH is not ported to ASP.NET Core yet, so this led me to look at what other options were out there.

You could use one of the many of the Cloud providers for this like Application Insightselmah.io (unaffiliated with the ELMAH project) or Exceptionless, but what if your company requires you to stay on-prem?  You can use Exception Filters, but those have some limitations, and I found a simpler way (arguably) that I didn’t find a blog post on, so I thought I’d write one up.

 

Step 1 – Hook up the ExceptionHandler middleware

If you’ve done much with ASP.NET Core, this will look very familiar to you.  First you need to hook up the ExceptionHandler middleware by adding this line to the Configure method of your Startup.cs:


// when an exception occurs, route to /Home/Error
app.UseExceptionHandler("/Home/Error");

view raw

Startup.cs

hosted with ❤ by GitHub

What that does is anytime an uncaught exception happens, it will send the request to the route listening on the path you  specified.  In the example above (and the default in the templates), that’s the Error Action on the Home Controller, obviously you can just change that to whatever you want.

Often, you’ll only want to use the Exception Handler in non-development environments, and instead use the DeveloperExceptionPage in Development, which is the new YSOD that gives you a stack trace and other good information.

A sample Configure method showing this is below:


public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// other code removed for brevity
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// when an exception occurs, route to /Home/Error
app.UseExceptionHandler("/Home/Error");
}
// other code removed for brevity
}

view raw

Startup.cs

hosted with ❤ by GitHub

 

Step 2 – Use IExceptionHandlerPathFeature to get the exception and the Path

Make sure you have the Microsoft.AspNetCore.Diagnostics NuGet package in your .csproj, or if you have the Microsoft.AspNetCore meta-package, then that contains the Microsoft.AspNetCore.Diagnostics package, so you’re all set.

In the action of the controller you’re listening on (in the above case, the Error action on the Home Controller).  Add the following code to your Error action.


using System;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
namespace GlobalExceptionHandling.Controllers
{
public class HomeController : Controller
{
public IActionResult Error()
{
// Get the details of the exception that occurred
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionFeature != null)
{
// Get which route the exception occurred at
string routeWhereExceptionOccurred = exceptionFeature.Path;
// Get the exception that occurred
Exception exceptionThatOccurred = exceptionFeature.Error;
// TODO: Do something with the exception
// Log it with Serilog?
// Send an e-mail, text, fax, or carrier pidgeon? Maybe all of the above?
// Whatever you do, be careful to catch any exceptions, otherwise you'll end up with a blank page and throwing a 500
}
return View();
}
}
}

Breaking the code down

The code is pretty straight forward, but let’s break it down.  When an exception occurs, an IExceptionHandlerPathFeature is set.  This contains two properties: 1) the Path of the route at which the exception occurred (such as /Home/Index), and 2) the Exception that occurred under the Error property.  After that, you can do whatever you want with this information such as log it to a database, send an e-mail or trigger a carrier pidgeon (I believe the CarrierPidgeon API is coming back in .NET Standard 2.0).

If you want to see the code that makes IExceptionHandlerPathFeature work, you can view go to GitHub here and see the code where they set the Path in the ExceptionHandler middleware that we rigged up in our Startup class.

 

Make sure you get the right Feature

Be careful to make sure you get an IExceptionHandlerPathFeature with the Path in the name.  There is also a IExceptionHandlerFeature without Path in the name that does not have the Path of where the exception occurred.  Obviously, it’s pretty useful to know the source route of where the exception happened.

 

Make sure you catch any Exceptions in your Exception Handler Action

Also be careful and make sure to catch any exceptions in your Exception Handler Action.  Causing a second exception in your exception handler action will cause the entire middleware to stop and you’ll end up with a blank page and a 500 status code.  A scenario where this could happen is if you’re logging the exception to a database, but your database is down causing an exception.

 

Microsoft.AspNetCore.Diagnostics.Elm

Microsoft provides a package called ELM (Error Logging Middleware) that has some similar features to what ELMAH did.  One of the main features ELM has is it allows you to see events on a web page that aggregates those events.  You can read more about that here.  However, there doesn’t seem to be any intent to extend ELM to do things like report to a database or send e-mails, based on this response from Eilon of the ASP.NET team here, and it is non-persistent through app restarts.  In my scenarios, we don’t have a ton of use for this, as we prefer to be able to look and query for logs in a database, but I thought I’d mention it in case it is useful for your scenarios.

 

Additionally – AppDomains Coming Back in .NET Standard 2.0

If you’re using .NET Core (and not full framework), AppDomains are coming back in .NET Standard 2.0 to help with global exception handling, as described by Damian Edwards in the ASP.NET Community Standup here: https://youtu.be/_3y0QsXj2e4?t=31m17s 

 

Don’t like using IExceptionHandlerPathFeature in your Controller action?

That’s ok.  There’s another way to achieve this same thing using raw middleware, even bypassing IExceptionHandlerPathFeature completely, but I’ll save that for a followup blog post, as this is approaching 1000 words.

Thanks for reading!

Precompiling MVC Views in ASP.NET Core with .csproj’s

Update 8/29/2017: 

When running ASP.NET Core 2:

  • Using .NET Core 2
    • You no longer have to do anything.  The app will precompile by default on publish.
  • Using full .NET Framework
    • The only thing you need is the package reference below.


<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.0.0" PrivateAssets="All" />

 

Below is the original post for ASP.NET Core 1

 

I didn’t see this documented on docs.asp.net yet for .csproj style projects, so I thought I’d blog about it, as it’s something I do on every project.

tldr;

Add this to your .csproj file:

2017-03-10_13-02-21.png

Alternatively, you can check out this GitHub commit that just adds pre-compiled views here.

Also – if you’re running on .NET Core and not Full Framework, then make sure your TargetFramework is netcoreapp1.1+ and not netcoreapp1.0.

What does precompiling views do?

Without precompiling your views, none of your views are compiled until they are requested for the first time.  This results in an extra few seconds of wait time for the end user.  Instead, most developers want to take a little bit of extra time in the publish step to precompile their views, so that users don’t have to eat that performance hit on the first request on every page.

Another benefit of precompiling your views is if there is a C# error on one of your .cshtml Razor pages (such as you changed the name of a property on your View Model and the rename didn’t update your .cshtml file), you will find out up front when you go to publish (via VS or a build server) rather than at run time when a user goes to request that page.

So now that we’ve seen what it does, let’s look at what it used to be in project.json.

What did it look like in project.json?

In project.json land, the pre-compiling of Views was a little verbose.  You had to do the following:

  1. Add a reference to “Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Design” under the “dependencies” section
  2. Add a reference to “Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Tools” under the tools section.
  3. Under buildOptions, set “preserveCompilationContext”to true
  4. And finally you had to add a fairly verbose post-publish script to actually use the pre-compile tool.All of that looked like this (removing the rest of the project.json for brevity):


{
"dependencies": {
"Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Design": {
"version": "1.1.0-preview4-final",
"type": "build"
}
},
"tools": {
"Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Tools": "1.1.0-preview4-final"
},
"buildOptions": {
"preserveCompilationContext": true
},
"scripts": {
"postpublish": [
"dotnet razor-precompile –configuration %publish:Configuration% –framework %publish:TargetFramework% –output-path %publish:OutputPath% %publish:ProjectPath%"
]
}
}

view raw

project.json

hosted with ❤ by GitHub

This then generates a .PrecompiledViews.dll in the root of your publish directory.  You will have no refs folder as well.

How does it look in .csproj?

In project.json, it was pretty verbose.  So what does it look like in .csproj?  It’s much cleaner.

  1. Add <MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish>
  2. Add <PackageReference Include=Microsoft.AspNetCore.Mvc.Razor.ViewCompilation Version=1.1.0 />

 

So the final output of a .csproj might look a little something like this.  Note lines 5,6, and 32.


<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish>
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>
<PropertyGroup>
<PackageTargetFallback>$(PackageTargetFallback);portable-net45+win8+wp8+wpa81;</PackageTargetFallback>
</PropertyGroup>
<PropertyGroup>
<UserSecretsId>aspnet-WebApplication2-59d1bc3a-42e0-4a81-940b-ce5e3aba9dba</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="1.0.0" />
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0" />
</ItemGroup>
</Project>

This will still generate a .PrecompiledViews.dll in the root of your publish directory and you will still have no refs folder.

This simplicity in order to get precompiled views is yet another win for the .csproj style ASP.NET Core projects over project.json.

Using the ASP.NET Core Script TagHelper to Polyfill The Latest JavaScript Features

tl;dr

The primary use case for fallbacks in the Script Tag Helper is checking if a CDN is down and loading a local script instead.  Another use case is you can use fallbacks to make it easy to polyfill missing JavaScript features in older browsers, while not having your users using the latest browsers take a network hit.


<script asp-fallback-test="window.Promise"
asp-fallback-src="https://unpkg.com/promise-polyfill@6.0.2"&gt;
</script>
<script asp-fallback-test="window.fetch"
asp-fallback-src="https://unpkg.com/whatwg-fetch@2.0.2"&gt;
</script>


View this gist on GitHub

Background – What is a Polyfill?

A polyfill is a fallback, written in JavaScript, that fills in a new JavaScript feature that is missing in an older browser and replicates the same functionality that newer browsers provide natively.  This allows JavaScript code using the latest features only available in newer browsers to work on older browsers as well.

To polyfill the API, you simply just check if that API is available, and if not, load the polyfill that adds that API to your browser.  That way, if your user is using the latest browser, you don’t punish them by downloading something they don’t need and hurting their performance.

How a Polyfill works

This JavaScript code will polyfill the “new” fetch API for making AJAX calls, that is currently available in all of the latest major browsers (Chrome, Edge, Firefox, Safari, etc.), but not in any of the Internet Explorer family tree (not even IE11).


window.Promise || document.write('<script src="https://unpkg.com/promise-polyfill@6.0.2"></script>&#39;)
window.fetch || document.write('<script src="https://unpkg.com/whatwg-fetch@2.0.2"></script>&#39;)

First, the code looks to see if the Promise API is available, because fetch relies on Promises in order to work.  If the API is not available, it loads a script from a CDN that polyfills the Promise API.  It does the same thing for the fetch API.

The built-in Script Tag Helper – CDN fallback

The built-in Script Tag Helper in ASP.NET Core has fallback support baked in that generates code very close to this.  The original intent of their fallback support was for attempting to load a script from a CDN.  After loading from that CDN, test to see if a JavaScript API is available, and if it’s not (due to the CDN being down, blocked, or whatever) fall back to loading a local JavaScript file.  That code looks like this:


<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.2.min.js&quot;
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery">
</script>

The fallback works for polyfills too!

What I haven’t seen anyone mention is to use this to conditionally polyfill if a JavaScript feature doesn’t exist.  And it works right out of the box, simply omit the src attribute, and the rest will be taken care of:


<script asp-fallback-test="window.Promise"
asp-fallback-src="https://unpkg.com/promise-polyfill@6.0.2"&gt;
</script>
<script asp-fallback-test="window.fetch"
asp-fallback-src="https://unpkg.com/whatwg-fetch@2.0.2"&gt;
</script>

The code above will generate nearly identical code to what’s in the first code sample.  As mentioned above, fetch needs Promises to work, so I’m also polyfilling that conditionally as well.  In the real world, I would likely bundle these two together (locally or using something like Polyfill.io) and make one network request, but using unpkg (an NPM CDN) was just for simplicity’s sake.

With the code above, I get the best of both worlds.  My code using fetch runs on older browsers, but my users who use the latest browsers don’t take a network hit for something they don’t need.  This same methodology will work for other ES2015 and above features and is nice for small apps that want to use some of the latest features and not have to deal with the build config of Babel or TypeScript transpiling down to ES5.

I’m not sure if this was an intended feature of the Script Tag Helper, but it’s a good use case for the fallback feature that I hadn’t seen anyone talk about, so I wanted to call attention to it.

And if you are lucky enough to only have to support Chrome at work.  I assume this is you right now reading the hoops us plebes have to go through to get our code to run on all browsers:

https://media.giphy.com/media/l3nWqD4ViFej9REAw/giphy.gif