Introducing BlueMilk: StructureMap’s Replacement & Jasper’s Special Sauce

BlueMilk is the codename for a new project that’s an outgrowth from our new Jasper framework. Specifically, BlueMilk is extracting the runtime code generation and compilation “Special Sauce” support code that’s in Jasper now into a stand alone library. Building upon the runtime code generation, the logical next step was to make BlueMilk into the intended successor to the venerable StructureMap project as a fast, minimal IoC container on its own, but also supports inlining the service activation code into Jasper’s message and HTTP request handlers.

I think these are the key points for BlueMilk:

  1. Support the essential functionality and configuration API of StructureMap to be an offramp for folks invested in StructureMap that want to move to a faster option in their Netstandard2 applications
  2. Align much closer with the ASP.Net team’s DI compliance behavior. In some cases like object lifecycles, this is a breaking change with StructureMap’s traditional behavior and I don’t entirely agree with their choices, but .Net is their world and all us scrappy community OSS authors are just living in it.
  3. Easy integration into ASP.Net Core applications by directly supporting their abstractions (IServiceCollection, IServiceProvider, ServiceDescriptor, IServiceScope, etc.) out of the box.
  4. Trade in some of the runtime flexibility that StructureMap had in favor of better performance (and fewer ways for users to get themselves in a tangle)
  5. Expose the runtime code generation and compilation model (originally built for Marten, but we took it out later) in a separate library because a few folks have expressed some interest in having just that without using Jasper

There’s a preliminary Nuget up this morning (0.1.0) that supports some of StructureMap’s behavior and all of the ASP.Net Core compliance. You can use a container like this:

// Idiomatic StructureMap
var container = new Container(_ =>
{
    _.For<IWidget>().Use<AWidget>().Named("A");
    
    // StructureMap's old type scanning
    _.Scan(s =>
    {
        s.TheCallingAssembly();
        s.WithDefaultConventions();
    });
});

var widget = container.GetInstance<IWidget>();

// ASP.Net Core DI compatible
IServiceProvider container2 = new Container(_ =>
{
    _.AddTransient<IWidget, AWidget>();
    _.AddSingleton(new MoneyWidget());
});

var widget2 = container.GetService<IWidget>();

 

My Thoughts on Project Scope

I only started working on BlueMilk by itself over the holidays, so it’s not like anything is truly set in concrete, but this list is what I think the scope would be. My philosophy here is to jettison many of the features in StructureMap that cause internal complexity, performance issues, or generate loads of user questions and edge case bugs.

Core Functionality

  1. All ASP.Net Core DI compliance — lifecycle management (note that it’s different than StructureMap’s lifecycle definitions), object disposal, basic service resolution, open generic support, dealing with enumerable types
  2. StructureMap’s basic support for service location
  3. Nested Containers (scoped container)
  4. Type Scanning from StructureMap
  5. Service resolution by name
  6. Lazy & Func<T> resolution
  7. WhatDoIHave() and other diagnostics — no IoC or any other kind of framework author should release a tool without something like this for the sake of their own sanity
  8. Auto-find missing registrations — one of my biggest gripes about the built in container

Later

  1. Inline dependencies
  2. AutoFactory support — I think this could work out very well with the code generation model
  3. Construction Policies
  4. Some of StructureMap’s attribute configuration

Leaving Behind unless someone else really wants to build *and* help support it

  • Interception — Maybe. I’m not super excited about supporting it
  • Child containers and profiles. Utter nightmare to support. Edge case hell. Crazy amount of complexity internally. The only way we use them in work is for per-test isolation, and we can live without them in that case
  • Changing configuration at runtime (Container.Configure()).
  • Passing arguments at runtime. One of the biggest sources of heartburn for me supporting StructureMap. I think the better autofactory support in BlueMilk could be a far better alternative anyway.

Why do this?

One of my fervent goals with Jasper from the very beginning was to maximize performance to the point where its throughput was barely distinguishable from laboriously writing highly optimized bespoke code by hand. I wanted users to have all the productivity benefits of a good framework that takes care of common infrastructure needs without sacrificing performance. I know that some folks will disagree, but I still think there’s ample reasons to use an IoC container to handle quite a bit of the object composition, service activation, object scoping, and service cleanup.

If you allow that assumption of IoC usage, that left me with a couple options and thoughts:

  • I think it’s hugely disadvantageous to .Net frameworks to have to support multiple IoC containers. My experience is that basically every single framework abstraction I have ever seen for an IoC container has been problematic. If you are going to support multiple IoC containers in your application framework, my experience from FubuMVC and from watching the unfolding consternation over ASP.Net Core’s DI compliance is to restrict your framework from making all but a handful of assumptions about IoC container behavior.
  • I could just use my own StructureMap container because I understand it front to back and it fits the way that I personally work and all the .Net developers in my shop know it. The only problem there is that StructureMap has fallen behind in terms of performance. I think I have a decent handle on what it would take to reverse that with a potential 5.0, but I’m just not up for doing the work, I’m exhausted keeping up with user questions, and I really want to get out of supporting StructureMap.
  • I tried a couple times to just use the new built-in ASP.Net Core DI tool, but it’s extremely limited and I was getting frustrated with how many things were missing and how much more hand holding it took to be usable compared to StructureMap.

If you saw my Jasper’s Special Sauce post last week, you know that we are already using the service registration information to opt into inlining all the object construction and disposal directly into the generated message handlers whenever possible. The code that did that was effectively the beginning of a real IoC container, so it wasn’t that big of a jump to pulling all of that code into its own library and building it into the IoC tool that I wanted a theoretical StructureMap 5.0 to be.

 

4 thoughts on “Introducing BlueMilk: StructureMap’s Replacement & Jasper’s Special Sauce

Leave a comment