Lamar 4.1: Multithreading improvements, diagnostics, documentation updates, and some thoughts on troubleshooting

As promised in my previous post My (Big) OSS Plans for 2020, the very first thing out the gate for me this year is a bug fix release for Lamar.

Lamar 4.1 and its related libraries was released on Nuget late last week with a variety of bug fixes, a couple new features, and a documentation refresh at https://jasperfx.github.io/lamar — including some new guidance here and there as a direct reaction to GitHub issues. Continuing my personal theme of OSS interactions being more positive than not over the past couple years, I received a lot of help from Lamar users. This release was largely the result of users submitting pull requests with fixes or failing unit tests that reproduced issues — and I cannot stress enough how helpful those reproduction tests are for an OSS maintainer. Another user took the time to investigate how an error message could be greatly improved. Thank you to all the users who helped on this release with pull requests, suggestions, and feedback on GitHub.

All told, the libraries updated are:

  • Lamar 4.1.0 — Multi-threading issues were finally addressed, fixes for Lamar + ASP.Net Core logging, some finer grained control over type scanning registrations
  • Lamar.Microsoft.DependencyInjection v4.1.0 — Adds support back for IWebHostBuilder for .Net Core 3.0 applications
  • Lamar.Diagnostics v1.1.3 — More on this one below
  • LamarCompiler 2.1.1 — Just updated the Roslyn dependencies. Lamar itself doesn’t use this, so you’re very unlikely to be impacted
  • LamarCodeGeneration v1.4.0 — Some small additions to support a couple Jasper use cases
  • LamarCodeGeneration.Commands v1.0.2 — This isn’t documented yet, and is really just to support some diagnostics and pre-generation of code for Jasper

 

A Note on Troubleshooting

I have a partially written blog post slash treatise on troubleshooting and debugging. One of the things I try to suggest when troubleshooting a technical issue is to come up with a series of theories about why something isn’t working and figuring out the quickest way to prove or disprove that theory.

In the case of Lamar’s multi-threading issues addressed in this release and a very similar issue fixed previously, the “obvious” theory was that somewhere there was some issue with data structures or locking. Myself and several others tried to investigate Lamar’s internals down this path, but came up empty handed.

The actual root cause turned out to be related to the Expression construction and compilation inside of Lamar that allowed variables to bleed through threads in heavily multi-threaded usage.

So, I still think that my idea of “build a theory about why something is failing, then try to knock it down” is a good approach, but not 100% effective. I’m adding a section to that blog post entitled “don’t get tunnel vision” and talk about fixating on one theory and not considering other explanations;-)

Then again, some things are just hard some time.

Lamar.Diagnostics

Back in October I blogged about the new Oakton.AspNetCore package that extends the command line capabilities of standard .Net Core / ASP.Net Core applications with additional diagnostics. As a drop in extension to Oakton.AspNetCore, the new Lamar.Diagnostics package can be installed into a .Net Core application to give you ready access to all of Lamar’s built in diagnostics through the command line.

Your newly available commands from the root of your project with Lamar.Diagnostics are:

  1. dotnet run -- lamar-services — prints out the Container.WhatDoIHave() output to the console or a designated file
  2. dotnet run -- lamar-scanning — prints out the Container.WhatDidIScan() output to the console or a designated file
  3. dotnet run -- lamar-validate — runs the Container.AssertConfigurationIsValid() command

You can also opt into Lamar’s built in environment tests being used through Oakton.AspNetCore’s environment check capability.

In all cases, these commands work by calling IHostBuilder.Build() to build up your application — but doesn’t call Start() so none of your IHostedService objects will run — and calls the underlying Container methods. By doing this, you get ready access to the Lamar diagnostics against your application exacstly the way that your applicaiton is configured, without you having to add any additional code to your system to get at this diagnostic information.

 

 

My (Big) OSS Plans for 2020

It’s now a yearly thing for me to blog about my aspirations and plans for various OSS projects at the beginning of the year. I was mostly on the nose in 2018, and way, way off in 2019. I’m hoping and planning for a much bigger year in 2020 as I’ve gotten much more enthusiastic and energetic about some ongoing efforts recently.

Most of my time and ambition next year is going toward Jasper, Marten, and Storyteller:

Jasper

Jasper is a toolkit for common messaging scenarios between .Net applications with a robust in process command runner that can be used either with or without the messaging. Jasper wholeheartedly embraces the .Net Core 3.0 ecosystem rather than trying to be its own standalone framework.

Jasper has been gestating for years, I almost gave up on it completely early last year, and purposely set it aside until after .Net Core 3.0 was released. However, I came back to it a few months ago with fresh eyes and full of new ideas from doing a lot of messaging scenario work for Calavista clients. I’m very optimistic right now about Jasper from a purely technical perspective. I’m furiously updating documentation, building sample projects, and dealing with last minute API improvements in an effort to kick out the big v1.0 release sometime in January of 2020.

Marten

Marten is a library that allows .Net developers to treat the outstanding Postgresql database as both a document database and an event store. Marten is mostly supported by a core team, but I’m hoping to be much more involved again this year. The big thing is a proposed v4 release that looks like it’s mostly going to be focused on the event sourcing functionality. There’s an initial GitHub issue for the overall work here, and I want to write a bigger post soon on some ideas about the approach. There’s going to be some new functionality, but the general theme is to make the event sourcing be much more scalable. Marten is a team effort now, and there’s plenty of room for more contributors or collaborators.

For some synergy, I’m also planning on building out some reference applications that use Jasper to integrate Marten with cloud based queueing and load distribution for the asynchronous projection support. I’m excited about this work just to level up on my cloud computing skills.

Storyteller

Storyteller is a tool I’ve worked on and used for what I prefer to call executable specification in .Net (but other folks would call Behavior Driven Development, which I don’t like only because BDD is overloaded). I did quite a bit of preliminary work last year on a proposed Storyteller v6 that would bring it more squarely into the .Net Core world, I wrote a post last year called Spitballing the Future of Storyteller that laid out all my thoughts. I liked where it was heading, but I got distracted by other things.

For more synergy, Storyteller v6 will use Jasper a little bit for its communication between the user interface and the specification process. It also dovetails nicely with my need to update my Javascript UI skillset.

 

Smaller Projects

Lamar — the modern successor to StructureMap and ASP.Net Core compliant IoC container. I will be getting a medium sized maintenance release out very soon as I’ve let the issue list back up. I’m only focused on dealing with problems and questions as they come in.

EDIT 1/6/2020 –> There’s a Lamar 4.1 release out!

Alba — a library that wraps TestServer to make integration testing against ASP.Net Core HTTP endpoints easier. The big work late last year was making it support ASP.Net Core v3. I don’t have any plans to do much with it this year, but that could change quickly if I get to use it on a client project this year.

Oakton — yet another command line parser. It’s used by Jasper, Storyteller, and the Marten command line package. I feel like it’s basically done and said so last year, but I added some specific features for ASP.Net Core applications and might add more along those lines this year.

StructureMap — Same as last year. I answer questions here and there, but otherwise it’s finished/abandoned

FubuMVC — A fading memory, and I’m pleasantly surprised when someone mentions it to me about once or twice a year

 

The Very Last ALT.Net Retrospective I’ll Ever Write

I’m on the latest episode of DotNetRocks (episode 1655) mostly talking about the .Net Core ecosystem and catching them up on the latest on Marten. Richard caught me a little off guard when he asked me if I thought after all this time that ALT.Net had been a success considering how Microsoft has embraced Open Source development as a model for themselves and the community as a whole.

If you’re in .Net and wondering what the hell is this “ALT.Net” thing, check out my article in MSDN from 2008 called What is ALT.NET? (that I was pleasantly surprised was still online to be honest). In short, it was a community in .Net of vaguely like-minded folks who were mostly drawn from the .Net blogging world and nascent OSS ecosystem of that time. I still think that the original couple ALT.Net Open Spaces events in Austin and Seattle were the best technical events and most impressive group of folks I’ve ever gotten to be around. As Richard had to bring up on DotNetRocks, the “movement” crystallized in some part because several of us crashed a session at the MVP summit in 2007 where the very earliest version of Entity Framework was being demonstrated and it, um, wasn’t good. At all.

Quoting from David Laribee’s original “ALT.Net Manifesto”:

  1. You’re the type of developer who uses what works while keeping an eye out for a better way.
  2. You reach outside the mainstream to adopt the best of any community: Open Source, Agile, Java, Ruby, etc.
  3. You’re not content with the status quo. Things can always be better expressed, more elegant and simple, more mutable, higher quality, etc.
  4. You know tools are great, but they only take you so far. It’s the principles and knowledge that really matter. The best tools are those that embed the knowledge and encourage the principles 

If you’d asked me personally in 2007-2008 what I thought ALT.Net was about and could maybe achieve it would be something like:

  • Introducing better software practices like Continuous Integration and TDD/BDD pulled from Agile software development. Heck, honestly I’d say that it was getting the .Net world to adopt Agile techniques — and at that time it was going to take some significant changes to the way the .Net mainstream built applications because the Microsoft technology of the day was a very poor fit for Agile development techniques (*cough* WebForms *cough*).
  • Opening the .Net community as a whole from ideas and tooling from outside the strict Microsoft ecosystem. I remember a lot of commentary about the “Microsoft monoculture”
  • And yes, to make .Net be much more OSS friendly.
  • Have a .Net community of practitioners that wasn’t focused solely on Microsoft tools. I remember being very critical of the Microsoft MVP/Regional Director camp at the time, even though I was a C# MVP at that time.

Like I said earlier, as an active participant in ALT.Net it was a tremendous experience, I learned a lot, and met some great folks that I’m friends with to this day. We unfortunately had some toxic personalities involved and the backlash from the mainstream .Net world more or less did ALT.Net in. I’d argue that ALT.Net as a distinct thing and any hopes of being a vibrant, transformative force within .Net was pretty well destroyed when Scott Hanselman did this:

whysomean

I’ll have to admit that even after a decade I still have some hard feelings toward many .Net celebrities of that day.

So, after all this time, do I think ALT.Net was successful? 

Eh, maybe, sort of. I think it’s possible that the positive changes would have happened over time anyway. I think it’s much more likely that folks like Hanselman, Phil Haack, Brad Wilson, Glenn Block, Jon Galloway and many others working within Microsoft made a much bigger difference in the end than we ALT.Net rabble rousers did from the outside.

ALT.Net was very successful in terms of bringing some people together who are still among the technical community leaders, so that’s a positive. I still think the .Net community is a little too focused on Microsoft, but I like the technical stuff and guidance coming out of Redmond much, much better now than I did in ’07-’08 and I do think that ALT.Net had some impact on that.

I think you could claim that ALT.Net had some influence in moving things in better directions, but it required a lot more time than we’d anticipated and it maybe inevitably had to come about by Microsoft itself changing. For those of you who don’t know this, Scott Guthrie did the first public demonstration of what became ASP.Net MVC in Austin at the initial ALT.Net Open Spaces event, partially in reaction to how so many of us at that time were very negatively comparing WebForms of the day to what we were seeing in Ruby on Rails.

One of my big bugaboos at that time was how bad of a fit the mainstream .Net tools from Microsoft were for Agile Software Development practices like TDD and CI (you almost had to have Visual Studio.Net installed on your build server back in those days, and the dominant .Net tools of the day were horrible for testability). Looking at ASP.Net Core today, I think that the approaches they use are very much appropriate for modern Agile development practices.

I have mixed things to say about the state of OSS in .Net. Microsoft no longer tries to actively kill off OSS alternatives the way they did in the early days. Nuget obviously helps quite a bit. Microsoft themselves using GitHub and an OSS model for much of their own development helps tremendously. There’s still the issue of Microsoft frequently destroying OSS alternatives with their own tools instead of embracing things from the community. This is worth a later blog post, but I see a lot of things in .Net Core (the DI abstractions that we all hated at first, the IHostBuilder idea, the vastly better configuration model) that I think act as a very good foundation that makes it easier to OSS authors to integrate their tools into .Net Core applications — so that’s definitely good.

And yes, I think that the latest EF Core is fine as a heavy ORM today, after it basically ditched all the silly stuff we complained about in EF v1 back then and adopted a lot of thinking from OSS NHibernate (pssst, EF Core “code first” looks a lot like Fluent NHibernate that came out of the community many years earlier). But at this point I’d much rather use NoSQL tools like Marten, so I’m not sure you’re getting too much from me there;)

The .Net world and Microsoft itself is much more open to ideas that originate in other development communities, and I think that’s a strength of .Net at this point to be honest. Hell, a lot of what I really like about the dotnet cli and .Net Core is very clearly influenced by Node.js and other platforms.

.Net is still too Microsoft-centric in my opinion, but there’s more community now that isn’t just regurgitating MSDN documentation. I still think the MVP program is hurtful over all, but that might just be me. Compared to the world of 2007, now is much better.

Environment Checks and Better Command Line Abilities for your .Net Core Application

Oakton.AspNetCore is a new package built on top of the Oakton 2.0+ command line parser that adds extra functionality to the command line execution of ASP.Net Core and .Net Core 3.0 codebases. At the bottom of this blog post is a small section showing you how to set up Oakton.AspNetCore to run commands in your .Net Core application.

First though, you need to understand that when you use the dotnet run command to build and execute your ASP.Net Core application, you can pass arguments and flags both to dotnet run itself and to your application through the string[] args argument of Program.Main(). These two types of arguments or flags are separated by a double dash, like this example: dotnet run --framework netcoreapp2.0 -- ?. In this case, “–framework netcoreapp2.0” is used by dotnet run itself, and the values to the right of the “–” are passed into your application as the args array.

With that out of the way, let’s see what Oakton.AspNetCore brings to the table.

Extended “Run” Options

In the default ASP.Net Core templates, your application can be started with all its defaults by using dotnet run.  Oakton.AspNetCore retains that usage, but adds some new abilities with its “Run” command. To check the syntax options, type dotnet run -- ? run:

 Usages for 'run' (Runs the configured AspNetCore application)
  run [-c, --check] [-e, --environment <environment>] [-v, --verbose] [-l, --log-level <logleve>] [----config:<prop> <value>]

  ---------------------------------------------------------------------------------------------------------------------------------------
    Flags
  ---------------------------------------------------------------------------------------------------------------------------------------
                        [-c, --check] -> Run the environment checks before starting the host
    [-e, --environment <environment>] -> Use to override the ASP.Net Environment name
                      [-v, --verbose] -> Write out much more information at startup and enables console logging
          [-l, --log-level <logleve>] -> Override the log level
          [----config:<prop> <value>] -> Overwrite individual configuration items
  ---------------------------------------------------------------------------------------------------------------------------------------

To run your application under a different hosting environment name value, use a flag like so:

dotnet run -- --environment Testing

or

dotnet run -- -e Testing

To overwrite configuration key/value pairs, you’ve also got this option:

dotnet run -- --config:key1 value1 --config:key2 value2

which will overwrite the configuration keys for “key1” and “key2” to “value1” and “value2” respectively.

Lastly, you can have any configured environment checks for your application immediately before starting your application by using this flag:

dotnet run -- --check

More on this function in the next section.

 

Environment Checks

I’m a huge fan of building environment tests directly into your application. Environment tests allow your application to self-diagnose issues with deployment, configuration, or environmental dependencies upfront that would impact its ability to run.

As a very real world example, let’s say your ASP.Net Core application needs to access another web service that’s managed independently by other teams and maybe, just maybe your testers have occasionally tried to test your application when:

  • Your application configuration has the wrong Url for the other web service
  • The other web service isn’t running at all
  • There’s some kind of authentication issue between your application and the other web service

In the real world project that spawned the example above, we added a formal environment check that would try to touch the health check endpoint of the external web service and throw an exception if we couldn’t connect to the external system. The next step was to execute our application as it was configured and deployed with this environment check as part of our Continuous Deployment pipeline. If the environment check failed, the deployment itself failed and triggered off the normal set of failure alerts letting us know to go fix the environment rather than letting our testers waste time on a bad deployment.

With all that said, let’s look at what Oakton.AspNetCore does here to help you add environment checks. Let’s say your application uses a single Sql Server database, and the connection string should be configured in the “connectionString” key of your application’s connection. You would probably want an environment check just to verify at a minimum that you can successfully connect to your database as it’s configured.

In your ASP.Net Core Startup class, you could add a new service registration for an environment check like this example:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // Other registrations we don't care about...
    
    // This extension method is in Oakton.AspNetCore
    services.CheckEnvironment<IConfiguration>("Can connect to the application database", config =>
    {
        var connectionString = config["connectionString"];
        using (var conn = new SqlConnection(connectionString))
        {
            // Just attempt to open the connection. If there's anything
            // wrong here, it's going to throw an exception
            conn.Open();
        }
    });
}

Now, during deployments or even just pulling down the code to run locally, we can run the environment checks on our application like so:

dotnet run -- check-env

Which in the case of our application above, blows up with output like this because I didn’t add configuration for the database in the first place:

Running Environment Checks
   1.) Failed: Can connect to the application database
System.InvalidOperationException: The ConnectionString property has not been initialized.
   at System.Data.SqlClient.SqlConnection.PermissionDemand()
   at System.Data.SqlClient.SqlConnectionFactory.Permissi
onDemand(DbConnection outerConnection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1
 retry, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, 
DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.Open()
   at MvcApp.Startup.<>c.<ConfigureServices>b_
_4_0(IConfiguration config) in /Users/jeremydmiller/code/oakton/src/MvcApp/Startup.cs:line 41
   at Oakton.AspNetCore.Environment.EnvironmentCheckExtensions.<>c__DisplayClass2_0`1.<CheckEnvironment>b__0(IServ
iceProvider s, CancellationToken c) in /Users/jeremydmiller/code/oakton/src/Oakton.AspNetCore/Environment/EnvironmentCheckExtensions.cs:line 53
   at Oakton.AspNetCore.Environment.LambdaCheck.Assert(IServiceP
rovider services, CancellationToken cancellation) in /Users/jeremydmiller/code/oakton/src/Oakton.AspNetCore/Environment/LambdaCheck.cs:line 19
   at Oakton.AspNetCore.Environment.EnvironmentChecker.ExecuteAll
EnvironmentChecks(IServiceProvider services, CancellationToken token) in /Users/jeremydmiller/code/oakton/src/Oakton.AspNetCore/Environment/EnvironmentChecker.cs:line 31

If you ran this command during continuous deployment scripts, the command should cause your build to fail when it detects environment problems.

In some of Calavista’s current projects , we’ve been adding environment tests to our applications for items like:

  • Can our application read certain configured directories?
  • Can our application as it’s configured connect to databases?
  • Can your application reach other web services?
  • Are required configuration items specified? That’s been an issue as we’ve had to build out Continuous Deployment pipelines to many, many different server environments

I don’t see the idea of “Environment Tests” mentioned very often, and it might have other names I’m not aware of. I learned about the idea back in the Extreme Programming days from a blog post from Nat Pryce that I can’t find any longer, but there’s this paper from those days too.

 

Add Other Commands

I’ve frequently worked in projects where we’ve built parallel console applications that reproduce a lot of the same IoC and configuration setup to perform administrative tasks or add other diagnostics. It could be things like adding users, rebuilding an event store projection, executing database migrations, or loading some kind of data into the application’s database. What if instead, you could just add these directly to your .Net Core application as additional dotnet run -- [command] options? Fortunately, Oakton.AspNetCore let’s you do exactly that, and even allows you to package up reusable commands in other assemblies that could be distributed by Nuget.

If you use Lamar as your IoC container in an ASP.Net Core application (or .Net Core 3.0 console app using the new unified HostBuilder), we now have an add on Nuget called Lamar.Diagnostics that will add new Oakton commands to your application that give you access to Lamar’s diagnostic tools from the command line. As an example, this library adds a command to write out the “WhatDoIHave()” report for the underlying Lamar IoC container of your application to the command line or a file like this:

dotnet run --lamar-services

Now, using the command above as an example, to build or add your own commands start by decorating the assembly containing the command classes with this attribute:

[assembly:OaktonCommandAssembly]

Having this assembly tells Oakton.AspNetCore to search the assembly for additional Oakton commands. There is no other setup necessary.

If your command needs to use the application’s services or configuration, have the Oakton input type inherit from NetCoreInput type from Oakton.AspNetCore like so:

public class LamarServicesInput : NetCoreInput
{
    // Lots of other flags
}

Next, the new command for “lamar-services” is just this:

[Description("List all the registered Lamar services", Name = "lamar-services")]
public class LamarServicesCommand : OaktonCommand<LamarServicesInput>
{
    public override bool Execute(LamarServicesInput input)
    {
        // BuildHost() will return an IHost for your application
        // if you're using .Net Core 3.0, or IWebHost for
        // ASP.Net Core 2.*
        using (var host = input.BuildHost())
        {
            // The actual execution using host.Services
            // to get at the underlying Lamar Container
        }

        return true;
    }


}

Getting Started

In both cases I’m assuming that you’ve bootstrapped your application with one of the standard project templates like dotnet new webapi or dotnet new mvc. In both cases, you’ll first add a reference to the Oakton.AspNetCore Nuget. Next, break into the Program.Main()entry point method in your project and modify it like the following samples.

If you’re absolutely cutting edge and using ASP.Net Core 3.0:

public class Program
{
    public static Task<int> Main(string[] args)
    {
        return CreateHostBuilder(args)
            
            // This extension method replaces the calls to
            // IWebHost.Build() and Start()
            .RunOaktonCommands(args);
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(x => x.UseStartup<Startup>());
    
}

For what I would guess is most folks, the ASP.Net Core 2.* setup (and this would work as well for ASP.Net Core 3.0 as well):

public class Program
{
    public static Task<int> Main(string[] args)
    {
        return CreateWebHostBuilder(args)
            
            // This extension method replaces the calls to
            // IWebHost.Build() and Start()
            .RunOaktonCommands(args);
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
    
}

The two changes from the template defaults is to:

  1. Change the return value to Task<int>
  2. Replace the calls to IHost.Build() and IHost.Start() to use the RunOaktonCommands(args) extension method that hangs off IWebHostBuilder and the new unified IHostBuilder if you’re targeting netcoreapp3.0.

And that’s it, you’re off to the races.

 

Alba 3.1 supercharges your ASP.Net Core HTTP Contract Testing

I was just able to push a Nuget for Alba 3.1 that adds support for ASP.Net Core 3.0 and updated the documentation website to reflect the mild additions. Big thanks are in order to Lauri Kotilainen and Jonathan Mezach for making this release happen.

If you’re not familiar with Alba, in its current incarnation it’s a wrapper around the ASP.Net Core TestServer that adds a whole lot of useful helpers to make your testing of ASP.Net Core HTTP services be much more declarative and easier than it is with TestServer alone.

Alba is descended from some built in support for HTTP contract testing in FubuMVC that I salvaged and adapted for usage with ASP.Net Core a few years back. Finally, Alba has used TestServer rather than its own homegrown HTTP runner since the big 3.0 release this January.

Lamar and Oakton join the .Net Core 3.0 Party

Like many other .Net OSS authors, I’ve been putting in some time this week making sure that various .Net tools support the brand spanking new .Net Core and ASP.Net Core 3.0 bits that were just released. First up is Oakton and Lamar, with the rest of the SW Missouri projects to follow soon.

Oakton

Oakton is yet another command line parser tool for .Net. The main Oakton 2.0.1 library adds support for the Netstandard2.1 target, but does not change in any other way. The Oakton.AspNetCore library got a full 2.0.0 release. If you’re using ASP.Net Core v2.0, your usage is unchanged. However, if you are targeting netcoreapp3.0, the extension methods now depend on the newly unified IHostBuilder rather than the older IWebHostBuilder and the bootstrapping looks like this now:

public class Program
{
    public static Task<int> Main(string[] args)
    {
        return CreateHostBuilder(args)
            
            // This extension method replaces the calls to
            // IWebHost.Build() and Start()
            .RunOaktonCommands(args);
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(x => x.UseStartup<Startup>());
    
}

 

Oakton.AspNetCore provides an improved and extensible command line experience for ASP.Net Core. I’ve been meaning to write a bigger blog post about it, but that’s gonna wait for another day.

Lamar

The 3.0 support in Lamar was unpleasant, because the targeting covers the spread from .Net 4.6.1 to netstandard2.0 to netstandard2.1, and the test library covered several .Net runtimes. After this, I’d really like to not have to type “#if/#else/#endif” ever, ever again (and I do use ReSharper/Rider’s ALT-CTRL-J surround with feature religiously that helps, but you get my point).

The new bits and releases are:

  • Lamar v3.2.0 adds a netstandard2.1 target
  • LamarCompiler v2.1.0 adds a netstandard2.1 target (probably only used by Jasper, but who knows who’s picked it up, so I updated it)
  • LamarCodeGeneration v1.1.0 adds a netstandard2.1 target but is otherwise unchanged
  • Lamar.Microsoft.DependencyInjection v4.0.0 — this is the adapter library to replace the built in DI container in ASP.Net Core with Lamar. This is a full point release because some of the method signatures changed. I deleted the special Lamar handling for IOption<T> and ILogger<T> because they no longer added any value. If your application targets netcoreapp3.0, the UseLamar() method and its overloads hang off of IHostBuilder instead of IWebHostBuilder. If you are remaining on ASP.Net Core v2.*, UseLamar() still hangs off of IWebHostBuilder
  • Lamar.Diagnostics v1.1.0 — assuming that you use the Oakton.AspNetCore command line adapter for your ASP.Net Core application, adding a reference to this library adds new commands to expose the Lamar diagnostic capabilities from the command line of your application. This version targets both netstandard2.0 for ASP.Net Core v2.* and netstandard2.1 for ASP.Net Core 3.*.

 

The challenges

The biggest problem was that in both of these projects, I wanted to retain support for .Net 4.6+ and netstandard2.0 or netcoreapp2.* runtime targets. That’s unfortunately meant a helluva lot of conditional compilation and conditional Nuget references per target framework. In some cases, the move from the old ASP.Net Core <=2.* IWebHostBuilder to the newer, unified IHostBuilder took some doing in both the real code and in the unit tests. Adding to the fun is that there are real differences sometimes between the old, full .Net framework, netcoreapp2.0, netcoreapp2.1/2, and certainly the brand new netcoreapp3.0.

Another little hiccup was that the dotnet pack pathing support was fixed to what it was originally in the project.json early days, but that broke all our build scripts and that had to be adjusted (the artifacts path is relative to the current directory now rather than to the binary target path like is was).

At least on AppVeyor, we had to force the existing image to install the latest .Net SDK as part of the build because the image we were using didn’t yet support the brand new .Net SDK. I’d assume that is very temporary and I can’t speak to other hosted CI providers. If you’re wondering how to do that, see this example from Lamar that I got from Jimmy Byrd.

 

Other Projects I’m Involved With

  • StructureMap — If someone feels like doing it, I’d take a pull request to StructureMap.Microsoft.DependencyInjection to put out a .Net Core 3.0 compatible version (really just means supporting the new IHostBuilder instead of or in addition to the old IWebHostBuilder).
  • Alba — Some other folks are working on that one, and I’m anticipating an Alba on ASP.Net Core 3.0 release in the next couple days. I’ll write a follow up blog post when that’s ready
  • Marten — I’m not anticipating much effort here, but we should at least have our testing libraries target netcoreapp3.0 and see what happens. We did have some issues with netcoreapp2.1, so we’ll see I guess
  • Jasper — I’ve admittedly had Jasper mostly on ice until .Net Core 3.0 was released. I’ll start work on Jasper next week, but in that is going to be a true conversion up to netcoreapp3.0 and some additional structural changes to finally get to a 1.0 release of that thing.
  • Storyteller — I’m not sure yet, but I’ve started doing a big overhaul of Storyteller that’s gotten derailed by the .Net Core 3.0 stuff

 

Lamar 3.1 – New Diagnostics and more

Lamar 3.1.0 was published today with a few fixes, new diagnostics, and a newly improved equivalent to StructureMap’s old “Forward” registration. The full details are here.

There’s one big bug fix on multi-threaded usage that was impacting folks using Lamar with MediatR (it’s worth a later blog post about debugging problems because this took several folks and at least two attempts from me to finally diagnose and solve).

“Inverse” Registration

For the not uncommon need to have one single object be the implementation for multiple role interfaces within the container, there’s the new “inverse” registration mechanism as shown below:

[Fact]
public void when_singleton_both_interfaces_give_same_instance()
{
    var container = new Container(services =>
    {
        services.Use<Implementation>()
            .Singleton()
            .For<IServiceA>()
            .For<IServiceB>();
    });

    var instanceA = container.GetInstance<IServiceA>();
    var instanceB = container.GetInstance<IServiceB>();

    instanceA.ShouldBeTheSameAs(instanceB);
}

What you see above is registering the concrete type Implementation as the shared, underlying service for both IServiceA and IServiceBregistrations.

HowDoIBuild

Lamar has been able to show you the “build plan” for registrations since the beginning, but now there’s a helper Container.HowDoIBuild() method that gives you easier access to this information that can be helpful for troubleshooting IoC configuration issues.

Lamar.Diagnostics

More on this one later, but there’s also a brand new package called Lamar.Diagnostics that, in conjunction with Oakton.AspNetCore, adds command line access to all the Lamar diagnostic capabilities directly to your ASP.Net Core application.