Error Validating the service descriptor

Michael Mastro II 56 Reputation points
2024-12-12T03:51:43.05+00:00

Good day all. I come across several errors in the past day, that were not present prior to my removing a service from my application. While this service did not touch any of these classes that are showing the error, I am at a loss on how to resolve it. So, a little about the project. It is a WebApi, but it reaches to an Application Layer and an Infrastructure layer. In the Infrastructure layer I have a custom implementation of UserManager (ApplicationUserManager). I also have a custom IdentityErrorDescriber (ApplicationIdentityErrorDescriber). I also have a DI class that is used in the WebApi's Program.cs. This DI Class adds my Repositories, Permissions service, and Email service.

public static class DependencyInjection
{
    public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddTransient<IAppDatabaseRepository, AppDatabaseRepository>();
        services.AddTransient<IAppUserRepository, AppUserRepository>();
        services.AddTransient<IAppPermissionRepository, AppPermissionRepository>();
        services.AddTransient<IAppRoleRepository, AppRoleRepository>();
        services.AddTransient<IClientAppRepository, ClientAppRepository>();
        services.AddTransient<ISignInService,  SignInService>();
        services.AddTransient<IPermissionService, PermissionService>();
        services.AddTransient<IApplicationUserManager, ApplicationUserManager>();
        var emailConfig = configuration.GetSection("EmailConfiguration").Get<EmailConfiguration>();
        services.AddSingleton(emailConfig!);
        services.AddEmailLibrary();
        services.AddTransient<IEmailSendingService, EmailSendingService>();
        return services;
    }
}

My custom IdentityErrorDecriber is as such:

public class ApplicationIdentityErrorDescriber : IdentityErrorDescriber
{
    public IdentityError UserAlreadyInDatabase(string databaseName)
    {
        return new IdentityError
        {
            Code = nameof(UserAlreadyInDatabase),
            Description = $"User already in database {databaseName}."
        };
    }
    public IdentityError UserAlreadyHasStatuses(string firstName, string lastName)
    {
        return new IdentityError
        {
            Code = nameof(UserAlreadyHasStatuses),
            Description = $"User {firstName} {lastName} already has statuses in the system."
        };
    }
    public IdentityError UserHasNoStatuses(string firstName, string lastName)
    {
        return new IdentityError
        {
            Code = nameof(UserHasNoStatuses),
            Description = $"User {firstName} {lastName} does not have any statuses in the system."
        };
    }
}

The ApplicationUserManager does call on the ApplicationErrorDescriber in the constructor.

private readonly IApplicationUserStore _applicationUserStore;
private readonly ApplicationIdentityErrorDescriber _errors;

public ApplicationUserManager(IApplicationUserStore store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<ApplicationUsers> passwordHasher,
    IEnumerable<IUserValidator<ApplicationUsers>> userValidators, IEnumerable<IPasswordValidator<ApplicationUsers>> passwordValidators, ILookupNormalizer keyNormalizer,
    ApplicationIdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUsers>> logger)
    : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
    _applicationUserStore = store;
    _errors = errors;
}

The application layer has some classes that map to various other classes and will call on the interfaces for the repositories.

The service that I removed was from the Infrastructure layer, and it was not in use in any of the above services, repositories, managers, etc. It would create a text document that this was run on this date and this time. Not needed so I removed it.

In the WebAPI Program.cs I have the following to work with the Identity and call the DI

builder.Services.AddDbContext<IdentDbContext>(options =>
{
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("IdentityDB"));
    options.UseOpenIddict();
});

builder.Services.AddDataProtection()
            .PersistKeysToDbContext<IdentDbContext>()
            .SetDefaultKeyLifetime(TimeSpan.FromDays(7))
            .SetApplicationName("MRM2Applications");

// Add the Identity Services we are going to be using the Application Users and the Application Roles
builder.Services.AddIdentity<ApplicationUsers, ApplicationRoles>()
    .AddEntityFrameworkStores<IdentDbContext>()
    .AddUserStore<ApplicationUserStore>()
    .AddRoleStore<ApplicationRoleStore>()
    .AddRoleManager<ApplicationRoleManager>()
    .AddUserManager<ApplicationUserManager>()
    .AddErrorDescriber<ApplicationIdentityErrorDescriber>()
    .AddDefaultTokenProviders()
    .AddDefaultUI();

builder.Services.Configure<IdentityOptions>(options =>
{
    // Configure Identity to use the same JWT claims as OpenIddict instead
    // of the legacy WS-Federation claims it uses by default (ClaimTypes),
    // which saves you from doing the mapping in your authorization controller.
    options.ClaimsIdentity.UserNameClaimType = Claims.Name;
    options.ClaimsIdentity.UserIdClaimType = Claims.Subject;
    options.ClaimsIdentity.RoleClaimType = Claims.Role;
    // Configure the options for the Identity Account
    options.SignIn.RequireConfirmedEmail = true;
    options.SignIn.RequireConfirmedAccount = true;
    options.User.RequireUniqueEmail = true;
    options.Lockout.MaxFailedAccessAttempts = 3;
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
});

builder.Services.Configure<SecurityStampValidatorOptions>(options =>
{
    options.ValidationInterval = TimeSpan.FromSeconds(1);
});

builder.Services.AddApplication()
    .AddInfrastructure(builder.Configuration)
    .AddDataLibrary();

You can see that I have the ApplicationIdentityErrorDescriber, the ApplicationUserManager, added to the Identity service, and also that the DI for the Application Layer, Infrastructure Layer all instantiated.

But on the launch of the program I am receving a list of 12 errors, 11 of which are unable to resolve the service for type 'ApplicationIdentityErrorDescriber' while trying to activate the 'ApplicationUserManager'. The last one is for the EmailService. Of the 11 that cannot resolve the ApplicationErrorDescriber 3 of them repeat.

Here is an error that is showing:

Error while validating the service descriptor 'ServiceType: IdentityInfrastructure.Managers.IApplicationUserManager Lifetime: Transient ImplementationType: IdentityInfrastructure.Managers.ApplicationUserManager': Unable to resolve service for type 'IdentityInfrastructure.Extensions.ApplicationIdentityErrorDescriber' while attempting to activate 'IdentityInfrastructure.Managers.ApplicationUserManager'.

If the AddIdentity service has the ApplicationIdentityErrorDescriber in it, why is it not pushing towards the Infrastructure layer?

As a side note, I tried the following and it did not work:

public static class DependencyInjection
{
    public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddTransient<IdentityErrorDescriber, ApplicationIdentityErrorDescriber>();
        services.AddTransient<IAppDatabaseRepository, AppDatabaseRepository>();
        services.AddTransient<IAppUserRepository, AppUserRepository>();
        services.AddTransient<IAppPermissionRepository, AppPermissionRepository>();
        services.AddTransient<IAppRoleRepository, AppRoleRepository>();
        services.AddTransient<IClientAppRepository, ClientAppRepository>();
        services.AddTransient<ISignInService,  SignInService>();
        services.AddTransient<IPermissionService, PermissionService>();
        services.AddTransient<IApplicationUserManager, ApplicationUserManager>();
        var emailConfig = configuration.GetSection("EmailConfiguration").Get<EmailConfiguration>();
        services.AddSingleton(emailConfig!);
        services.AddEmailLibrary();
        services.AddTransient<IEmailSendingService, EmailSendingService>();
        return services;
    }
}

So, what have I missed that is causing the error? Monday, no issues if I ran the program, in debug, Tuesday after 3 PM Eastern, the error started happening. If anyone has a thought on what might be causing this or how to resolve it I am willing to listen and try.

Thank you in advance.

.NET
.NET
Microsoft Technologies based on the .NET software framework.
4,049 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,736 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.