search
csharp star Featured

Fix: Cannot consume scoped service from singleton error in C#

Learn how to fix the 'Cannot consume scoped service from singleton' error in C# dependency injection. This comprehensive guide covers service lifetimes, proper registration patterns, and architectural solutions.

person By Gautam Sharma
calendar_today January 8, 2026
schedule 24 min read
C# Dependency Injection DI Service Lifetime Error ASP.NET Core IoC Container Scoped Singleton

The ‘Cannot consume scoped service from singleton’ error is a common issue in C# applications that use dependency injection (DI). This error occurs when a singleton service attempts to depend on a scoped service, creating an invalid lifetime configuration. Understanding and resolving this error is crucial for building maintainable C# applications with proper dependency injection patterns.

This comprehensive guide explains what causes the ‘Cannot consume scoped service from singleton’ error, why it happens, and provides multiple solutions to fix and prevent it in your C# projects with clean code examples and directory structure.


What is the “Cannot consume scoped service from singleton” error?

The “Cannot consume scoped service from singleton” error occurs when:

  • A singleton service has a dependency on a scoped service
  • Attempting to register a singleton that depends on a scoped service
  • Using incorrect service lifetime combinations in DI
  • Creating circular dependencies with different lifetimes
  • Misconfiguring service lifetimes in the DI container

Common Error Messages:

  • System.AggregateException: Some services are not able to be constructed: Cannot consume scoped service 'MyNamespace.IScopedService' from singleton 'MyNamespace.ISingletonService'
  • InvalidOperationException: Cannot resolve scoped service 'MyNamespace.IScopedService' from root provider
  • System.InvalidOperationException: Cannot resolve 'MyNamespace.IScopedService' from root provider because it requires a scoped service provider
  • Microsoft.Extensions.DependencyInjection: Cannot consume scoped service from singleton

Understanding the Problem

In C#, dependency injection uses different service lifetimes to manage object creation and disposal. The three main lifetimes are:

  • Singleton: One instance for the entire application lifetime
  • Scoped: One instance per request/operation scope
  • Transient: New instance every time it’s requested

The error occurs because a singleton service is created once and lives for the entire application lifetime, while scoped services are created per request and disposed at the end of the request. When a singleton tries to access a scoped service, it would need access to a request-specific instance, which is not available in the singleton’s context.

Typical C# Project Structure:

MyCSharpApp/
├── MyCSharpApp.sln
├── src/
│   ├── MyCSharpApp/
│   │   ├── Program.cs
│   │   ├── Startup.cs
│   │   ├── Controllers/
│   │   │   ├── HomeController.cs
│   │   │   └── UserController.cs
│   │   ├── Models/
│   │   │   ├── User.cs
│   │   │   └── Product.cs
│   │   ├── Services/
│   │   │   ├── IScopedService.cs
│   │   │   ├── ScopedService.cs
│   │   │   ├── ISingletonService.cs
│   │   │   ├── SingletonService.cs
│   │   │   ├── ITransientService.cs
│   │   │   └── TransientService.cs
│   │   ├── Repositories/
│   │   │   ├── IUserRepository.cs
│   │   │   └── UserRepository.cs
│   │   ├── MyCSharpApp.csproj
│   │   └── appsettings.json
│   └── MyCSharpApp.Tests/
│       ├── UnitTests.cs
│       └── MyCSharpApp.Tests.csproj
├── packages/
└── bin/

Solution 1: Proper Service Lifetime Matching

The most fundamental approach to prevent this error is to ensure service lifetimes are compatible.

❌ With Lifetime Mismatch:

// Services/SingletonService.cs - ❌ Singleton depending on scoped service
using MyCSharpApp.Repositories;
using System;

namespace MyCSharpApp.Services
{
    public class SingletonService : ISingletonService
    {
        private readonly IUserRepository _userRepository; // ❌ Scoped service

        public SingletonService(IUserRepository userRepository) // ❌ Error: Scoped service in singleton
        {
            _userRepository = userRepository;
        }

        public void DoWork()
        {
            // ❌ This will fail when trying to access scoped service
            var users = _userRepository.GetAll(); // ❌ Cannot access scoped service from singleton
        }
    }
}

✅ With Proper Lifetime Matching:

Services/ISingletonService.cs:

namespace MyCSharpApp.Services
{
    public interface ISingletonService
    {
        void DoWork();
        string GetAppInfo();
        void LogOperation(string operation);
    }
}

Services/IScopedService.cs:

using MyCSharpApp.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MyCSharpApp.Services
{
    public interface IScopedService
    {
        Task<List<User>> GetUsersAsync();
        Task<User> GetUserByIdAsync(int id);
        Task<User> CreateUserAsync(User user);
        string GetRequestInfo();
    }
}

Services/ITransientService.cs:

namespace MyCSharpApp.Services
{
    public interface ITransientService
    {
        string GenerateId();
        void ProcessData(string data);
        int GetRandomNumber();
    }
}

Services/SingletonService.cs:

using Microsoft.Extensions.Logging;
using System;

namespace MyCSharpApp.Services
{
    public class SingletonService : ISingletonService
    {
        private readonly ILogger<SingletonService> _logger;
        private readonly ITransientService _transientService;

        public SingletonService(
            ILogger<SingletonService> logger,
            ITransientService transientService) // ✅ Transient service is safe in singleton
        {
            _logger = logger;
            _transientService = transientService;
        }

        public void DoWork()
        {
            // ✅ Safe to use transient service
            var id = _transientService.GenerateId();
            _logger.LogInformation($"Performing work with ID: {id}");
        }

        public string GetAppInfo()
        {
            return $"App running since {DateTime.UtcNow}";
        }

        public void LogOperation(string operation)
        {
            _logger.LogInformation($"Operation performed: {operation} at {DateTime.UtcNow}");
        }

        // ✅ Additional singleton service methods
        public string GetServiceInstanceId()
        {
            return $"SingletonService_{Guid.NewGuid()}";
        }

        public void ProcessGlobalData()
        {
            // ✅ Perform application-wide operations
            _logger.LogInformation("Processing global application data");
        }

        public void InitializeAppServices()
        {
            // ✅ Initialize services that should only happen once
            _logger.LogInformation("Initializing application services");
        }

        public void CleanupResources()
        {
            // ✅ Perform cleanup that happens once
            _logger.LogInformation("Cleaning up application resources");
        }

        public DateTime GetAppStartTime()
        {
            return DateTime.UtcNow;
        }

        public void ValidateConfiguration()
        {
            // ✅ Validate application configuration
            _logger.LogInformation("Validating application configuration");
        }
    }
}

Services/ScopedService.cs:

using Microsoft.Extensions.Logging;
using MyCSharpApp.Models;
using MyCSharpApp.Repositories;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MyCSharpApp.Services
{
    public class ScopedService : IScopedService
    {
        private readonly IUserRepository _userRepository;
        private readonly ILogger<ScopedService> _logger;
        private readonly string _requestId;

        public ScopedService(
            IUserRepository userRepository,
            ILogger<ScopedService> logger)
        {
            _userRepository = userRepository;
            _logger = logger;
            _requestId = Guid.NewGuid().ToString();
        }

        public async Task<List<User>> GetUsersAsync()
        {
            _logger.LogInformation($"Getting users for request: {_requestId}");
            return await _userRepository.GetAllAsync();
        }

        public async Task<User> GetUserByIdAsync(int id)
        {
            _logger.LogInformation($"Getting user {id} for request: {_requestId}");
            return await _userRepository.GetByIdAsync(id);
        }

        public async Task<User> CreateUserAsync(User user)
        {
            _logger.LogInformation($"Creating user for request: {_requestId}");
            return await _userRepository.CreateAsync(user);
        }

        public string GetRequestInfo()
        {
            return $"Request ID: {_requestId}";
        }

        // ✅ Additional scoped service methods
        public async Task<List<User>> GetActiveUsersAsync()
        {
            var allUsers = await GetUsersAsync();
            return allUsers.FindAll(u => u.IsActive);
        }

        public async Task<User> GetUserByEmailAsync(string email)
        {
            var allUsers = await GetUsersAsync();
            return allUsers.Find(u => u.Email.Equals(email, StringComparison.OrdinalIgnoreCase));
        }

        public async Task<int> GetUserCountAsync()
        {
            var users = await GetUsersAsync();
            return users.Count;
        }

        public async Task<bool> UserExistsAsync(int id)
        {
            var user = await GetUserByIdAsync(id);
            return user != null;
        }

        public async Task<List<User>> GetUsersByRoleAsync(string role)
        {
            var allUsers = await GetUsersAsync();
            return allUsers.FindAll(u => u.Role?.Equals(role, StringComparison.OrdinalIgnoreCase) == true);
        }

        public async Task<User> UpdateUserAsync(int id, User user)
        {
            var existingUser = await GetUserByIdAsync(id);
            if (existingUser == null)
            {
                return null;
            }

            existingUser.Name = user.Name;
            existingUser.Email = user.Email;
            existingUser.IsActive = user.IsActive;
            existingUser.Role = user.Role;

            return await _userRepository.UpdateAsync(id, existingUser);
        }
    }
}

Services/TransientService.cs:

using System;

namespace MyCSharpApp.Services
{
    public class TransientService : ITransientService
    {
        private readonly string _instanceId;

        public TransientService()
        {
            _instanceId = Guid.NewGuid().ToString();
        }

        public string GenerateId()
        {
            return $"Transient_{_instanceId}_{DateTime.UtcNow.Ticks}";
        }

        public void ProcessData(string data)
        {
            // ✅ Process data with this specific instance
            Console.WriteLine($"Processing data: {data} with instance: {_instanceId}");
        }

        public int GetRandomNumber()
        {
            return new Random().Next(1, 100);
        }

        // ✅ Additional transient service methods
        public string GetInstanceId()
        {
            return _instanceId;
        }

        public DateTime GetCreationTime()
        {
            return DateTime.UtcNow;
        }

        public string GetInstanceInfo()
        {
            return $"TransientService Instance: {_instanceId}, Created: {GetCreationTime()}";
        }

        public T CloneObject<T>(T obj) where T : ICloneable
        {
            return (T)obj.Clone();
        }

        public bool ValidateData(string data)
        {
            return !string.IsNullOrWhiteSpace(data);
        }

        public string FormatData(string data)
        {
            return data?.Trim().ToUpper() ?? string.Empty;
        }
    }
}

Repositories/IUserRepository.cs:

using MyCSharpApp.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MyCSharpApp.Repositories
{
    public interface IUserRepository
    {
        Task<List<User>> GetAllAsync();
        Task<User> GetByIdAsync(int id);
        Task<User> CreateAsync(User user);
        Task<User> UpdateAsync(int id, User user);
        Task<bool> DeleteAsync(int id);
    }
}

Repositories/UserRepository.cs:

using MyCSharpApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyCSharpApp.Repositories
{
    public class UserRepository : IUserRepository
    {
        private readonly List<User> _users;

        public UserRepository()
        {
            // ✅ Initialize with sample data
            _users = new List<User>
            {
                new User { Id = 1, Name = "John Doe", Email = "john@example.com", IsActive = true, Role = "Admin" },
                new User { Id = 2, Name = "Jane Smith", Email = "jane@example.com", IsActive = true, Role = "User" },
                new User { Id = 3, Name = "Bob Johnson", Email = "bob@example.com", IsActive = false, Role = "User" }
            };
        }

        public async Task<List<User>> GetAllAsync()
        {
            return await Task.FromResult(_users.ToList());
        }

        public async Task<User> GetByIdAsync(int id)
        {
            var user = _users.FirstOrDefault(u => u.Id == id);
            return await Task.FromResult(user);
        }

        public async Task<User> CreateAsync(User user)
        {
            user.Id = _users.Any() ? _users.Max(u => u.Id) + 1 : 1;
            user.CreatedAt = DateTime.UtcNow;
            _users.Add(user);
            return await Task.FromResult(user);
        }

        public async Task<User> UpdateAsync(int id, User user)
        {
            var existingUser = _users.FirstOrDefault(u => u.Id == id);
            if (existingUser == null)
            {
                return null;
            }

            existingUser.Name = user.Name;
            existingUser.Email = user.Email;
            existingUser.IsActive = user.IsActive;
            existingUser.Role = user.Role;
            existingUser.UpdatedAt = DateTime.UtcNow;

            return await Task.FromResult(existingUser);
        }

        public async Task<bool> DeleteAsync(int id)
        {
            var user = _users.FirstOrDefault(u => u.Id == id);
            if (user == null)
            {
                return false;
            }

            _users.Remove(user);
            return await Task.FromResult(true);
        }

        // ✅ Additional repository methods
        public async Task<List<User>> GetActiveUsersAsync()
        {
            var activeUsers = _users.Where(u => u.IsActive).ToList();
            return await Task.FromResult(activeUsers);
        }

        public async Task<User> GetByEmailAsync(string email)
        {
            var user = _users.FirstOrDefault(u => u.Email.Equals(email, StringComparison.OrdinalIgnoreCase));
            return await Task.FromResult(user);
        }

        public async Task<int> GetCountAsync()
        {
            return await Task.FromResult(_users.Count);
        }

        public async Task<List<User>> GetByRoleAsync(string role)
        {
            var users = _users.Where(u => u.Role?.Equals(role, StringComparison.OrdinalIgnoreCase) == true).ToList();
            return await Task.FromResult(users);
        }
    }
}

Program.cs (for .NET 6+):

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MyCSharpApp.Repositories;
using MyCSharpApp.Services;

var builder = WebApplication.CreateBuilder(args);

// ✅ Register services with proper lifetimes
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// ✅ Register services with correct lifetimes
builder.Services.AddSingleton<ISingletonService, SingletonService>(); // ✅ Singleton
builder.Services.AddScoped<IUserRepository, UserRepository>(); // ✅ Scoped
builder.Services.AddScoped<IScopedService, ScopedService>(); // ✅ Scoped
builder.Services.AddTransient<ITransientService, TransientService>(); // ✅ Transient
builder.Services.AddLogging(); // ✅ Logging

var app = builder.Build();

// ✅ Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Solution 2: Use Service Factory Pattern

Use a factory pattern to create scoped services when needed from a singleton.

Services/IServiceScopeFactoryWrapper.cs:

using System;

namespace MyCSharpApp.Services
{
    public interface IServiceScopeFactoryWrapper
    {
        T GetScopedService<T>() where T : class;
        void ExecuteInScope(Action<IServiceProvider> action);
        TResult ExecuteInScope<TResult>(Func<IServiceProvider, TResult> func);
    }
}

Services/ServiceScopeFactoryWrapper.cs:

using Microsoft.Extensions.DependencyInjection;
using System;

namespace MyCSharpApp.Services
{
    public class ServiceScopeFactoryWrapper : IServiceScopeFactoryWrapper
    {
        private readonly IServiceProvider _serviceProvider;

        public ServiceScopeFactoryWrapper(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public T GetScopedService<T>() where T : class
        {
            var scope = _serviceProvider.CreateScope();
            return scope.ServiceProvider.GetRequiredService<T>();
        }

        public void ExecuteInScope(Action<IServiceProvider> action)
        {
            using var scope = _serviceProvider.CreateScope();
            action(scope.ServiceProvider);
        }

        public TResult ExecuteInScope<TResult>(Func<IServiceProvider, TResult> func)
        {
            using var scope = _serviceProvider.CreateScope();
            return func(scope.ServiceProvider);
        }
    }
}

Services/SingletonServiceWithFactory.cs:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MyCSharpApp.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MyCSharpApp.Services
{
    public class SingletonServiceWithFactory : ISingletonService
    {
        private readonly ILogger<SingletonServiceWithFactory> _logger;
        private readonly IServiceScopeFactory _serviceScopeFactory;

        public SingletonServiceWithFactory(
            ILogger<SingletonServiceWithFactory> logger,
            IServiceScopeFactory serviceScopeFactory)
        {
            _logger = logger;
            _serviceScopeFactory = serviceScopeFactory;
        }

        public void DoWork()
        {
            // ✅ Use service scope factory to access scoped services
            using var scope = _serviceScopeFactory.CreateScope();
            var scopedService = scope.ServiceProvider.GetRequiredService<IScopedService>();
            
            // ✅ Now we can safely use the scoped service
            var requestInfo = scopedService.GetRequestInfo();
            _logger.LogInformation($"Work performed in request: {requestInfo}");
        }

        public string GetAppInfo()
        {
            return $"App running with factory pattern since {DateTime.UtcNow}";
        }

        public void LogOperation(string operation)
        {
            _logger.LogInformation($"Operation performed via factory: {operation} at {DateTime.UtcNow}");
        }

        // ✅ Additional methods using scoped services
        public async Task<List<User>> GetUsersFromBackgroundTask()
        {
            using var scope = _serviceScopeFactory.CreateScope();
            var scopedService = scope.ServiceProvider.GetRequiredService<IScopedService>();
            return await scopedService.GetUsersAsync();
        }

        public async Task<User> GetUserByIdFromBackgroundTask(int id)
        {
            using var scope = _serviceScopeFactory.CreateScope();
            var scopedService = scope.ServiceProvider.GetRequiredService<IScopedService>();
            return await scopedService.GetUserByIdAsync(id);
        }

        public async Task<User> CreateUserFromBackgroundTask(User user)
        {
            using var scope = _serviceScopeFactory.CreateScope();
            var scopedService = scope.ServiceProvider.GetRequiredService<IScopedService>();
            return await scopedService.CreateUserAsync(user);
        }

        public async Task ProcessUsersInBackground()
        {
            var users = await GetUsersFromBackgroundTask();
            _logger.LogInformation($"Processing {users.Count} users in background task");
        }
    }
}

Solution 3: Use IOptions Pattern for Configuration

For configuration data that singleton services need, use the IOptions pattern instead of scoped services.

Models/AppSettings.cs:

namespace MyCSharpApp.Models
{
    public class AppSettings
    {
        public string AppName { get; set; } = "My Application";
        public string Version { get; set; } = "1.0.0";
        public string Environment { get; set; } = "Development";
        public DatabaseSettings Database { get; set; } = new DatabaseSettings();
        public EmailSettings Email { get; set; } = new EmailSettings();
    }

    public class DatabaseSettings
    {
        public string ConnectionString { get; set; } = string.Empty;
        public int CommandTimeout { get; set; } = 30;
    }

    public class EmailSettings
    {
        public string SmtpServer { get; set; } = string.Empty;
        public int Port { get; set; } = 587;
        public string Username { get; set; } = string.Empty;
        public string Password { get; set; } = string.Empty;
    }
}

Services/ConfigurableSingletonService.cs:

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MyCSharpApp.Models;
using System;

namespace MyCSharpApp.Services
{
    public class ConfigurableSingletonService : ISingletonService
    {
        private readonly ILogger<ConfigurableSingletonService> _logger;
        private readonly AppSettings _appSettings;

        public ConfigurableSingletonService(
            ILogger<ConfigurableSingletonService> logger,
            IOptions<AppSettings> appSettingsOptions)
        {
            _logger = logger;
            _appSettings = appSettingsOptions.Value;
        }

        public void DoWork()
        {
            // ✅ Use configuration from IOptions instead of scoped service
            _logger.LogInformation($"Performing work in {_appSettings.Environment} environment");
        }

        public string GetAppInfo()
        {
            return $"{_appSettings.AppName} v{_appSettings.Version} in {_appSettings.Environment}";
        }

        public void LogOperation(string operation)
        {
            _logger.LogInformation($"[{_appSettings.AppName}] Operation: {operation}");
        }

        // ✅ Additional methods using configuration
        public string GetDatabaseConnectionString()
        {
            return _appSettings.Database.ConnectionString;
        }

        public string GetAppName()
        {
            return _appSettings.AppName;
        }

        public string GetEnvironment()
        {
            return _appSettings.Environment;
        }

        public void ValidateConfiguration()
        {
            if (string.IsNullOrEmpty(_appSettings.Database.ConnectionString))
            {
                _logger.LogWarning("Database connection string is not configured");
            }
        }

        public EmailSettings GetEmailSettings()
        {
            return _appSettings.Email;
        }
    }
}

appsettings.json:

{
  "AppSettings": {
    "AppName": "My C# Application",
    "Version": "1.0.0",
    "Environment": "Development",
    "Database": {
      "ConnectionString": "Server=localhost;Database=MyApp;Trusted_Connection=true;",
      "CommandTimeout": 30
    },
    "Email": {
      "SmtpServer": "smtp.example.com",
      "Port": 587,
      "Username": "user@example.com",
      "Password": "password"
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

Solution 4: Refactor to Use Transient Services

Sometimes the solution is to change the scoped service to a transient service if it doesn’t need request-specific state.

Services/RefactoredScopedService.cs:

using Microsoft.Extensions.Logging;
using MyCSharpApp.Models;
using MyCSharpApp.Repositories;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MyCSharpApp.Services
{
    // ✅ This service is now designed to work as transient
    public class RefactoredScopedService : IScopedService
    {
        private readonly IUserRepository _userRepository;
        private readonly ILogger<RefactoredScopedService> _logger;
        private readonly string _instanceId;

        public RefactoredScopedService(
            IUserRepository userRepository,
            ILogger<RefactoredScopedService> logger)
        {
            _userRepository = userRepository;
            _logger = logger;
            _instanceId = Guid.NewGuid().ToString();
        }

        public async Task<List<User>> GetUsersAsync()
        {
            _logger.LogInformation($"Getting users with instance: {_instanceId}");
            return await _userRepository.GetAllAsync();
        }

        public async Task<User> GetUserByIdAsync(int id)
        {
            _logger.LogInformation($"Getting user {id} with instance: {_instanceId}");
            return await _userRepository.GetByIdAsync(id);
        }

        public async Task<User> CreateUserAsync(User user)
        {
            _logger.LogInformation($"Creating user with instance: {_instanceId}");
            return await _userRepository.CreateAsync(user);
        }

        public string GetRequestInfo()
        {
            // ✅ Return instance info instead of request-specific info
            return $"Instance ID: {_instanceId}";
        }

        // ✅ Additional methods that work without request context
        public async Task<List<User>> GetActiveUsersAsync()
        {
            var allUsers = await GetUsersAsync();
            return allUsers.FindAll(u => u.IsActive);
        }

        public async Task<User> GetUserByEmailAsync(string email)
        {
            var allUsers = await GetUsersAsync();
            return allUsers.Find(u => u.Email.Equals(email, StringComparison.OrdinalIgnoreCase));
        }

        public async Task<int> GetUserCountAsync()
        {
            var users = await GetUsersAsync();
            return users.Count;
        }
    }
}

Solution 5: Use AsyncLocal for Thread-Safe Context

For cases where you need to maintain context across async operations, use AsyncLocal.

Services/ContextAwareSingletonService.cs:

using Microsoft.Extensions.Logging;
using System;
using System.Threading;

namespace MyCSharpApp.Services
{
    public class ContextAwareSingletonService : ISingletonService
    {
        private readonly ILogger<ContextAwareSingletonService> _logger;
        private static readonly AsyncLocal<string> _requestContext = new AsyncLocal<string>();

        public ContextAwareSingletonService(ILogger<ContextAwareSingletonService> logger)
        {
            _logger = logger;
        }

        public void DoWork()
        {
            var context = _requestContext.Value ?? "No Context";
            _logger.LogInformation($"Performing work in context: {context}");
        }

        public string GetAppInfo()
        {
            return $"Context-aware service running since {DateTime.UtcNow}";
        }

        public void LogOperation(string operation)
        {
            var context = _requestContext.Value ?? "No Context";
            _logger.LogInformation($"Operation: {operation} in context: {context}");
        }

        // ✅ Methods to manage context
        public static void SetContext(string context)
        {
            _requestContext.Value = context;
        }

        public static string GetContext()
        {
            return _requestContext.Value;
        }

        public static void ClearContext()
        {
            _requestContext.Value = null;
        }

        public void ProcessWithContext(string context, Action action)
        {
            var originalContext = _requestContext.Value;
            try
            {
                _requestContext.Value = context;
                action();
            }
            finally
            {
                _requestContext.Value = originalContext;
            }
        }
    }
}

Working Code Examples

Complete C# Application with Proper Lifetime Management:

// Program.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MyCSharpApp.Models;
using MyCSharpApp.Repositories;
using MyCSharpApp.Services;

var builder = WebApplication.CreateBuilder(args);

// ✅ Add configuration
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
builder.Configuration.AddEnvironmentVariables();

// ✅ Register services with proper lifetimes
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// ✅ Register configuration
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings"));

// ✅ Register repositories and services with correct lifetimes
builder.Services.AddSingleton<ISingletonService, ConfigurableSingletonService>(); // ✅ Singleton with config
builder.Services.AddScoped<IUserRepository, UserRepository>(); // ✅ Scoped repository
builder.Services.AddScoped<IScopedService, ScopedService>(); // ✅ Scoped service
builder.Services.AddTransient<ITransientService, TransientService>(); // ✅ Transient service

// ✅ Register factory for accessing scoped services from singleton
builder.Services.AddSingleton<IServiceScopeFactoryWrapper, ServiceScopeFactoryWrapper>();
builder.Services.AddScoped<IServiceScopeFactoryWrapper, ServiceScopeFactoryWrapper>();

// ✅ Register services that need to access scoped services
builder.Services.AddSingleton<ISingletonService, SingletonServiceWithFactory>();

// ✅ Add logging
builder.Services.AddLogging();

var app = builder.Build();

// ✅ Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Controller with Properly Configured Services:

// Controllers/UserController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using MyCSharpApp.Models;
using MyCSharpApp.Services;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MyCSharpApp.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class UserController : ControllerBase
    {
        private readonly IScopedService _scopedService;
        private readonly ISingletonService _singletonService;
        private readonly ILogger<UserController> _logger;

        public UserController(
            IScopedService scopedService,
            ISingletonService singletonService,
            ILogger<UserController> logger)
        {
            _scopedService = scopedService;
            _singletonService = singletonService;
            _logger = logger;
        }

        [HttpGet]
        public async Task<IActionResult> GetUsers()
        {
            // ✅ Use properly scoped service
            var users = await _scopedService.GetUsersAsync();
            _logger.LogInformation($"Retrieved {users.Count} users");
            return Ok(users);
        }

        [HttpGet("{id}")]
        public async Task<IActionResult> GetUser(int id)
        {
            // ✅ Use properly scoped service
            var user = await _scopedService.GetUserByIdAsync(id);
            if (user == null)
            {
                return NotFound();
            }

            return Ok(user);
        }

        [HttpPost]
        public async Task<IActionResult> CreateUser([FromBody] User user)
        {
            // ✅ Use properly scoped service
            var createdUser = await _scopedService.CreateUserAsync(user);
            _logger.LogInformation($"Created user with ID: {createdUser.Id}");
            return CreatedAtAction(nameof(GetUser), new { id = createdUser.Id }, createdUser);
        }

        [HttpGet("app-info")]
        public IActionResult GetAppInfo()
        {
            // ✅ Use singleton service
            var appInfo = _singletonService.GetAppInfo();
            return Ok(new { AppInfo = appInfo });
        }

        [HttpPost("log-operation")]
        public IActionResult LogOperation([FromBody] string operation)
        {
            // ✅ Use singleton service for logging
            _singletonService.LogOperation(operation);
            return Ok(new { Message = "Operation logged" });
        }

        [HttpGet("request-info")]
        public IActionResult GetRequestInfo()
        {
            // ✅ Use scoped service for request-specific info
            var requestInfo = _scopedService.GetRequestInfo();
            return Ok(new { RequestInfo = requestInfo });
        }

        [HttpGet("active")]
        public async Task<IActionResult> GetActiveUsers()
        {
            // ✅ Use scoped service method
            var users = await _scopedService.GetActiveUsersAsync();
            return Ok(users);
        }

        [HttpGet("count")]
        public async Task<IActionResult> GetUserCount()
        {
            // ✅ Use scoped service method
            var count = await _scopedService.GetUserCountAsync();
            return Ok(new { count });
        }
    }
}

Unit Test Example:

// MyCSharpApp.Tests/UnitTests.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MyCSharpApp.Models;
using MyCSharpApp.Repositories;
using MyCSharpApp.Services;
using System;

namespace MyCSharpApp.Tests
{
    [TestClass]
    public class ServiceLifetimeTests
    {
        private ServiceProvider _serviceProvider;

        [TestInitialize]
        public void Setup()
        {
            var services = new ServiceCollection();

            // ✅ Register services with proper lifetimes
            var appSettings = new AppSettings
            {
                AppName = "Test App",
                Version = "1.0.0",
                Environment = "Test"
            };

            services.AddSingleton<IOptions<AppSettings>>(Options.Create(appSettings));
            services.AddSingleton<ISingletonService, ConfigurableSingletonService>();
            services.AddScoped<IUserRepository, UserRepository>();
            services.AddScoped<IScopedService, ScopedService>();
            services.AddTransient<ITransientService, TransientService>();
            services.AddTransient<IServiceScopeFactory, ServiceScopeFactory>();

            _serviceProvider = services.BuildServiceProvider();
        }

        [TestMethod]
        public void ServiceProvider_ResolvesSingletonService_Successfully()
        {
            // ✅ Act
            var singletonService = _serviceProvider.GetService<ISingletonService>();

            // ✅ Assert
            Assert.IsNotNull(singletonService);
            Assert.IsInstanceOfType(singletonService, typeof(ConfigurableSingletonService));
        }

        [TestMethod]
        public void ServiceProvider_ResolvesScopedServiceInScope_Successfully()
        {
            // ✅ Act
            using var scope = _serviceProvider.CreateScope();
            var scopedService = scope.ServiceProvider.GetService<IScopedService>();

            // ✅ Assert
            Assert.IsNotNull(scopedService);
            Assert.IsInstanceOfType(scopedService, typeof(ScopedService));
        }

        [TestMethod]
        public void ServiceProvider_ResolvesTransientService_Successfully()
        {
            // ✅ Act
            var transientService = _serviceProvider.GetService<ITransientService>();

            // ✅ Assert
            Assert.IsNotNull(transientService);
            Assert.IsInstanceOfType(transientService, typeof(TransientService));
        }

        [TestMethod]
        public void SingletonAndScopedServices_HaveDifferentLifetimes()
        {
            // ✅ Get singleton service
            var singletonService1 = _serviceProvider.GetService<ISingletonService>();
            var singletonService2 = _serviceProvider.GetService<ISingletonService>();

            // ✅ Get scoped services in different scopes
            IScopedService scopedService1, scopedService2;

            using (var scope1 = _serviceProvider.CreateScope())
            {
                scopedService1 = scope1.ServiceProvider.GetService<IScopedService>();
            }

            using (var scope2 = _serviceProvider.CreateScope())
            {
                scopedService2 = scope2.ServiceProvider.GetService<IScopedService>();
            }

            // ✅ Assert singleton services are the same instance
            Assert.AreSame(singletonService1, singletonService2);

            // ✅ Assert scoped services are different instances (even though disposed)
            // Note: In real usage, you'd compare instances within the same scope
            Assert.IsNotNull(scopedService1);
            Assert.IsNotNull(scopedService2);
        }

        [TestMethod]
        [ExpectedException(typeof(System.InvalidOperationException))]
        public void ServiceProvider_WithInvalidLifetime_ThrowsException()
        {
            var services = new ServiceCollection();
            
            // ✅ This would cause the error if we tried to resolve
            // services.AddSingleton<ISingletonService, InvalidSingletonService>(); // That depends on scoped
            
            var provider = services.BuildServiceProvider();
            
            // ✅ This would throw the "Cannot consume scoped service from singleton" error
            using var scope = provider.CreateScope();
            var singleton = scope.ServiceProvider.GetService<ISingletonService>();
        }
    }

    // ✅ Example of what NOT to do - this would cause the error
    public interface IInvalidSingletonService : ISingletonService { }
    
    public class InvalidSingletonService : IInvalidSingletonService
    {
        private readonly IScopedService _scopedService; // ❌ This causes the error
        
        public InvalidSingletonService(IScopedService scopedService)
        {
            _scopedService = scopedService;
        }
        
        public void DoWork() { }
        public string GetAppInfo() => "";
        public void LogOperation(string operation) { }
    }
}

Best Practices for Service Lifetimes

1. Match Service Lifetimes Appropriately

// ✅ Singleton can depend on singleton or transient
services.AddSingleton<IMySingletonService, MySingletonService>();
services.AddTransient<IDependency, Dependency>();

// ✅ Scoped can depend on scoped, singleton, or transient
services.AddScoped<IMyScopedService, MyScopedService>();
services.AddSingleton<ISingletonDependency, SingletonDependency>();

// ✅ Transient can depend on any lifetime
services.AddTransient<IMyTransientService, MyTransientService>();

2. Use Service Scope Factory When Needed

// ✅ Use service scope factory to access scoped services from singleton
public class MySingletonService
{
    private readonly IServiceScopeFactory _scopeFactory;
    
    public MySingletonService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }
    
    public async Task DoWork()
    {
        using var scope = _scopeFactory.CreateScope();
        var scopedService = scope.ServiceProvider.GetRequiredService<IScopedService>();
        // Use scoped service safely
    }
}

3. Design Services with Lifetime in Mind

// ✅ Design services to work with their intended lifetime
public class MyScopedService
{
    // ✅ Can safely store request-specific data
    private readonly string _requestId;
    
    public MyScopedService()
    {
        _requestId = Guid.NewGuid().ToString();
    }
}

4. Use IOptions for Configuration

// ✅ Use IOptions for configuration instead of scoped services
public class MySingletonService
{
    private readonly AppSettings _settings;
    
    public MySingletonService(IOptions<AppSettings> settings)
    {
        _settings = settings.Value;
    }
}

5. Validate Service Lifetimes During Startup

// ✅ Add validation in development
#if DEBUG
public static void ValidateServiceLifetimes(IServiceProvider serviceProvider)
{
    // Try to resolve all services to catch lifetime issues early
    using var scope = serviceProvider.CreateScope();
    var singleton = scope.ServiceProvider.GetService<ISingletonService>();
    var scoped = scope.ServiceProvider.GetService<IScopedService>();
    // Validate other services...
}
#endif

Debugging Steps

Step 1: Identify the Problematic Service

// Look for the specific error message to identify which services have lifetime conflicts
// Example: "Cannot consume scoped service 'MyNamespace.IScopedService' from singleton 'MyNamespace.ISingletonService'"
// The singleton service is trying to depend on the scoped service

Step 2: Check Service Dependencies

// ✅ Review the constructor of the singleton service
public class MySingletonService
{
    public MySingletonService(IScopedService scopedService) // ❌ This is the problem
    {
        // ...
    }
}

Step 3: Fix the Lifetime Mismatch

// ✅ Option 1: Use service scope factory
public class MyFixedSingletonService
{
    private readonly IServiceScopeFactory _scopeFactory;
    
    public MyFixedSingletonService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }
}

// ✅ Option 2: Change the service to scoped
services.AddScoped<IMyService, MyService>(); // Instead of AddSingleton

Step 4: Verify the Fix

// ✅ Test that the application starts without errors
// ✅ Test that services work as expected

Step 5: Use Diagnostic Tools

// ✅ Use dependency injection diagnostic tools
public void ConfigureServices(IServiceCollection services)
{
    // Register services
    services.AddSingleton<ISingletonService, MySingletonService>();
    services.AddScoped<IScopedService, MyScopedService>();
    
    // ✅ In development, validate the configuration
    #if DEBUG
    services.BuildServiceProvider(new ServiceProviderOptions 
    { 
        ValidateOnBuild = true,
        ValidateScopes = true 
    });
    #endif
}

Common Mistakes to Avoid

1. Direct Dependencies Between Incompatible Lifetimes

// ❌ Singleton depending directly on scoped service
public class MySingletonService
{
    public MySingletonService(IScopedService scopedService) // ❌ Error
    {
        // This will cause the error
    }
}

2. Storing Scoped Services in Singleton Fields

// ❌ Storing scoped service reference in singleton
public class MySingletonService
{
    private readonly IScopedService _scopedService; // ❌ Error
    
    public MySingletonService(IScopedService scopedService)
    {
        _scopedService = scopedService; // ❌ This will fail
    }
}

3. Incorrect Service Registration Order

// ❌ Registering services in wrong order can sometimes cause issues
// Always register dependencies before services that depend on them

4. Using AsyncLocal Improperly

// ❌ AsyncLocal can cause memory leaks if not used properly
// Make sure to clear AsyncLocal values when appropriate

5. Overcomplicating Simple Solutions

// ❌ Don't use complex patterns when simple lifetime changes would work
// Sometimes just changing from singleton to scoped is the right solution

Performance Considerations

1. Minimize Service Scope Creation

// ✅ Reuse service scopes when possible
using var scope = _scopeFactory.CreateScope();
var service1 = scope.ServiceProvider.GetRequiredService<IService1>();
var service2 = scope.ServiceProvider.GetRequiredService<IService2>();
// Use both services in the same scope

2. Consider Using Transient for Stateless Services

// ✅ If a service doesn't need request-specific state, consider making it transient
services.AddTransient<IMyService, MyService>(); // Instead of scoped

3. Cache Expensive Operations in Singleton

// ✅ Use singleton services for caching expensive operations
public class CachedSingletonService
{
    private readonly IMemoryCache _cache;
    
    public CachedSingletonService(IMemoryCache cache)
    {
        _cache = cache;
    }
    
    public async Task<T> GetCachedDataAsync<T>(string key, Func<Task<T>> factory)
    {
        if (!_cache.TryGetValue(key, out T result))
        {
            result = await factory();
            _cache.Set(key, result, TimeSpan.FromMinutes(10));
        }
        return result;
    }
}

Security Considerations

1. Validate Service Dependencies

// ✅ Ensure services don't expose sensitive data across requests
public class SecureSingletonService
{
    // ✅ Don't store request-specific sensitive data in singleton
    // Use service scope factory or other patterns instead
}

2. Protect Against Memory Leaks

// ✅ Be careful with AsyncLocal to avoid memory leaks
// Always clear AsyncLocal values when they're no longer needed

3. Secure Configuration Access

// ✅ Use IOptions for configuration instead of scoped services
// This prevents configuration data from being tied to request lifetimes

Testing Service Lifetimes

1. Unit Test Lifetime Compatibility

[TestMethod]
public void ServiceProvider_WithValidLifetimes_DoesNotThrow()
{
    var services = new ServiceCollection();
    
    // ✅ Register services with compatible lifetimes
    services.AddSingleton<ISingletonService, ConfigurableSingletonService>();
    services.AddScoped<IScopedService, ScopedService>();
    services.AddTransient<ITransientService, TransientService>();
    
    // ✅ This should not throw
    var provider = services.BuildServiceProvider();
    
    // ✅ Verify services can be resolved
    Assert.IsNotNull(provider.GetService<ISingletonService>());
}

2. Test Service Scope Factory Pattern

[TestMethod]
public async Task SingletonService_WithServiceScopeFactory_CanAccessScopedService()
{
    var services = new ServiceCollection();
    services.AddSingleton<ISingletonService, SingletonServiceWithFactory>();
    services.AddScoped<IScopedService, ScopedService>();
    services.AddScoped<IUserRepository, UserRepository>();
    services.AddLogging();
    
    var provider = services.BuildServiceProvider();
    var singletonService = provider.GetService<ISingletonService>();
    
    // ✅ This should work without throwing lifetime exceptions
    singletonService.DoWork();
    
    // ✅ Test async operations
    var factoryService = provider.GetService<ISingletonService>() as SingletonServiceWithFactory;
    if (factoryService != null)
    {
        var users = await factoryService.GetUsersFromBackgroundTask();
        Assert.IsNotNull(users);
    }
}

3. Test Different Lifetime Scenarios

[TestMethod]
public void ServiceLifetimes_AreCorrectlySeparated()
{
    var services = new ServiceCollection();
    services.AddSingleton<ISingletonService, ConfigurableSingletonService>();
    services.AddScoped<IScopedService, ScopedService>();
    services.AddTransient<ITransientService, TransientService>();
    
    var provider = services.BuildServiceProvider();
    
    // ✅ Test singleton lifetime
    var singleton1 = provider.GetService<ISingletonService>();
    var singleton2 = provider.GetService<ISingletonService>();
    Assert.AreSame(singleton1, singleton2);
    
    // ✅ Test scoped lifetime within scope
    IScopedService scoped1, scoped2;
    using (var scope1 = provider.CreateScope())
    {
        scoped1 = scope1.ServiceProvider.GetService<IScopedService>();
    }
    
    using (var scope2 = provider.CreateScope())
    {
        scoped2 = scope2.ServiceProvider.GetService<IScopedService>();
    }
    
    // Services should be different when resolved in different scopes
    // (Note: They're disposed, but the pattern is correct)
    
    // ✅ Test transient lifetime
    var transient1 = provider.GetService<ITransientService>();
    var transient2 = provider.GetService<ITransientService>();
    Assert.AreNotSame(transient1, transient2);
}

Alternative Solutions

1. Use Third-Party DI Containers

// ✅ Example with Autofac
var builder = new ContainerBuilder();
builder.RegisterType<MySingletonService>().SingleInstance(); // ✅ Singleton
builder.RegisterType<MyScopedService>().InstancePerLifetimeScope(); // ✅ Scoped
builder.RegisterType<MyTransientService>().InstancePerDependency(); // ✅ Transient
// ❌ Avoid manual service creation as it bypasses lifetime management
public class MyService
{
    public void DoSomething()
    {
        var scopedService = new MyScopedService(); // ❌ Bypasses DI container
    }
}
// ❌ Avoid service locator as it hides dependencies and lifetime issues
public class MyService
{
    public void DoSomething()
    {
        var scopedService = ServiceLocator.Current.GetInstance<IScopedService>(); // ❌ Anti-pattern
    }
}

Migration Checklist

  • Identify all services with lifetime conflicts
  • Review singleton services that depend on scoped services
  • Implement service scope factory pattern where needed
  • Use IOptions pattern for configuration instead of scoped services
  • Refactor services to use compatible lifetimes
  • Update unit tests to validate service lifetimes
  • Test all functionality after lifetime changes
  • Document service lifetime decisions and patterns used

Conclusion

The ‘Cannot consume scoped service from singleton’ error is a common but preventable C# dependency injection issue that occurs when there’s an invalid lifetime configuration between services. By following the solutions provided in this guide—implementing proper service lifetime matching, using service scope factory patterns, implementing configuration patterns, and following best practices—you can effectively prevent and resolve this error in your C# applications.

The key is to understand C#‘s dependency injection lifetime mechanisms, implement proper service registration patterns, use modern C# features like service scope factory when needed, and maintain clean, well-organized code. With proper DI lifetime management, your C# applications will be more maintainable, performant, and less prone to runtime exceptions.

Remember to test your changes thoroughly, follow C# best practices for dependency injection lifetimes, implement proper error handling, and regularly review your service registrations to ensure your applications maintain the best possible architecture and avoid common DI lifetime errors like “Cannot consume scoped service from singleton”.

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

csharp

How to Fix: No service for type has been registered error in C# - Complete Dependency Injection Guide

Learn how to fix the 'No service for type has been registered' error in C# dependency injection. This comprehensive guide covers DI registration, service lifetimes, and proper configuration techniques.

January 8, 2026
csharp

Fix: CORS Error in ASP.NET Core - Complete Cross-Origin Guide

Learn how to fix CORS errors in ASP.NET Core applications. This comprehensive guide covers CORS configuration, policy setup, and proper cross-origin request handling techniques.

January 8, 2026
csharp

Fix: CS0246: The type or namespace name could not be found error

Learn how to fix the 'CS0246: The type or namespace name could not be found' error in C# applications. This comprehensive guide covers using statements, assembly references, and proper namespace management.

January 8, 2026