Saturday, October 3, 2026

C# Dependency Injection: What Happens When the Same Service Is Registered Twice?

In a .NET 10 web service, I recently found ILogger registered twice in Program.cs: 

services.AddSingleton<ILogger>(sp =>
    new ControlPlaneLogger(
        sp.GetRequiredService<IArchitecturalPlanesFactory>()
          .GetControlPlaneLogger()));
services.AddSingleton<ILogger>(sp =>
    new ControlPlaneLogger(
        sp.GetRequiredService<IArchitecturalPlanesFactory>()
          .GetDataPlaneLogger()));

No class in the project injected ILogger, so I wanted to know what happens when the same interface is registered more than once. The duplicate registrations in Program.cs did not throw an exception.

I unearthed the following from Microsoft's documentation (Service registration):

In plain English, the last registered ILogger is the one injected into a class constructor. In the original duplicate-registration example, the bolded registration is the one DI will resolve for ILogger:

services.AddSingleton<ILogger>(sp =>
    new ControlPlaneLogger(
        sp.GetRequiredService<IArchitecturalPlanesFactory>()
          .GetControlPlaneLogger()));
services.AddSingleton<ILogger>(sp =>
    new ControlPlaneLogger(
        sp.GetRequiredService<IArchitecturalPlanesFactory>()
          .GetDataPlaneLogger()));




Friday, October 2, 2026

Claude Code Blurts Out "Footgun": A Legitimate Software Anti-Pattern

While working with Claude Code, Sonnet 5.x diagnosed some C# I inherited as containing a "footgun." I had never heard the term footgun before. I mean, the most lethal footwork I'd seen was Rosa Klebb’s poison-tipped shoe blades immortalized in 'From Russia with Love.'

In modern computer science nomenclature, a footgun is a design that is technically valid but makes it unnecessarily easy for a developer to make a mistake.

A close-to-real-world example of this is as follows:

ILogger dataPlaneLogger =
           _architecturalPlanesFactory.GetDataPlaneLogger();

The factory method indicates that the logger is Data Plane specific. But the returned type is ILogger, which for all intents and purposes could be anything (log to a UDP port, log to Cloudflare R2 blob store, log to App Insights).

The factory makes the ambiguity explicit:

ILogger GetDataPlaneLogger();
ILogger GetControlPlaneLogger();

After that assignment, the type system no longer knows that this is the Data Plane logger. A variable named dataPlaneLogger cannot enforce that it was returned by method GetDataPlaneLogger. It is just another ILogger.

This is exacerbated by dependency injection. Consider a .NET 10 / C# class that requires a logging sink for the Control Plane and a logger sink for the Data Plane:

public class PlaneService(
                 ILogger controlPlaneLogger,
                 ILogger dataPlaneLogger)
{
}

The parameter names communicate intent to a human, but dependency injection resolves both services as the same type: ILogger. The primary constructor has two parameters of the same type, so there is no type-level distinction between logging to the Control Plane and logging to the Data Plane.

This ambiguity is an example of a footgun.


Thursday, October 1, 2026

LinkedIn Jobs: How to Sort by Most Recent When the Sort Option Is Missing

LinkedIn’s newer Jobs interface may not show a visible “Sort by Most Recent” option. What is the point of applying for an eleven-month-old job? Fear not! You can still favor more recently posted jobs by adding the following to the end of your LinkedIn Jobs search URL and reloading the page:

&sortBy=DD

However, LinkedIn does not appear to sort the results in strict chronological order. You may still see jobs posted 8 hours ago, 3 hours ago, 2 hours ago, and 10 hours ago mixed together.