autofac, dotnet comments edit

Alex and I have been working on deprecating the ability to update an Autofac container after it’s already been built. There are lots of reasons for this, and if you’re curious about that or have feedback on it, we have a discussion issue set up. You can also see ways to work around the need to update the container in that issue, so check it out.

However, one of the main reasons we’ve heard about why people want to update the container is to handle conditional registrations. For example, “I only want ComponentB registered in the container if ComponentA is not registered.”

To that end, in version 4.4.0 we’ve added OnlyIf() and IfNotRegistered() extensions to support conditional registration.

OnlyIf() lets you provide a lambda that acts on an IComponentRegistry. You can check if something is or isn’t registered and have some other registration execute only if the predicate returns true.

IfNotRegistered() is a convenience method built on OnlyIf() that allows you to execute a registration if some other service is not registered.

The documentation has been updated to explain how it works including examples but here’s a taste:

var builder = new ContainerBuilder();

// Only ServiceA will be registered.
// Note the IfNotRegistered takes the SERVICE TYPE to
// check for (the As<T>), NOT the COMPONENT TYPE
// (the RegisterType<T>).
builder.RegisterType<ServiceA>()
       .As<IService>();
builder.RegisterType<ServiceB>()
       .As<IService>()
       .IfNotRegistered(typeof(IService));

// HandlerA WILL be registered - it's running
// BEFORE HandlerB has a chance to be registered
// so the IfNotRegistered check won't find it.
//
// HandlerC will NOT be registered because it
// runs AFTER HandlerB. Note it can check for
// the type "HandlerB" because HandlerB registered
// AsSelf() not just As<IHandler>(). Again,
// IfNotRegistered can only check for "As"
// types.
builder.RegisterType<HandlerA>()
       .AsSelf()
       .As<IHandler>()
       .IfNotRegistered(typeof(HandlerB));
builder.RegisterType<HandlerB>()
       .AsSelf()
       .As<IHandler>();
builder.RegisterType<HandlerC>()
       .AsSelf()
       .As<IHandler>()
       .IfNotRegistered(typeof(HandlerB));

// Manager will be registered because both an IService
// and HandlerB are registered. The OnlyIf predicate
// can allow a lot more flexibility.
builder.RegisterType<Manager>()
       .As<IManager>()
       .OnlyIf(reg =>
         reg.IsRegistered(new TypedService(typeof(IService))) &&
         reg.IsRegistered(new TypedService(typeof(HandlerB))));

// This is when the conditionals actually run. Again,
// they run in the order the registrations were added
// to the ContainerBuilder.
var container = builder.Build();

If that’s something you’re into, head over to NuGet, grab v4.4.0 of Autofac, and try it out. Find something not working? Let us know!

ndepend, dotnet comments edit

It’s a new year, and with that comes a new version of NDepend - 2017.1. I’ve looked at NDepend before and am a big fan. This time they’ve added a feature that I’m particularly excited about: Technical Debt Estimation

One of the challenges I’ve seen when trying to communicate to non-technical folks about things I find in NDepend is cost. “How much is it going to cost to fix issue X?” Estimation is a tough thing. Now NDepend can help you with that.

First, in your project you need to configure your Issue and Debt settings. This is where you set things like…

  • How many work hours are in a day / work days in a year?
  • What’s the average cost of a person-hour (and in which currency)?
  • What are the various thresholds that define issue severity levels?

There are quite a lot of configuration options. Luckily, NDepend provides a lot of good doc on what the settings mean so you can configure them based on your project/company. And if you have a lot of projects that use the same settings, you can share the settings with a central .ndsettings file.

Issue and Debt settings (click to enlarge)

For my example, I’m just using the default settings.

Once you have that set up and you run analysis, your dashboard will show you your debt “rating” based on the SQALE method and estimate the amount of effort to improve the code to the next rating.

Debt displayed on the dashboard

The little “Explore Debt” button there will open up a query window that shows, for example, how much it would cost to fix each of the various queries you’ve applied to the code.

Debt associated with queries

In this case, you can see that this project has some pretty extensive debt related to the UI talking directly to the data access layer - 47 days’ worth if I wanted to fix it all! However, I might be able to fix up some static field naming conventions in a couple of days and save myself a day’s worth of interest accumulating each year - head it off before it gets too big.

I can also look at a prioritized list of types to fix - places I might get the biggest bang for my buck.

Prioritized type list

How much is it going to cost in terms of money, not just time?

Simple enough, just update your Issue and Debt settings to show both time and money…

Change value format

…and the report automatically updates to reflect that:

Prioritized type list with time and money displayed

Obviously it may take some tweaking of the settings to reflect the situation in your environment, but this is a huge help when it comes to communicating cost/benefit when looking to update code that is working but is worth cleaning up.

And, of course, you shouldn’t let anyone instantly just take it as gospel. It’s a tool. It will help you get started and make it easier to communicate, but you really shouldn’t substitute a generated estimate for something provided by the people actually doing the work.

Go grab yourself a copy of NDepend 2017 and get estimating!

Full disclosure: I got a free personal license from Patrick at NDepend. However, we have also purchased several licenses at work and make use of it to great benefit.

blog, downloads comments edit

Over the years I’ve pushed out a lot of little downloads, source, and code snippets on my blog. Yesterday I finally got all of that moved out of the various little dump sites on disks and in private repos and into GitHub.

I’ll continue updating links and adding things when I find them, but you should be able to see most everything there:

  • Repositories (contain more fully-fledged projects and things that can be built)
  • Gists (contain one-off files and snippets)

It was kind of a blast from the past looking at some of that stuff. I can see how I’ve changed styles and improved. Who doesn’t look at stuff they wrote 10 years ago and shake their head?

I could also see where I used certain tools or tech back then and don’t anymore. Like… remember when T4 didn’t exist and CodeSmith was the way to generate things? Anyone remember the Prototype JS library? Building with NAnt?

I can’t promise all of it will compile as-is. For example, I see a lot of VS 2003 and VS 2005 solutions in there. Will that straight-up convert to VS 2015+? Your guess is as good as mine.

Anyway, it felt good to get things centralized, even if it’s not all stellar code.

personal, family, humor comments edit

Captain’s Log: December 9, 2016.

School has been canceled for the second day in a row. The school district claims this is due to “potential safety concerns” for people coming in from higher elevations where there may be ice and snow, but our vessel is less than one mile from the school and there is nothing on the ground, nor is there anything falling from the heavens.

I think it’s a plot.

Of the regular crew of three, only two of us remain on board. The XO has gone on an away mission to work leaving me here with the first mate. I am attempting to address my standard duties but the first mate, being (what I understand is) a typical six-year-old, is fairly needy and in a constant attempt at mutiny.

I have considered throwing her in the brig but given the smallish size of the vessel, such sentences don’t last very long and definitely don’t have the desired effect. I have, however, informed her that if she continues her mutinous trend that her very life may be in danger. We’ll see how long she lasts when I throw her overboard into the icy waters.

There is constant rumblings of “nothing to do” and “super bored,” the suggested remedy for which is, naturally, “more television.” I have suggested several alternatives based on the diversions available on board, including - but not limited to - Barbies, Magnatiles, LEGOs, art projects, Playmobil make believe, stuffed animals, play kitchen, tea parties, dress up, and other various combinations of toys with inventive scenarios. None of these placate the desires of the restless first mate.

I find interruptions from the first mate come in at regular 15 minute intervals, almost as though she has a timer set somewhere. I will log such an interruption as an example here:

I was sitting in my office attempting to work through the daily reports. As I was sitting here, I heard a small but growing call.

“Daddy. Daddy. DADDY. DADDY. DAAADDDYYY. DAADDDYYYYYY!!!!!!!”

I raced from my office to find the cause of the call. The first mate was sitting eating breakfast.

“What is it, Phoenix? Are you hurt? With the amount of screaming, you’d best be really injured or bleeding or something.”

“I just wanted to tell you I love you.”

“NO. No, you don’t get to just screeeeam for no reason and then try to get away with it. Finish eating your breakfast.”

This sort of interruption occurs, as mentioned, fairly regularly. Either a call comes in or the first mate enters unannounced to make a nonsensical request.

I would ship her off to a neighboring vessel to play with one of her crewmates but I’m unfamiliar with the other ships’ captains so that’s not really an option. I believe one of her crewmates lives across the street. I will make a note to become more familiar with that vessel so I am not caught by surprise like this again.

Should our boat sink within the next few hours, this log explains the brewing storm being faced. There is a high probability that the first mate’s mutiny will succeed before the XO returns. When I am done with this log I will raise a distress call on the radio to see if any help may be coming. I have little hope.

teamcity, dotnet, build comments edit

I’ve run across more than my fair share of times, particularly early on in a project, where I need to flush the NuGet package cache for my TeamCity build agents. This has usually involved connecting to each agent in Remote Desktop and doing some manual commands or delete operations.

No more!

Instead of manually flushing the NuGet package cache, create a build configuration that does it for you.

Create a build configuration that isn’t attached to any source. The point of this build is to execute a script as the build user so the appropriate package cache gets cleared.

In the build configuration, add a single “Command Line” build step. Set the working directory to %teamcity.tool.NuGet.CommandLine.DEFAULT%\tools - this is where TeamCity has its default NuGet command line installation. For the custom script, put this:

echo ##teamcity[buildNumber '%build.counter% (%teamcity.agent.name%)']
nuget.exe locals -clear all

The first line sets the build number so you can see which agent ran it easily from the top-level dashboard. The build number will look like #24 (my-agent-name) The second line runs the actual NuGet package cache clearing command to ensure all the various cache locations get purged.

Now all you need to do is queue a build and target the agent you want to flush - it runs in a second or two and you’re done. No more need to connect and do it all manually.