Mid From PDF MVC ASP.NET Core MVC

Explain built-in dependency injection in ASP.NET Core.

ASP.NET Core has a built-in Dependency Injection (DI) container, which means you

don’t need third-party frameworks like Autofac or Ninject.

DI allows you to register classes (services) in a central place and then inject them

wherever they’re needed. This promotes loose coupling, testability, and maintainability.

Example:

public interface IEmailService
{

void Send(string to, string subject, string body);

}
public class EmailService : IEmailService
{
public void Send(string to, string subject, string body)
=> Console.WriteLine($"Email sent to {to}");
}

Register it in Program.cs:

builder.Services.AddScoped<IEmailService, EmailService>();

Use it in a controller:

public class AccountController : Controller
{
private readonly IEmailService _emailService;
public AccountController(IEmailService emailService)
{
_emailService = emailService;
}
public IActionResult Register()
{

_emailService.Send("user@example.com", "Welcome!", "Thanks

for joining!");
return View();
}
}

🔁 2. What is the lifetime of services (Transient,

Scoped, Singleton)?

SP.NET Core provides three lifetimes for services:

Lifetime Description Example Use Case

Transien

new instance is created every time

the service is requested.

Lightweight, stateless services like

formatters or mappers.

Scoped A new instance is created per HTTP

request.

Database contexts, unit of work

patterns.

Singleto

single instance for the entire app

lifetime.

Configuration, caching, or logging

services.

Example:

builder.Services.AddTransient<IFormatter, TextFormatter>();

builder.Services.AddScoped<IProductRepository, ProductRepository>();

builder.Services.AddSingleton<IAppCache, MemoryAppCache>();

Tip: Scoped is most common for web apps — e.g., DbContext.

🧱 3. How do you inject dependencies into controllers?

ASP.NET Core automatically uses constructor injection for controllers.

The DI container will look at the constructor parameters and inject registered services.

Example:

public class OrderController : Controller
{
private readonly IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService;
}
public IActionResult Index() => View(_orderService.GetAll());
}

You don’t manually create OrderService; the framework does.

🔄 4. How do you resolve dependencies in

middleware?

Middleware is created once at startup, so you can’t inject scoped services directly into its

constructor.

Instead, you resolve them inside the Invoke method using the

HttpContext.RequestServices.

Example:

public class LoggingMiddleware
{
private readonly RequestDelegate _next;
public LoggingMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var logger =

context.RequestServices.GetRequiredService<ILogger<LoggingMiddleware

>>();

logger.LogInformation("Request path: " +

context.Request.Path);

wait _next(context);

}
}

Register it:

pp.UseMiddleware<LoggingMiddleware>();

🧰 5. How to use IServiceProvider?

IServiceProvider is the built-in service resolver. You can use it to manually resolve

registered dependencies.

Example:

var serviceProvider = builder.Services.BuildServiceProvider();
var emailService =

serviceProvider.GetRequiredService<IEmailService>();

emailService.Send("user@example.com", "Test", "DI working!");

In general:

  • Use IServiceProvider sparingly — prefer constructor injection.
  • Good for scenarios like custom factories or background tasks.

⚠ 6. What happens if a scoped service is injected into

singleton?

That’s a lifetime mismatch — it causes problems because:

  • The singleton lives for the app’s lifetime.
  • The scoped service lives only for a single request.
If a singleton holds a reference to a scoped service, that scoped instance never gets

released — leading to memory leaks and unexpected data sharing across requests.

Solution:

  • Don’t inject scoped services into singletons.
  • Instead, inject an IServiceProvider and create a scope manually when needed:
public class ReportGenerator
{
private readonly IServiceProvider _provider;
public ReportGenerator(IServiceProvider provider) => _provider =

provider;

public void Generate()
{
using var scope = _provider.CreateScope();
var db =

scope.ServiceProvider.GetRequiredService<AppDbContext>();

// Use db safely here

}
}

🧩 7. How to register multiple implementations for an

interface?

Sometimes you may have multiple implementations of the same interface — you can

register all of them and inject IEnumerable<T>.

Example:

builder.Services.AddTransient<INotificationService,

EmailNotification>();

builder.Services.AddTransient<INotificationService,

SmsNotification>();

Then:

public class NotificationManager
{
private readonly IEnumerable<INotificationService> _services;
public NotificationManager(IEnumerable<INotificationService>

services)

{
_services = services;
}
public void NotifyAll(string message)
{
foreach (var service in _services)

service.Send(message);

}
}

This will call both EmailNotification and SmsNotification.

🧱 8. What is TryAdd in dependency injection?

TryAdd methods (from

Microsoft.Extensions.DependencyInjection.Extensions) register a service

only if it’s not already registered.

Example:

builder.Services.TryAddScoped<ILogService, DefaultLogService>();

If another part of the code already registered a custom ILogService, this one won’t

override it.

Use Case:

When writing reusable libraries or frameworks that should allow overriding defaults.

⚙ 9. How do you inject configuration or options into

services?

You can bind configuration sections (from appsettings.json) to strongly typed

classes and inject them using IOptions<T>.

Example:

// appsettings.json

{

"SmtpSettings": {

"Host": "smtp.mailtrap.io",

"Port": 2525

}
}

Model:

public class SmtpSettings
{
public string Host { get; set; }
public int Port { get; set; }
}

Register:

builder.Services.Configure<SmtpSettings>(

builder.Configuration.GetSection("SmtpSettings"));

Use in service:

public class EmailService
{
private readonly SmtpSettings _settings;
public EmailService(IOptions<SmtpSettings> options)
{
_settings = options.Value;
}
}

🧠 10. What are IOptions, IOptionsSnapshot, and

IOptionsMonitor?

Interface 	Scope 	Use Case

IOptions<T> Singleton Read config at startup — doesn’t change at

runtime.

IOptionsSnapshot<T

Scoped (per

request)

Re-reads configuration on each request.

Useful in web apps.

IOptionsMonitor<T> Singleton, listens

for changes

utomatically updates when config changes

(great for dynamic reloading).

Example:

public class MyService
{
private readonly IOptionsMonitor<SmtpSettings> _settings;
public MyService(IOptionsMonitor<SmtpSettings> settings)
{
_settings = settings;
}
public void SendMail()
{

Console.WriteLine($"Sending using host:

{_settings.CurrentValue.Host}");

}
}
If you change appsettings.json and

configuration reload is enabled,

IOptionsMonitor picks up the new

value without restarting the app.

Entity Framework Core

More from ASP.NET Core MVC Tutorial

All questions for this course
Toolliyo Assistant
Ask about tutorials, ebooks, training, pricing, mentor services, and support. I use public site content only—not admin or internal tools.

care@toolliyo.com

Need callback? Share your details