Skip to main content

Fixing Incorrect Scope Injection of Services in .Net Core

Sometimes we inject Scope Services into singleton Services which may cause incorrect behavior of application, we will see how we can identify those objects or services

Incorrect Dependency Injection

Identifying and resolving issues caused by incorrect scope injection in services is crucial for maintaining the integrity and performance of a .NET Core application. Incorrectly scoped services can lead to unintended behavior, performance issues, or memory leaks.

It is very important to understand Lifetime of object in .NET core and how to register with incorrect lifetime.

Key rules

  • Transient services can be injected into any other lifetime.
  • Scoped services can be injected into other scoped services, or into transient services, but not into singletons.
  • Singleton services can only safely inject other singletons, not scoped or transient services.

Why?

  • Scoped services are disposed at the end of a request. Injecting a scoped service into a singleton would mean that the scoped service could be disposed of before the singleton finishes using it.
  • Transient services are created each time, so they can be injected into any service without issue, but it’s generally not a good idea to inject them into long-lived singletons.

Example and Implementation

Let’s see a incorrect injection example and how we will catch it.

  1. Creation of Scope Service.
public interface IScopedService
{
void DoSomeAction();
}

public class ScopedService : IScopedService
{
public void DoSomeAction()
{
Console.WriteLine("Performing scoped action...");
}
}

2. Creation of Singelton Service and scope service injection.

 public class MySingletonService
{
private readonly IScopedService _scopedService;

// Constructor injects a Scoped service into a Singleton (incorrect)
public MySingletonService(IScopedService scopedService)
{
_scopedService = scopedService;
}

public void Execute()
{
_scopedService.DoSomeAction();
}
}

3. Code to Catch incorrect scope injections

public static class ServiceCollectionExtensions
{
public static void ValidateServiceLifetimes(this IServiceCollection services)
{
var descriptors = services.ToList(); // Get all registered services

foreach (var descriptor in descriptors)
{
// Check for Singleton services that depend on Scoped or Transient services
if (descriptor.Lifetime == ServiceLifetime.Singleton)
{
var dependentServices = descriptors
.Where(d => d.Lifetime == ServiceLifetime.Scoped || d.Lifetime == ServiceLifetime.Transient)
.ToList();

foreach (var dependentService in dependentServices)
{
// If a Singleton service depends on a Scoped or Transient service, throw an exception
if (dependentService.ServiceType.IsAssignableFrom(descriptor.ServiceType))
{
throw new InvalidOperationException(
$"Service '{descriptor.ServiceType.Name}' with Singleton lifetime " +
$"cannot depend on service '{dependentService.ServiceType.Name}' with {dependentService.Lifetime} lifetime.");
}
}
}
}
}

4. Service Registration at Startup.cs

builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<MySingletonService>(); // Singleton
builder.Services.AddScoped<IScopedService, ScopedService>(); // Scoped

// Validate service lifetimes before application starts
builder.Services.ValidateServiceLifetimes();

5. Code execution

we can see , as we injected incorrect scope service into singelton we are getting error as per above screen shot.

Explanation

a. We created Scope Service named as: ScopedService

b. We created Singelton service : MySingletonService

c. We injected IScopedService into MySingletonService which is incorrect.

d. We created extension method ValidateServiceLifetimes on IServiceCollection

e. As per Rule below

Scoped services can be injected into other scoped services, or into transient services, but not into singletons.

we tried to find how many singelton services we have using below code

var descriptors = services.ToList();  // Get all registered services

foreach (var descriptor in descriptors)
{
// Check for Singleton services that depend on Scoped or Transient services
if (descriptor.Lifetime == ServiceLifetime.Singleton

we tried to find if scope service injected into singelton

var dependentServices = descriptors
.Where(d => d.Lifetime == ServiceLifetime.Scoped || d.Lifetime == ServiceLifetime.Transient)
.ToList();

foreach (var dependentService in dependentServices)
{

if such case or service found throw exception

foreach (var dependentService in dependentServices)
{
// If a Singleton service depends on a Scoped or Transient service, throw an exception
if (dependentService.ServiceType.IsAssignableFrom(descriptor.ServiceType))
{
throw new InvalidOperationException(
$"Service '{descriptor.ServiceType.Name}' with Singleton lifetime " +
$"cannot depend on service '{dependentService.ServiceType.Name}' with {dependentService.Lifetime} lifetime.");
}
}

Conclusion

We should follow correct rules for DI else we will get issues like memory leak or sometimes we will get Invalid operation exceptions.

Thanks Happy coding.

#coding

#injection

#dependencyinjection

#programming

#dotnetcore

Comments

Popular posts from this blog

Design Application using Clean Architecture

  Clean Architecture , introduced by  Robert C. Martin   (Uncle Bob), aims to create systems that are: Independent of frameworks Testable Independent of UI Independent of database Independent of any external agency Clean Architecture emphasizes separating the concerns of different parts of the system and ensuring that each part has a clear responsibility. .NET clean architecture as a development approach, available in a layered form to reduce dependency. The architecture consists of several layers, each with a specific role and dependencies that flow in one direction: from the outer layers to the inner layers. Inner most Layer is independent to its outer layer, means inner most layer does not have any references, it builds and stand independently. Dependency Rule The core principle of Clean Architecture is the  Dependency Rule , which states that source code dependencies can only point inward.  This means: Nothing in inner circle can depend on anything in an out...

How to Earn online from Medium.com

  As freelancer I started writing on medium (Tech blogs) from  Aug 2024   but I was already writing tech blogs on c-sharpcorner.com “The purpose of this post is to encourage new writers by helping them understand how they can earn as freelancers.” “Medium is a great platform for writers. When I started writing, I had no idea that I would reach the $100 benchmark in just four months. Now, I’m feeling self-inspired, as it has become a valuable source of income as a freelancer.” AUG 2024 ( $0 ) It was just beginning, and I posted 4 articles and had only few views 455 and 165 reads. During this time, I was learning about medium rules for writers and partner program. It will take some time to understand over all process. SEP 2024 ($6) As I started writing and I was getting few cents on Aug 2024, I posted 8 more articles in SEP, and it was good month because my blogs were getting noticed and I started getting claps etc. “This month, I went from $0 to $6, which was an achievemen...

Fixing High CPU Usage in .NET Core using Parallelism

  We will fix problem occurs due to incorrect use Parallelism in .NET Core To increase application performance sometimes we use process task or work extensively in Parallel and that may lead performance issue. When we do code, we should understand our requirement very carefully along with hardware resources those we have. We should code like that there should be less CPU usage and server should work without issues. In .NET Core, when you’re using parallelism (like Parallel.For, Task.WhenAll, or Task.Run), you might encounter performance issues if the number of concurrent threads or tasks exceeds what your system can efficiently handle. A common issue is high CPU usage or resource contention, which can degrade overall performance, cause excessive context switching, and even lead to thread starvation or deadlocks. Non members can access from here Effective Parallelism Strategies to Mitigate High CPU Usage in .NET Core We will fix problem occurs due to incorrect use Parallelism in .NE...