AltCover and ReportGenerator give amazing code coverage on .NET Core

I’m continuing to explore testing and code coverage on open source .NET Core. Earlier this week I checked out coverlet. There is also the venerable OpenCover and there’s some cool work being done to get OpenCover working with .NET Core, but it’s Window…

I'm continuing to explore testing and code coverage on open source .NET Core. Earlier this week I checked out coverlet. There is also the venerable OpenCover and there's some cool work being done to get OpenCover working with .NET Core, but it's Windows only.

Today, I'm exploring AltCover by Steve Gilham. There are coverage tools that use the .NET Profiling API at run-time, instead, AltCover weaves IL for its coverage.

As the name suggests, it's an alternative coverage approach. Rather than working by hooking the .net profiling API at run-time, it works by weaving the same sort of extra IL into the assemblies of interest ahead of execution. This means that it should work pretty much everywhere, whatever your platform, so long as the executing process has write access to the results file. You can even mix-and-match between platforms used to instrument and those under test.

AltCover is a NuGet package but it's also available as .NET Core Global Tool which is awesome.

dotnet tool install --global altcover.global

This makes "altcover" a command that's available everywhere without adding it to my project.

That said, I'm going to follow the AltCover Quick Start and see how quickly I can get it set up!

I'll Install into my test project hanselminutes.core.tests

dotnet add package AltCover

and then run

dotnet test /p:AltCover=true

90.1% Line Coverage, 71.4% Branch CoverageCool. My tests run as usual, but now I've got a coverage.xml in my test folder. I could also generate LCov or Cobertura reports if I'd like. At this point my coverage.xml is nearly a half-meg! That's a lot of good information, but how do I see  the results in a human readable format?

This is the OpenCover XML format and I can run ReportGenerator on the coverage file and get a whole bunch of HTML files. Basically an entire coverage mini website!

I downloaded ReportGenerator and put it in its own folder (this would be ideal as a .NET Core global tool).

c:\ReportGenerator\ReportGenerator.exe -reports:coverage.xml -targetdir:./coverage

Make sure you use a decent targetDir otherwise you might end up with dozens of HTML files littered in your project folder. You might also consider .gitignoring the resulting folder and coverage file. Open up index.htm and check out all this great information!

Coverage Report says 90.1% Line Coverage

Note the Risk Hotspots at the top there! I've got a CustomPageHandler with a significant NPath Complexity and two Views with a significant Cyclomatic Complexity.

Also check out the excellent branch coverage as expressed here in the results of the coverage report. You can see that EnableAutoLinks was always true, so I only ever tested one branch. I might want to add a negative test here and explore if there's any side effects with EnableAutoLinks is false.

Branch Coverage

Be sure to explore AltCover and its Full Usage Guide. There's a number of ways to run it, from global tools, dotnet test, MSBuild Tasks, and PowerShell integration!

There's a lot of great work here and it took me literally 10 minutes to get a great coverage report with AltCover and .NET Core. Kudos to Steve on AltCover! Head over to https://github.com/SteveGilham/altcover and give it a STAR, file issues (be kind) or perhaps offer to help out! And most of all, share cool Open Source projects like this with your friends and colleagues.


Sponsor: Preview the latest JetBrains Rider with its built-in spell checking, initial Blazor support, partial C# 7.3 support, enhanced debugger, C# Interactive, and a redesigned Solution Explorer.


© 2018 Scott Hanselman. All rights reserved.
     

.NET Core Code Coverage as a Global Tool with coverlet

Last week I blogged about “dotnet outdated,” an essential .NET Core “global tool” that helps you find out what NuGet package reference you need to update. .NET Core Global Tools are really taking off right now. They are meant for devs – this isn’t a r…

Last week I blogged about "dotnet outdated," an essential .NET Core "global tool" that helps you find out what NuGet package reference you need to update.

.NET Core Global Tools are really taking off right now. They are meant for devs - this isn't a replacement for chocolatey or apt-get - this is more like npm's global developer tools. They're putting together a better way to find and identify global tools, but for now Nate McMaster has a list of some great .NET Core Global Tools on his GitHub. Feel free to add to that list!

.NET tools can be installed like this:

dotnet tool install -g <package id>

So for example:

C:\Users\scott> dotnet tool install -g dotnetsay

You can invoke the tool using the following command: dotnetsay
Tool 'dotnetsay' (version '2.1.4') was successfully installed.
C:\Users\scott> dotnetsay

Welcome to using a .NET Core global tool!

You know, all the important tools. Seriously, some are super fun. ;)

Coverlet is a cross platform code coverage tool that's in active development. In fact, I automated my build with code coverage for my podcast site back in March. I combined VS Code, Coverlet, xUnit, plus these Visual Studio Code extensions

for a pretty nice experience! All free and open source.

I had to write a little PowerShell script because the "dotnet test" command for testing my podcast site with coverlet got somewhat unruly. Coverlet.msbuild was added as a package reference for my project.

dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./lcov .\hanselminutes.core.tests

I heard last week that coverlet had initial support for being a .NET Core Global Tool, which I think would be convenient since I could use it anywhere on any project without added references.

dotnet tool install --global coverlet.console

At this point I can type "Coverlet" and it's available anywhere.

I'm told this is an initial build as a ".NET Global Tool" so there's always room for constructive feedback.

From what I can tell, I run it like this:

coverlet .\bin\Debug\netcoreapp2.1\hanselminutes.core.tests.dll --target "dotnet" --targetargs "test --no-build"

Note I have to pass in the already-built test assembly since coverlet instruments that binary and I need to say "--no-build" since we don't want to accidentally rebuild the assemblies and lose the instrumentation.

Coverlet can generate lots of coverage formats like opencover or lcov, and by default gives a nice ASCII table:

88.1% Line Coverage in Hanselminutes.core

I think my initial feedback (I'm not sure if this is possible) is smarter defaults. I'd like to "fall into the Pit of Success." That means, even I mess up and don't read the docs, I still end up successful.

For example, if I type "coverlet test" while the current directory is a test project, it'd be nice if that implied all this as these are reasonable defaults.

.\bin\Debug\whatever\whatever.dll --target "dotnet" --targetargs "test --nobuild"

It's great that there is this much control, but I think assuming "dotnet test" is a fair assumption, so ideally I could go into any folder with a test project and type "coverlet test" and get that nice ASCII table. Later I'd be more sophisticated and read the excellent docs as there's lots of great options like setting coverage thresholds and the like.

I think the future is bright with .NET Global Tools. This is just one example! What's your favorite?


Sponsor: Preview the latest JetBrains Rider with its built-in spell checking, initial Blazor support, partial C# 7.3 support, enhanced debugger, C# Interactive, and a redesigned Solution Explorer.



© 2018 Scott Hanselman. All rights reserved.
     

NuKeeper for automated NuGet Package Reference Updates on Build Servers

Last week I looked at “dotnet outdated,” a super useful .NET Core Global Tool for keeping a project’s NuGet packages up to date. Since then I’ve discovered there’s a whole BUNCH of great projects solving different aspects of the “minor version problem….

Last week I looked at "dotnet outdated," a super useful .NET Core Global Tool for keeping a project's NuGet packages up to date. Since then I've discovered there's a whole BUNCH of great projects solving different aspects of the "minor version problem." I love this answer "Why?" from the NuKeeper (inspired by Greenkeeper) project with emphasis mine. NuKeeper will check for updates AND try to update your references for you! Why not automate the tedious!

NuGet package updates are a form of change that should be deployed, and we likewise want to change the cycle from "NuGet package updates are infrequent and contain lots of package changes, therefore NuGet package updates are hard and dangerous..." to "NuGet package updates are frequent and contain small changes, therefore NuGet package updates are easy and routine...".

Certainly no one is advocating updating the major versions of your dependent NuGet packages, but small compatible bug fixes come often and are often missed. Including a tool to discover - and optionally apply - these changes in a CI/CD (Continuous Integration/Continuous Deployment) pipeline can be a great timesaver.

Why do we deploy code changes frequently but seldom update NuGet packages?

Good question!

NuKeeper

NuKeeper is a .NET tool as well that you can install safely with:

dotnet tool install --global NuKeeper

Here it is running on my regularly updated podcast website that is running ASP.NET Core 2.1:

NuKeeper says I have 3 packages to update

Looks like three of my packages are out of date. NuKeeper shows what version I have and what I could update to, as well as how long an update has been available.

You can also restrict your updates by policy, so "age=3w" for packages over 3 weeks old (so you don't get overly fresh updates) or "change=minor" or "change=patch" if you trust your upstream packages to not break things in patch releases, etc.

NuKeeper is picking up steam and while (as of the time of this writing) its command line parameter style is a little unconventional, Anthony Steele and the team is very open to feedback with many improvements already in progress as this project matures!

The update functionality is somewhat experimental and currently does 1 update per local run, but I'm really enjoying the direction NuKeeper is going!

Automatic NuGet Updates via Pull Request

NuKeeper has a somewhat unique and clever feature called Repository Mode in that it can automatically issue a Pull Request against your repository with the changes needed to update your NuGet references. Check out this example PullRequest!

The NuKeeperBot has automatically issued a PR with a list of packages to update

Again, it's early days, but between NuKeeper and "dotnet outdated," I'm feeling more in control of my package references than ever before! What are YOU using?


Sponsor: Scale your Python for big data & big science with Intel® Distribution for Python. Near-native code speed. Use with NumPy, SciPy & scikit-learn. Get it Today!



© 2018 Scott Hanselman. All rights reserved.
     

dotnet outdated helps you keep your projects up to date

I’ve moved my podcast site over to ASP.NET Core 2.1 over the last few months. You might want to follow the saga by checking out some of the recent blog posts. Upgrading my podcast site to ASP.NET Core 2.1 in Azure plus some Best Practices Major build…

I've moved my podcast site over to ASP.NET Core 2.1 over the last few months. You might want to follow the saga by checking out some of the recent blog posts.

That's just a few of the posts. Be sure to check out the last several months' posts in the calendar view. Anyway, I've been trying lots of new open source tools and libraries like coverlet for .NET Core Code Coverage, and frankly, keeping my project files and dependencies up to date has sucked.

Npm has "npm outdated" and paket has "paket outdated," why doesn't dotnet Core have this also? Certainly at a macro level there's more things to consider as NuGet would need to find the outdated packages for UWP, C++, and a lot of other project types as well. However if we just focus on .NET Core as an initial/primary use case, Jerrie Pelser has "dotnet outdated" for us and it's fantastic!

Once you've got the .NET Core 2.1 SDK or newer, just install the tool globally with one line:

dotnet tool install --global dotnet-outdated

At this point I'll run "dotnet outdated" on my podcast website. While that's running, let me just point you to https://github.com/jerriep/dotnet-outdated as a lovely example of how to release a tool (no matter how big or small) on GitHub.

  • It has an AppVeyor CI link along with a badge showing you that it's passing its build and test suite. Nice.
  • It includes both a NuGet link to the released package AND a myGet link and badge to the dailies.
  • It's got clear installation and clear usage details.
  • Bonus points of screenshots. While not accessible to call, I admit personally that I'm more likely to feel that a project is well-maintained if there are clear screenshots that tell me "what am I gonna get with this tool?"

Here's the initial output on my Site and Tests.

dotnet outdated

After updating the patch versions, here's the output, this time as text. For some reason it's not seeing Coverlet's NuGet so I'm getting a "Cannot resolve latest version" error but I haven't debugged that yet.

» hanselminutes.core.tests
  [.NETCoreApp,Version=v2.1]
  Microsoft.AspNetCore.Mvc.Testing 2.1.1
  Microsoft.NET.Test.Sdk 15.7.2
  Selenium.Support 3.13.1
  Selenium.WebDriver 3.13.1
  Xunit.SkippableFact 1.3.6
  coverlet.msbuild 2.0.1 Cannot resolve latest version
  xunit 2.3.1
  xunit.runner.visualstudio 2.3.1
» hanselminutes.core
  [.NETCoreApp,Version=v2.1]
  BuildBundlerMinifier 2.8.391
  LazyCache 2.0.0-beta03
  LazyCache.AspNetCore 2.0.0-beta03
  Markdig 0.15.0
  Microsoft.ApplicationInsights.AspNetCore 2.4.0-beta2
  Microsoft.AspNetCore.App 2.1.1
  Microsoft.Extensions.Http.Polly 2.1.1
  Microsoft.NET.Test.Sdk 15.7.2

As with all projects and references, while things aren't *supposed* to break when you update a Major.Minor.Patch/Revision.build...things sometimes do. You should check your references and their associated websites and release notes to confirm that you know what's changed and you know what changes you're bringing in.

Shayne blogged about dotnet out-dated and points out the -vl (version lock) options that allows you to locking on Major or Minor versions. No need to take things you aren't ready to take.

All in all, a super useful tool that you should install TODAY.

dotnet tool install --global dotnet-outdated

The source is up at https://github.com/jerriep/dotnet-outdated if you want to leave issues or get involved.


Sponsor: Check out dotMemory Unit, a free unit testing framework for fighting all kinds of memory issues in your code. Extend your unit testing with the functionality of a memory profiler!



© 2018 Scott Hanselman. All rights reserved.
     

The whole of WordPress compiled to .NET Core and a NuGet Package with PeachPie

Why? Because it’s awesome. Sometimes a project comes along that is impossibly ambitious and it works. I’ve blogged a little about Peachpie, the open source PHP compiler that runs PHP under .NET Core. It’s a project hosted at https://www.peachpie.io. Bu…

Compiling WordPress to .NET CoreWhy? Because it's awesome. Sometimes a project comes along that is impossibly ambitious and it works. I've blogged a little about Peachpie, the open source PHP compiler that runs PHP under .NET Core. It's a project hosted at https://www.peachpie.io.

But...why? Here's why:

  1. Performance: compiled code is fast and also optimized by the .NET Just-in-Time Compiler for your actual system. Additionally, the .NET performance profiler may be used to resolve bottlenecks.
  2. C# Extensibility: plugin functionality can be implemented in a separate C# project and/or PHP plugins may use .NET libraries.
  3. Sourceless distribution: after the compilation, most of the source files are not needed.
  4. Power of .NET: Peachpie allows the compiled WordPress clone to run in a .NET JIT'ted, secure and manageable environment, updated through windows update.
  5. No need to install PHP: Peachpie is a modern compiler platform and runtime distributed as a dependency to your .NET project. It is downloaded automatically on demand as a NuGet package or it can be even deployed standalone together with the compiled application as its library dependency.

A year ago you could very happily run Wordpress (a very NON-trivial PHP application, to be clear) under .NET Core using Peachpie. You would compile your PHP into an assembly and then do something like this in your Startup.cs:

public void Configure(IApplicationBuilder app)
{
    app.UseSession();
    app.UsePhp(new PhpRequestOptions(scriptAssemblyName: "peachweb"));
    app.UseDefaultFiles();
    app.UseStaticFiles();
}

And that's awesome. However, I noticed something on their GitHub recently, specifically under https://github.com/iolevel/wpdotnet-sdk. It says:

The solution compiles all of WordPress into a .NET assembly and additionally provides C# wrappers for utilization of compiled sources.

Whoa. Drink that in. The project consists of several parts:

  • wordpress contains sources of WordPress that are compiled into a single .NET Core assembly (wordpress.dll). Together with its content files it is packed into a NuGet package PeachPied.WordPress. The project additionally contains the "must-use" plugin peachpie-api.php which exposes the WordPress API to .NET.
  • PeachPied.WordPress.Sdk defines abstraction layer providing .NET interfaces over PHP WordPress instance. The interface is implemented and provided by peachpie-api.php.
  • PeachPied.WordPress.AspNetCore is an ASP.NET Core request handler that configures the ASP.NET pipeline to pass requests to compiled WordPress scripts. The configuration includes response caching, short URL mapping, various .NET enhancements and the settings of WordPress database.
  • app project is the executable demo ASP.NET Core web server making use of compiled WordPress.

They compiled the whole of WordPress into a NuGet Package.

YES.

  • The compiled website runs on .NET Core
  • You're using ASP.NET Core request handling and you can extend WordPress with C# plugins and themes

Seriously. Go get the .NET Core SDK version 2.1.301 over at https://dot.net and clone their repository locally from https://github.com/iolevel/wpdotnet-sdk.

Make sure you have a copy of mySQL running. I get one started FAST with Docker using this command:

docker run --name=mysql1 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress mysql --default-authentication-plugin=mysql_native_password

Then just "dotnet build" at the root of the project, then go into the app folder and "dotnet run." It will show up on localhost:5004.

NOTE: I needed to include the default authentication method to prevent the generic Wordpress "Cannot establish database connection." I also added the MYSQL_DATABASE environment variable so I could avoid logging initially using the mysql client and creating the database manually with "CREATE DATABASE wordpress."

Look at that. I have my mySQL in one terminal listening on 3306, and ASP.NET Core 2.1 running on port 5004 hosting freaking WordPress compiled into a single NuGet package.

Wordpress under .NET Core

Here's my bin folder:

WordPress as a single DLL

There's no PHP files which is a nice security bonus - not only are you running from the one assembly but there's no text files for any rogue plugins to modify or corrupt.

Here's the ASP.NET Core 2.1 app that hosts it, in full:

using System.IO;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using PeachPied.WordPress.AspNetCore;
namespace peachserver
{
    class Program
    {
        static void Main(string[] args)
        {
            // make sure cwd is not app\ but its parent:
            if (Path.GetFileName(Directory.GetCurrentDirectory()) == "app")
            {
                Directory.SetCurrentDirectory(Path.GetDirectoryName(Directory.GetCurrentDirectory()));
            }
            //
            var host = WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseUrls("http://*:5004/")
                .Build();
            host.Run();
        }
    }
    class Startup
    {
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IConfiguration configuration)
        {
            // settings:
            var wpconfig = new WordPressConfig();
            configuration
                .GetSection("WordPress")
                .Bind(wpconfig);
            //
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseWordPress(wpconfig);
            app.UseDefaultFiles();
        }
    }
}

I think the app.UseWordPress() is such a nice touch. ;)

I often get emails from .NET developers asking what blog engine they should consider. Today, I think you should look closely at Peachpie and strongly consider running WordPress under .NET Core. It's a wonderful open source project that brings two fantastic ecosystems together! I'm looking forward to exploring this project more and I'd encourage you to check it out and get involved with Peachpie.


Sponsor: Check out dotMemory Unit, a free unit testing framework for fighting all kinds of memory issues in your code. Extend your unit testing with the functionality of a memory profiler!



© 2018 Scott Hanselman. All rights reserved.
     

Detecting that a .NET Core app is running in a Docker Container and SkippableFacts in XUnit

I have moved my podcast site over to ASP.NET Core 2.1 and I’ve got it running in a Docker container. Take a moment a check out some of the blog posts, as I’ve been blogging as I’ve been learning. I’ve added Unit Tests as well as Selenium Tests that are…

Container Ship by NOAA used under CCI have moved my podcast site over to ASP.NET Core 2.1 and I've got it running in a Docker container. Take a moment a check out some of the blog posts, as I've been blogging as I've been learning.

I've added Unit Tests as well as Selenium Tests that are also run with the XUnit Unit Test Runner. However, I don't want those Selenium Tests that automate Google Chrome to run within the context of Docker.

I tried to add an Environment Variable within my Dockerfile like this:

ENV INDOCKER=1

I figured I'd check for that variable and conditionally skip tests. Simple, right? Well, I decided to actually READ the Dockerfiles that my ASP.NET Core 2.1 app uses. Remember, Dockerfiles (and the resulting images) are layered, and with all things .NET, are Open Source. 

Looking at my own layers and exploring the source on Github, I see I'm using:

Nice, so I don't need to set anything to know I'm running .NET in a Container! I wouldn't have known any of this if I hadn't taken 15 minutes and exploring/asserted/confirmed my stack. Just because I'm running Docker containers doesn't mean it's not useful to take the time to KNOW what I'm running! Assert your assumptions and all that, right?

I added a little helper in my Tests:

private bool InDocker { get { return Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true";} }

Since I'm using XUnit, I decided to bring in the very useful helper Xunit.SkippableFact!

For example:

[SkippableFact]
public void LoadTheMainPageAndCheckTitle()
{
    Skip.If(InDocker, "We are in Docker, y'all!");
    Browser.Navigate().GoToUrl(Server.RootUri);
    Assert.StartsWith("Hanselminutes Technology Podcast - Fresh Air and Fresh Perspectives for Developers", Browser.Title);
}

SkippableFact lets me skip tests for basically any reason. I could help if I'm in Docker, as I'm doing here. Or, given that Selenium Tests will throw an "OpenQA.Selenium.WebDriverException" when it can't find the Selenium Web Driver, I could also do this, skipping because a specific Exception was through. Note this means it's a SKIP not a FAIL.

[SkippableFact(typeof(OpenQA.Selenium.WebDriverException))]
public void KevinScottTestThenGoHome()
{
   Browser.Navigate().GoToUrl(Server.RootUri + "/631/how-do-you-become-a-cto-with-microsofts-cto-kevin-scott");
   var headerSelector = By.TagName("h1");
   var link = Browser.FindElement(headerSelector);
   link.Click();
}

The results look like this:

Total tests: 22. Passed: 18. Failed: 0. Skipped: 4.
Test Run Successful.
Test execution time: 8.7878 Seconds

You could choose to Skip Tests if a backend, 3rd party API, or DB was down, but you still wanted to test as much as possible. I'm pretty happy with the results!


New Sponsor! Never type an invoice again! With DocSight OCR by ActivePDF, you’ll extract data from bills, invoices, PO’s & other documents using zonal data capture technology. Achieve Digital Transformation today!


© 2018 Scott Hanselman. All rights reserved.
     

.NET Core and Docker

If you’ve got Docker installed you can run a .NET Core sample quickly just like this. Try it:docker run –rm microsoft/dotnet-samples
If your Docker for Windows is in “Windows Container mode” you can try .NET Framework (the full 4.x Windows Framework) …

If you've got Docker installed you can run a .NET Core sample quickly just like this. Try it:

docker run --rm microsoft/dotnet-samples

If your Docker for Windows is in "Windows Container mode" you can try .NET Framework (the full 4.x Windows Framework) like this:

docker run --rm microsoft/dotnet-framework-samples

vs-docker-toolsI did a video last week with a write up showing how easy it is to get a containerized application into Azure AND cheaply with per-second billing.

Container images are easy to share via Docker Hub, the Docker Store, and private Docker registries, such as the Azure Container Registry. Also check out Visual Studio Tools for Docker. It all works very nicely together.

I like this quote from Richard Lander:

Imagine five or so years ago someone telling you in a job interview that they care so much about consistency that they always ship the operating system with their app. You probably wouldn’t have hired them. Yet, that’s exactly the model Docker uses!

And it's a good model! It gives you guaranteed consistency. "Containers include the application and all of its dependencies. The application executes the same code, regardless of computer, environment or cloud." It's also a good way to make sure your underlying .NET is up to date with security fixes:

Docker is a game changer for acquiring and using .NET updates. Think back to just a few years ago. You would download the latest .NET Framework as an MSI installer package on Windows and not need to download it again until we shipped the next version. Fast forward to today. We push updated container images to Docker Hub multiple times a month.

The .NET images get built using the official Docker images which is nice.

.NET images are built using official images. We build on top of Alpine, Debian, and Ubuntu official images for x64 and ARM. By using official images, we leave the cost and complexity of regularly updating operating system base images and packages like OpenSSL, for example, to the developers that are closest to those technologies. Instead, our build system is configured to automatically build, test and push .NET images whenever the official images that we use are updated. Using that approach, we’re able to offer .NET Core on multiple Linux distros at low cost and release updates to you within hours.

Here's where you can find .NET Docker Hub repos:

.NET Core repos:

.NET Framework repos:

  • microsoft/dotnet-framework – includes .NET Framework runtime and sdk images.
  • microsoft/aspnet – includes ASP.NET runtime images, for ASP.NET Web Forms and MVC, configured for IIS.
  • microsoft/wcf – includes WCF runtime images configured for IIS.
  • microsoft/iis – includes IIS on top of the Windows Server Core base image. Works for but not optimized for .NET Framework applications. The microsoft/aspnet and microsoft/wcfrepos are recommended instead for running the respective application types.

There's a few kinds of images in the microsoft/dotnet repo:

  • sdk — .NET Core SDK images, which include the .NET Core CLI, the .NET Core runtime and ASP.NET Core.
  • aspnetcore-runtime — ASP.NET Core images, which include the .NET Core runtime and ASP.NET Core.
  • runtime — .NET Core runtime images, which include the .NET Core runtime.
  • runtime-deps — .NET Core runtime dependency images, which include only the dependencies of .NET Core and not .NET Core itself. This image is intended for self-contained applications and is only offered for Linux. For Windows, you can use the operating system base image directly for self-contained applications, since all .NET Core dependencies are satisfied by it.

For example, I'll use an SDK image to build my app, but I'll use aspnetcore-runtime to ship it. No need to ship the SDK with a running app. I want to keep my image sizes as small as possible!

For me, I even made a little PowerShell script (runs on Windows or Linux) that builds and tests my Podcast site (the image tagged podcast:test) within docker. Note the volume mapping? It stores the Test Results outside the container so I can look at them later if I need to.

#!/usr/local/bin/powershell

docker build --pull --target testrunner -t podcast:test .
docker run --rm -v c:\github\hanselminutes-core\TestResults:/app/hanselminutes.core.tests/TestResults podcast:test

Pretty slick.

Results File: /app/hanselminutes.core.tests/TestResults/_898a406a7ad1_2018-06-28_22_05_04.trx


Total tests: 22. Passed: 22. Failed: 0. Skipped: 0.
Test execution time: 8.9496 Seconds

Go read up on how the .NET Core images are built, managed, and maintained. It made it easy for me to get my podcast site - once dockerized - running on .NET Core on a Raspberry Pi (ARM32).


New Sponsor! Never type an invoice again! With DocSight OCR by ActivePDF, you’ll extract data from bills, invoices, PO’s & other documents using zonal data capture technology. Achieve Digital Transformation today!



© 2018 Scott Hanselman. All rights reserved.
     

Using Flurl to easily build URLs and make testable HttpClient calls in .NET

I posted about using Refit along with ASP.NET Core 2.1’s HttpClientFactory earlier this week. Several times when exploring this space (both on Twitter, googling around, and in my own blog comments) I come upon Flurl as in, “Fluent URL.” Not only is th…

FlurlI posted about using Refit along with ASP.NET Core 2.1's HttpClientFactory earlier this week. Several times when exploring this space (both on Twitter, googling around, and in my own blog comments) I come upon Flurl as in, "Fluent URL."

Not only is that a killer name for an open source project, Flurl is very active, very complete, and very interesting. By the way, take a look at the https://flurl.io/ site for a great example of a good home page for a well-run open source library. Clear, crisp, unambiguous, with links on how to Get It, Learn It, and Contribute. Not to mention extensive docs. Kudos!

Flurl is a modern, fluent, asynchronous, testable, portable, buzzword-laden URL builder and HTTP client library for .NET.

You had me at buzzword-laden! Flurl embraces the .NET Standard and works on .NET Framework, .NET Core, Xamarin, and UWP - so, everywhere.

To use just the Url Builder by installing Flurl. For the kitchen sink (recommended) you'll install Flurl.Http. In fact, Todd Menier was kind enough to share what a Flurl implementation of my SimpleCastClient would look like! Just to refresh you, my podcast site uses the SimpleCast podcast hosting API as its back-end.

My super basic typed implementation that "has a" HttpClient looks like this. To be clear this sample is WITHOUT FLURL.

public class SimpleCastClient

{
private HttpClient _client;
private ILogger<SimpleCastClient> _logger;
private readonly string _apiKey;

public SimpleCastClient(HttpClient client, ILogger<SimpleCastClient> logger, IConfiguration config)
{
_client = client;
_client.BaseAddress = new Uri($"https://api.simplecast.com"); //Could also be set in Startup.cs
_logger = logger;
_apiKey = config["SimpleCastAPIKey"];
}

public async Task<List<Show>> GetShows()
{
try
{
var episodesUrl = new Uri($"/v1/podcasts/shownum/episodes.json?api_key={_apiKey}", UriKind.Relative);
_logger.LogWarning($"HttpClient: Loading {episodesUrl}");
var res = await _client.GetAsync(episodesUrl);
res.EnsureSuccessStatusCode();
return await res.Content.ReadAsAsync<List<Show>>();
}
catch (HttpRequestException ex)
{
_logger.LogError($"An error occurred connecting to SimpleCast API {ex.ToString()}");
throw;
}
}
}

Let's explore Tim's expression of the same client using the Flurl library!

Not we set up a client in Startup.cs, use the same configuration, and also put in some nice aspect-oriented events for logging the befores and afters. This is VERY nice and you'll note it pulls my cluttered logging code right out of the client!

// Do this in Startup. All calls to SimpleCast will use the same HttpClient instance.

FlurlHttp.ConfigureClient(Configuration["SimpleCastServiceUri"], cli => cli
.Configure(settings =>
{
// keeps logging & error handling out of SimpleCastClient
settings.BeforeCall = call => logger.LogWarning($"Calling {call.Request.RequestUri}");
settings.OnError = call => logger.LogError($"Call to SimpleCast failed: {call.Exception}");
})
// adds default headers to send with every call
.WithHeaders(new
{
Accept = "application/json",
User_Agent = "MyCustomUserAgent" // Flurl will convert that underscore to a hyphen
}));

Again, this set up code lives in Startup.cs and is a one-time thing. The Headers, User Agent all are dealt with once there and in a one-line chained "fluent" manner.

Here's the new SimpleCastClient with Flurl.

using Flurl;

using Flurl.Http;

public class SimpleCastClient
{
// look ma, no client!
private readonly string _baseUrl;
private readonly string _apiKey;

public SimpleCastClient(IConfiguration config)
{
_baseUrl = config["SimpleCastServiceUri"];
_apiKey = config["SimpleCastAPIKey"];
}

public Task<List<Show>> GetShows()
{
return _baseUrl
.AppendPathSegment("v1/podcasts/shownum/episodes.json")
.SetQueryParam("api_key", _apiKey)
.GetJsonAsync<List<Show>>();
}
}

See in GetShows() how we're also using the Url Builder fluent extensions in the Flurl library. See that _baseUrl is actually a string? We all know that we're supposed to use System.Uri but it's such a hassle. Flurl adds extension methods to strings so that you can seamlessly transition from the strings (that we all use) representations of Urls/Uris and build up a Query String, and in this case, a GET that returns JSON.

Very clean!

Flurl also prides itself on making HttpClient testing easier as well. Here's a more sophisticated example of a library from their site:

// Flurl will use 1 HttpClient instance per host

var person = await "https://api.com"
.AppendPathSegment("person")
.SetQueryParams(new { a = 1, b = 2 })
.WithOAuthBearerToken("my_oauth_token")
.PostJsonAsync(new
{
first_name = "Claire",
last_name = "Underwood"
})
.ReceiveJson<Person>();

This example is doing a post with an anonymous object that will automatically turn into JSON when it hits the wire. It also receives JSON as the response. Even the query params are created with a C# POCO (Plain Old CLR Object) and turned into name=value strings automatically.

Here's a test Flurl-style!

// fake & record all http calls in the test subject

using (var httpTest = new HttpTest()) {
// arrange
httpTest.RespondWith(200, "OK");
// act
await sut.CreatePersonAsync();
// assert
httpTest.ShouldHaveCalled("https://api.com/*")
.WithVerb(HttpMethod.Post)
.WithContentType("application/json");
}

Flurl.Http includes a set of features to easily fake and record HTTP activity. You can make a whole series of assertions about your APIs:

httpTest.ShouldHaveCalled("http://some-api.com/*")

.WithVerb(HttpMethd.Post)
.WithContentType("application/json")
.WithRequestBody("{\"a\":*,\"b\":*}") // supports wildcards
.Times(1)

All in all, it's an impressive set of tools that I hope you explore and consider for your toolbox! There's a ton of great open source like this with .NET Core and I'm thrilled to do a small part to spread the word. You should to!


Sponsor: Check out dotMemory Unit, a free unit testing framework for fighting all kinds of memory issues in your code. Extend your unit testing with the functionality of a memory profiler.



© 2018 Scott Hanselman. All rights reserved.
     

Using ASP.NET Core 2.1’s HttpClientFactory with Refit’s REST library

When I moved my podcast site over to ASP.NET Core 2.1 I also started using HttpClientFactory and wrote up my experience. It’s a nice clean way to centralize both settings and policy for your HttpClients, especially if you’re using a lot of them to talk…

Strong by Lucyb_22 used under Creative Commons from FlickrWhen I moved my podcast site over to ASP.NET Core 2.1 I also started using HttpClientFactory and wrote up my experience. It's a nice clean way to centralize both settings and policy for your HttpClients, especially if you're using a lot of them to talk to a lot of small services.

Last year I explored Refit, an automatic type-safe REST library for .NET Standard. It makes it super easy to just declare the shape of a client and its associated REST API with a C# interface:

public interface IGitHubApi

{
[Get("/users/{user}")]
Task<User> GetUser(string user);
}

and then ask for an HttpClient that speaks that API's shape, then call it. Fabulous.

var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");


var octocat = await gitHubApi.GetUser("octocat");

But! What does Refit look like and how does it work in an HttpClientFactory-enabled world? Refit has recently been updated with first class support for ASP.NET Core 2.1's HttpClientFactory with the Refit.HttpClientFactory package.

Since you'll want to centralize all your HttpClient configuration in your ConfigureServices method in Startup, Refit adds a nice extension method hanging off of Services.

You add a RefitClient of a type, then add whatever other IHttpClientBuilder methods you want afterwards:

services.AddRefitClient<IWebApi>()

.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"));
// Add additional IHttpClientBuilder chained methods as required here:
// .AddHttpMessageHandler<MyHandler>()
// .SetHandlerLifetime(TimeSpan.FromMinutes(2));

Of course, then you can just have your HttpClient automatically created and passed into the constructor. You'll see in this sample from their GitHub that you get an IWebAPI (that is, whatever type you want, like my IGitHubApi) and just go to town with a strongly typed interfaces of an HttpClient with autocomplete.

public class HomeController : Controller

{
public HomeController(IWebApi webApi)
{
_webApi = webApi;
}

private readonly IWebApi _webApi;

public async Task<IActionResult> Index(CancellationToken cancellationToken)
{
var thing = await _webApi.GetSomethingWeNeed(cancellationToken);

return View(thing);
}
}

Refit is easy to use, and even better with ASP.NET Core 2.1. Go get Refit and try it today!

* Strong image by Lucyb_22 used under Creative Commons from Flickr


Sponsor: Check out dotMemory Unit, a free unit testing framework for fighting all kinds of memory issues in your code. Extend your unit testing with the functionality of a memory profiler.



© 2018 Scott Hanselman. All rights reserved.
     

ASP.NET Core Architect David Fowler’s hidden gems in 2.1

Open source ASP.NET Core 2.1 is out, and Architect David Fowler took to twitter to share some hidden gems that not everyone knows about. Sure, it’s faster, builds faster, runs faster, but there’s a number of details and fun advanced techniques that are…

ASP.NET Architect David FowlerOpen source ASP.NET Core 2.1 is out, and Architect David Fowler took to twitter to share some hidden gems that not everyone knows about. Sure, it's faster, builds faster, runs faster, but there's a number of details and fun advanced techniques that are worth a closer look at.

.NET Generic Host

ASP.NET Core introduced a new hosting model. .NET apps configure and launch a host.

The host is responsible for app startup and lifetime management. The goal of the Generic Host is to decouple the HTTP pipeline from the Web Host API to enable a wider array of host scenarios. Messaging, background tasks, and other non-HTTP workloads based on the Generic Host benefit from cross-cutting capabilities, such as configuration, dependency injection (DI), and logging.

This means that there's not just a WebHost anymore, there's a Generic Host for non-web-hosting scenarios. You get the same feeling as with ASP.NET Core and all the cool features like DI, logging, and config. The sample code for a Generic Host is up on GitHub.

IHostedService

A way to run long running background operations in both the generic host and in your web hosted applications. ASP.NET Core 2.1 added support for a BackgroundService base class that makes it trivial to write a long running async loop. The sample code for a Hosted Service is also up on GitHub.

Check out a simple Timed Background Task:

public Task StartAsync(CancellationToken cancellationToken)

{
_logger.LogInformation("Timed Background Service is starting.");

_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));

return Task.CompletedTask;
}

Fun!

Windows Services on .NET Core

You can now host ASP.NET Core inside a Windows Service! Lots of people have been asking for this. Again, no need for IIS, and you can host whatever makes you happy. Check out Microsoft.AspNetCore.Hosting.WindowsServices on NuGet and extensive docs on how to host your own ASP.NET Core app without IIS on Windows as a Windows Service.

public static void Main(string[] args)

{
var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);

var host = WebHost.CreateDefaultBuilder(args)
.UseContentRoot(pathToContentRoot)
.UseStartup<Startup>()
.Build();

host.RunAsService();
}

IHostingStartup - Configure IWebHostBuilder with an Assembly Attribute

Simple and clean with source on GitHub as always.

[assembly: HostingStartup(typeof(SampleStartups.StartupInjection))]

Shared Source Packages

This is an interesting one you should definitely take a moment and pay attention to. It's possible to build packages that are used as helpers to share source code. We internally call these "shared source packages." These are used all over ASP.NET Core for things that should be shared BUT shouldn't be public APIs. These get used but won't end up as actual dependencies of your resulting package.

They are consumed like this in a CSPROJ. Notice the PrivateAssets attribute.

<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="" />

<PackageReference Include="Microsoft.Extensions.ObjectMethodExecutor.Sources" PrivateAssets="All" Version="" />

ObjectMethodExecutor

If you ever need to invoke a method on a type via reflection and that method could be async, we have a helper that we use everywhere in the ASP.NET Core code base that is highly optimized and flexible called the ObjectMethodExecutor.

The team uses this code in MVC to invoke your controller methods. They use this code in SignalR to invoke your hub methods. It handles async and sync methods. It also handles custom awaitables and F# async workflows

SuppressStatusMessages

A small and commonly requested one. If you hate the output that dotnet run gives when you host a web application (printing out the binding information) you can use the new SuppressStatusMessages extension method.

WebHost.CreateDefaultBuilder(args)

.SuppressStatusMessages(true)
.UseStartup<Startup>();

AddOptions

They made it easier in 2.1 to configure options that require services. Previously, you would have had to create a type that derived from IConfigureOptions<TOptions>, now you can do it all in ConfigureServices via AddOptions<TOptions>

public void ConfigureServicdes(IServiceCollection services)

{
services.AddOptions<MyOptions>()
.Configure<IHostingEnvironment>((o,env) =>
{
o.Path = env.WebRootPath;
});
}

IHttpContext via AddHttpContextAccessor

You likely shouldn't be digging around for IHttpContext, but lots of folks ask how to get to it and some feel it should be automatic. It's not registered by default since having it has a performance cost. However, in ASP.NET Core 2.1 a PR was put in for an extension method that makes it easy IF you want it.

services.AddHttpContextAccessor();

So ASP.NET Core 2.1 is out and ready to go

New features in this release include:

Check out What's New in ASP.NET Core 2.1 in the ASP.NET Core docs to learn more about these features. For a complete list of all the changes in this release, see the release notes.

Go give it a try. Follow this QuickStart and you can have a basic Web App up in 10 minutes.


Sponsor: Check out JetBrains Rider: a cross-platform .NET IDE. Edit, refactor, test and debug ASP.NET, .NET Framework, .NET Core, Xamarin or Unity applications. Learn more and download a 30-day trial!



© 2018 Scott Hanselman. All rights reserved.