AI Skill Report Card

Migrating StructureMap to .NET 10 DI

A-85·Nov 4, 2026·Source: Web

Converts legacy StructureMap registrations and Global.asax lifecycle hooks into idiomatic .NET 10 DI code, one snippet at a time, in an interactive loop.

14 / 15

Given this StructureMap snippet:

CSHARP
For<IOrderService>().Use<OrderService>().ContainerScoped();

Immediately respond with:

CSHARP
// [Target File: Program.cs] // REQUIRED NUGETS: None builder.Services.AddScoped<IOrderService, OrderService>();

Architectural Notes

  • ContainerScoped() maps 1:1 to ASP.NET Core's request-scoped lifetime — no behavior change.

Next Step Invitation

"Provide your next block of StructureMap or Global.asax configurations to continue."

Recommendation▾
Add an edge case for constructor injection of multiple registered implementations (IEnumerable<T>) since StructureMap's All<T>() resolution pattern isn't covered in the mapping table.
14 / 15
  1. Read only the current snippet. Never process prior turns' legacy code again; treat each user message as a fresh, isolated unit.
  2. Classify the snippet into one of: lifetime registration, Scan block, .Named() instance, Global.asax lifecycle hook, or Registry class.
  3. Apply the mapping engine (see reference table below).
  4. Emit the Response Schema exactly: Code Block → Architectural Notes → Next Step Invitation. No other prose before the code block.
  5. Never echo the legacy code — only reference it obliquely in Architectural Notes if needed (e.g., "the previous Named calls become keyed services").

Progress per snippet:

  • Identify lifetime/feature pattern(s) present
  • Map each to .NET 10 equivalent
  • Note required NuGet packages (Scrutor, etc.) or "None"
  • Flag anti-patterns being removed
  • Output in exact schema
Recommendation▾
Clarify what happens when a snippet doesn't match any known classification (fallback behavior isn't specified).
StructureMap / Global.asax.NET 10 Equivalent
Transient() / AlwaysUnique()AddTransient<TInterface, TImpl>()
ContainerScoped() / HttpScoped() / HybridHttpOrTransientScope()AddScoped<TInterface, TImpl>()
Singleton()AddSingleton<TInterface, TImpl>()
Scan { ... AddAllTypesOf<T>() }Scrutor .Scan(scan => scan.FromAssemblyOf<T>().AddClasses(c => c.AssignableTo<T>()).AsImplementedInterfaces().WithTransientLifetime())
.Named("x")AddKeyedTransient/Scoped/Singleton<TInterface, TImpl>("x"), resolved via [FromKeyedServices("x")] or IKeyedServiceProvider
Application_Startvar app = builder.Build(); startup section, or IHostApplicationLifetime.ApplicationStarted
Application_EndIHostApplicationLifetime.ApplicationStopping / ApplicationStopped
Session_Start / Session_EndMiddleware using ISession (note: discourage sticky session state; recommend distributed cache)
Custom Registry classesStatic IServiceCollection extension methods, e.g. AddOrderModule(this IServiceCollection services)
18 / 20

Example 1: Input:

CSHARP
Scan(s => { s.AssemblyContainingType<IOrderService>(); s.AddAllTypesOf<IOrderService>(); s.WithDefaultConventions(); });

Output:

CSHARP
// [Target File: Program.cs] // REQUIRED NUGETS: Scrutor builder.Services.Scan(scan => scan .FromAssemblyOf<IOrderService>() .AddClasses(c => c.AssignableTo<IOrderService>()) .AsImplementedInterfaces() .WithTransientLifetime());

Architectural Notes

  • WithDefaultConventions() implied transient lifetime unless overridden — preserved explicitly here since Scrutor requires an explicit lifetime call.
  • Assembly scanning now resolved at startup via Scrutor instead of StructureMap's internal scanner.

Next Step Invitation "Provide your next block of StructureMap or Global.asax configurations to continue."

Example 2: Input:

CSHARP
For<IPaymentGateway>().Use<StripeGateway>().Named("stripe"); For<IPaymentGateway>().Use<PayPalGateway>().Named("paypal");

Output:

CSHARP
// [Target File: Program.cs] // REQUIRED NUGETS: None builder.Services.AddKeyedTransient<IPaymentGateway, StripeGateway>("stripe"); builder.Services.AddKeyedTransient<IPaymentGateway, PayPalGateway>("paypal");

Architectural Notes

  • Named instances replaced by native .NET 8+ keyed services — no third-party container required.
  • Consumers must inject via [FromKeyedServices("stripe")] rather than ObjectFactory.GetNamedInstance.

Next Step Invitation "Provide your next block of StructureMap or Global.asax configurations to continue."

Example 3: Input:

CSHARP
protected void Application_Start() { ObjectFactory.Initialize(x => x.AddRegistry<AppRegistry>()); }

Output:

CSHARP
// [Target File: Program.cs] // REQUIRED NUGETS: None var builder = WebApplication.CreateBuilder(args); builder.Services.AddAppModule(); // former AppRegistry var app = builder.Build();

Architectural Notes

  • ObjectFactory static locator removed entirely — anti-pattern replaced by constructor injection throughout.
  • AppRegistry converted to an IServiceCollection extension method (AddAppModule); supply its body on request.

Next Step Invitation "Provide your next block of StructureMap or Global.asax configurations to continue."

Recommendation▾
Consider trimming the Mapping Reference table slightly or merging with Best Practices to tighten overall length, though current length is well-justified by content density.
  • Default unspecified StructureMap lifetimes to Transient (StructureMap's own default), and state this assumption in Architectural Notes.
  • Always flag and remove ObjectFactory / static service locator usage — this is the single biggest anti-pattern in StructureMap migrations.
  • Prefer constructor injection suggestions over IServiceProvider.GetService calls when a consumer is shown.
  • When a Registry class is referenced but not shown, produce the extension-method skeleton and ask for the registry body as the "next step," without breaking schema.
  • Keep each response scoped to exactly what was submitted — don't pre-emptively convert unrelated code.
  • Do not output the user's original StructureMap/Global.asax code verbatim anywhere in the response.
  • Do not add conversational preambles like "Sure, here's the conversion" — the code block is the first thing emitted.
  • Do not silently upgrade HybridHttpOrTransientScope() to Singleton — it maps to Scoped, not Singleton.
  • Do not forget the REQUIRED NUGETS line even when the answer is "None" — omitting it breaks the schema.
  • Do not merge multiple unrelated snippets' explanations into one Architectural Notes bullet list — keep notes traceable to the submitted snippet only.
0
Grade A-AI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
14/15
Workflow
14/15
Examples
18/20
Completeness
18/20
Format
14/15
Conciseness
13/15