Registering services
“How do you register a service in ASP.NET Core, and what happens if you forget one?”
The lines in Program.cs that tell the container: when someone asks for this, build that.
See it
In plain words
Program.cs holds a list of lines like AddScoped<ILoanService, LoanService>(). Each one means: when someone asks for , build a . Writing the list builds nothing; the builds objects later, when they are . Forget a line and the code still compiles, but the app fails when that object is needed. The word in the method name (Singleton, Scoped, Transient) says how long the object lives; that is .
- You register services on
builder.Services, an , by mapping a service type to an implementation and a lifetime: , or . - A missing registration is a runtime error, "Unable to resolve service for type X while attempting to activate Y", so I turn on and in every environment to fail at startup instead of on a user's request.
- If a type is registered twice, a single resolve gets the last registration and gets all of them.
- The check does not cover controllers unless I call , so an integration test that starts the app is the real safety net.
In the lending API
Program.cs before and after the fix. Both were run with .NET 10 and give the errors shown. Press Next line to walk through them.
Lending.sln · where these 2 files sit
- src/Api/
builder.Services is the list. Framework features register many rows in one call: adds everything MVC (the controller framework) needs.What they ask next
Interviewers check that you can explain every line. Tap a question to open it.
What exactly is the error?
On the first request:
InvalidOperationException: Unable to resolve service for type 'Lending.Application.Servicing.Loans.ILoanRepository' while attempting to activate 'Lending.Application.Servicing.Loans.LoanService'.Read it from the end: it was building LoanService and found no row for ILoanRepository. With the same message comes at startup, inside "Some services are not able to be constructed".Why not…Why did the unit tests not catch it?
Unit tests build themselves with and fake objects, so the container never runs. Only something that starts the real app, or at startup, reads Program.cs.
Why not…Development already checks at startup. Why turn it on in Production?
Production starts with the checks off, to save startup time. A registration that differs by environment, or a build that was never run locally, then fails only on a user's request. With the checks on, the new version fails at startup; in a or rolling deploy (the new version must start before it gets traffic), the old version keeps serving.
Does check controllers too?
No. Controllers are not in the list by default; MVC builds them itself. A controller asking for a missing service still fails only on the request.
AddControllers().AddControllersAsServices()puts them in the list, so the startup check covers them. Both were tested with .NET 10.What happens if I register the same service twice?
No error. Asking for one gets the one registered last. Asking for gets all of them, in order. Integration tests rely on this to replace a real service with a fake.
How do I register only if nothing is there yet?
TryAddSingleton<ICountryRules, IndiaRules>()adds the row only when no row exists. Libraries use so your own registration wins.
Explain this lineWhy register the interface and not just the class?
So depends on the , not the class. Swapping for the EF Core repository is then one line in Program.cs. You can register a class by itself,
AddScoped<LoanService>(), but then everyone who asks gets exactly that class.What is ?
The type of
builder.Services: a plain list of descriptors, each with a service type, an implementation and a lifetime.Build()turns it into the , the , and the list can no longer change.
Traps
- Don't say
Registering a service creates the object.SayRegistering only adds a row to a list. The container builds the object the first time someone asks for it. - Don't say
If it compiles, the DI wiring is fine.SayA missing registration compiles. It fails at runtime, unless checks it at startup. - Don't say
Registering a service twice throws an error.SayNo error. Asking for one gets the last one; gets all of them.
An AI tool often adds a new constructor parameter to a service and forgets the matching line in Program.cs. It compiles and the unit tests pass, because they never touch the container. Interviews now include reviewing AI-written code, and "where is this registered?" is the catch. makes that mistake fail at startup.