System.AggregateException: 一些服务无法被构建

huangapple go评论68阅读模式
英文:

System.AggregateException: Some services are not able to be constructed

问题

我正在使用 ASP-NET Core 项目,使用 MediatR 12.0.1 库。我对 .net 6 不太了解,我正在学习依赖注入。

using 应用程序;
using 应用程序.通用;
using 领域;
using 领域接口;
using Microsoft.EntityFrameworkCore;
using System.Reflection;

namespace Tavrida.Backend
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            builder.Services.AddDbContext<AppDbContext>(opt =>
            {
                if (builder.Environment.IsDevelopment())
                    opt.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"));

                if (builder.Environment.IsProduction())
                {
                    var database = Environment.GetEnvironmentVariable("PGDATABASE");
                    var host = Environment.GetEnvironmentVariable("PGHOST");
                    var user = Environment.GetEnvironmentVariable("PGUSER");
                    var password = Environment.GetEnvironmentVariable("PGPASSWORD");
                    var port = Environment.GetEnvironmentVariable("PGPORT");
                    var connection = $"User ID={user};Password={password};Host={host};Port={port};Database={database}";
                    opt.UseNpgsql(connection);
                }
            });

            builder.Services.AddScoped<IForumContext>(provider => provider.GetService<AppDbContext>());
            builder.Services.AddScoped<IModelContext>(provider => provider.GetService<AppDbContext>());
            builder.Services.AddScoped<IUserContext>(provider => provider.GetService<AppDbContext>());

            using (var scope = builder.Services.BuildServiceProvider())
            {
                try
                {
                    var context = scope.GetRequiredService<AppDbContext>();
                    DbInitializer.Initialize(context);
                }
                catch (Exception exception)
                {
                    var logger = scope.GetRequiredService<ILogger<Program>>();
                    logger.LogError(exception, "应用程序初始化时发生错误");
                }
            }
            builder.Services.AddApplicationModule();

            builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));

            builder.Services.AddControllers();
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();

            if (app.Environment.IsDevelopment())
                app.UseDeveloperExceptionPage();

            app.UseSwagger();
            app.UseSwaggerUI();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });

            app.Run();
        }
    }
}

这个项目构建成功,但在运行时调用 System.AggregateException:

System.AggregateException: "无法构造某些服务(在验证服务描述符时发生错误,'ServiceType: MediatR.IRequestHandler`2[Application.Forums.Queries.GetForumList.GetForumListQuery,Application.Forums.Queries.GetForumList.ForumListVm] Lifetime: Transient ImplementationType: Application.Forums.Queries.GetForumList.GetForumListQueryHandler' 时出错:在尝试激活'Application.Forums.Queries.GetForumList.GetForumListQueryHandler' 时无法解析类型'mapsterMapper.IMapper' 的服务。)(在验证服务描述符时发生错误,'ServiceType: MediatR.IRequestHandler`2[Application.Forums.Queries.GetForumDetail.GetForumDetailQuery,Application.Forums.Queries.GetForumDetail.ForumDetailVm] Lifetime: Transient ImplementationType: Application.Forums.Queries.GetForumDetail.GetForumDetailQueryHandler' 时出错:在尝试激活'Application.Forums.Queries.GetForumDetail.GetForumDetailQueryHandler' 时无法解析类型'mapsterMapper.IMapper' 的服务。)(在验证服务描述符时发生错误,'ServiceType: MediatR.IRequestHandler`2[Tavrida.Backend.Auth.Users.Queries.AuthUser.LoginDefault.LoginDefaultQuery,System.IdentityModel.Tokens.Jwt.JwtSecurityToken] Lifetime: Transient ImplementationType: Tavrida.Backend.Auth.Users.Queries.AuthUser.LoginDefault.LoginDefaultQueryHandler' 时出错:在尝试激活'Tavrida.Backend.Auth.Users.Queries.AuthUser.LoginDefault.LoginDefaultQueryHandler' 时无法解析类型'Microsoft.AspNetCore.Identity.UserManager`1[Domain.Models.User]' 的服务。)"

其中一个处理程序的代码:

using 领域接口;
using Mapster;
using MapsterMapper;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace Application.Forums.Queries.GetForumList
{
    public class GetForumListQueryHandler : IRequestHandler<GetForumListQuery, ForumListVm>
    {
        private readonly IForumContext _context;
        private readonly IMapper _mapper;

        public GetForumListQueryHandler(IForumContext context, IMapper mapper) =>
            (_context, _mapper) = (context, mapper);

        public async Task<ForumListVm> Handle(GetForumListQuery request, CancellationToken cancellationToken)
        {
            var forums = await _mapper.From(_context.Forums
                    .OrderBy(x => x.StartedAt)
                    .Skip(request.Skiped)
                    .Take(request.Count))
                .ProjectToType<ForumDto>()
                .ToListAsync(cancellationToken);

            return new ForumListVm { ForumList = forums };
        }
    }
}
using MediatR;

namespace Application.Forums.Queries.GetForumList
{
    public class GetForumListQuery : IRequest<ForumListVm>
    {
        public int Count { get; set; }
        public int Skiped { get; set; }
    }
}
namespace Application.Forums.Queries.GetForumList
{
    public class ForumListVm
    {
        public IList<ForumDto>? ForumList { get; set; }
    }
}
namespace Application.Forums.Queries.GetForumList
{
    public class ForumDto
    {
        public string? Id { get; set; }
        public string? Title { get; set; }
        public string? LogoUrl { get; set; }
    }
}

要注册服务,我使用以下代码:

using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

namespace Application
{
    public static class ApplicationModule
    {
        public static IServiceCollection AddApplicationModule(this IServiceCollection services)
        {

            services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));

            return services;
        }
    }
}

我将 MediatR 库添加到控制器中,使用以下代码:

        private IMediator _mediator;
        protected IMediator Mediator =>
            _mediator ??= HttpContext.RequestServices.GetService<IMediator>();

我尝试了不同的 MediatR 注册方法。我的所有

英文:

I'm writing a project on ASP-NET Core using the MediatR 12.0.1 library. I'm new to .net 6 and I'm learn Dependency Injection.
Structure

using Application;
using Application.Common;
using Domain;
using Domain.Interfaces;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
namespace Tavrida.Backend
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(opt =>
{
if (builder.Environment.IsDevelopment())
opt.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"));
if (builder.Environment.IsProduction())
{
var database = Environment.GetEnvironmentVariable("PGDATABASE");
var host = Environment.GetEnvironmentVariable("PGHOST");
var user = Environment.GetEnvironmentVariable("PGUSER");
var password = Environment.GetEnvironmentVariable("PGPASSWORD");
var port = Environment.GetEnvironmentVariable("PGPORT");
var connection = $"User ID={user};Password={password};Host={host};Port={port};Database={database}";
opt.UseNpgsql(connection);
}
});
builder.Services.AddScoped<IForumContext>(provider => provider.GetService<AppDbContext>());
builder.Services.AddScoped<IModelContext>(provider => provider.GetService<AppDbContext>());
builder.Services.AddScoped<IUserContext>(provider => provider.GetService<AppDbContext>());
using (var scope = builder.Services.BuildServiceProvider())
{
try
{
var context = scope.GetRequiredService<AppDbContext>();
DbInitializer.Initialize(context);
}
catch (Exception exception)
{
var logger = scope.GetRequiredService<ILogger<Program>>();
logger.LogError(exception, "An error occurred while app initialization");
}
}
builder.Services.AddApplicationModule();
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.Run();
}
}
}

The build of this project is successful, but in runtime it calls System.AggregateException

System.AggregateException: "Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler`2[Application.Forums.Queries.GetForumList.GetForumListQuery,Application.Forums.Queries.GetForumList.ForumListVm] Lifetime: Transient ImplementationType: Application.Forums.Queries.GetForumList.GetForumListQueryHandler': Unable to resolve service for type 'MapsterMapper.IMapper' while attempting to activate 'Application.Forums.Queries.GetForumList.GetForumListQueryHandler'.) (Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler`2[Application.Forums.Queries.GetForumDetail.GetForumDetailQuery,Application.Forums.Queries.GetForumDetail.ForumDetailVm] Lifetime: Transient ImplementationType: Application.Forums.Queries.GetForumDetail.GetForumDetailQueryHandler': Unable to resolve service for type 'MapsterMapper.IMapper' while attempting to activate 'Application.Forums.Queries.GetForumDetail.GetForumDetailQueryHandler'.) (Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler`2[Tavrida.Backend.Auth.Users.Queries.AuthUser.LoginDefault.LoginDefaultQuery,System.IdentityModel.Tokens.Jwt.JwtSecurityToken] Lifetime: Transient ImplementationType: Tavrida.Backend.Auth.Users.Queries.AuthUser.LoginDefault.LoginDefaultQueryHandler': Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Domain.Models.User]' while attempting to activate 'Tavrida.Backend.Auth.Users.Queries.AuthUser.LoginDefault.LoginDefaultQueryHandler'.)"

The code of one of my handlers

using Domain.Interfaces;
using Mapster;
using MapsterMapper;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Forums.Queries.GetForumList
{
public class GetForumListQueryHandler : IRequestHandler<GetForumListQuery, ForumListVm>
{
private readonly IForumContext _context;
private readonly IMapper _mapper;
public GetForumListQueryHandler(IForumContext context, IMapper mapper) =>
(_context, _mapper) = (context, mapper);
public async Task<ForumListVm> Handle(GetForumListQuery request, CancellationToken cancellationToken)
{
var forums = await _mapper.From(_context.Forums
.OrderBy(x => x.StartedAt)
.Skip(request.Skiped)
.Take(request.Count))
.ProjectToType<ForumDto>()
.ToListAsync(cancellationToken);
return new ForumListVm { ForumList = forums };
}
}
}
using MediatR;
namespace Application.Forums.Queries.GetForumList
{
public class GetForumListQuery : IRequest<ForumListVm>
{
public int Count { get; set; }
public int Skiped { get; set; }
}
}
namespace Application.Forums.Queries.GetForumList
{
public class ForumListVm
{
public IList<ForumDto>? ForumList { get; set; }
}
}
namespace Application.Forums.Queries.GetForumList
{
public class ForumDto
{
public string? Id { get; set; }
public string? Title { get; set; }
public string? LogoUrl { get; set; }
}
}

To register the service, I use the class

using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace Application
{
public static class ApplicationModule
{
public static IServiceCollection AddApplicationModule(this IServiceCollection services)
{
services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
return services;
}
}
}

I add the MediatoR library to the controller with the following code

        private IMediator _mediator;
protected IMediator Mediator =>
_mediator ??= HttpContext.RequestServices.GetService<IMediator>();

I have tried different MediatR registration methods. All my attempts end with two scenarios:

  1. Handler was not found for request of type MediatR.IRequestHandler
  2. Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler

I read a similar article, but I didn't understand how to solve my problem.
Article
I would be very grateful for any help!

答案1

得分: 0

You have some missing registrations in your dependency injection setup.

The aggregate exception thrown shows 3 inner exceptions.

2 of them indicate that there is no IMapper registered (it appears you are using Mapster).

Add this above your AddDbContext call in Program.cs (see here) for more info):

builder.Services.AddMapster()

This should take care of the first two errors in your aggregate exception.

The 3rd exception indicates that there is no UserManager<Domain.Models.User> registered. Your class, Tavrida.Backend.Auth.Users.Queries.AuthUser.LoginDefault.LoginDefaultQueryHandler evidently has a constructor parameter of type UserManager<Domain.Models.User>, but your host doesn't now how to create that object type.

Considering that you are using your own custom-implemented user model (Domain.Models.User), make sure this class implements the built-in ASP.NET Core IdentityUser class

using System;
using Microsoft.AspNetCore.Identity;

public class User : IdentityUser&lt;Guid&gt;
{
   // your custom properties here
}

Then in your Program.cs, the following should register ASP.Net Core identity-related classes in DI for you, such as UserManager.

builder.services.AddDefaultIdentity&lt;Domain.Models.User&gt;()
app.UseAuthentication();
app.UseAuthorization();

I suggest reviewing the ASP.Net Core Identity documentation for the recommended way to implement identity using built-in functionality.

英文:

You have some missing registrations in your dependency injection setup.

The aggregate exception thrown shows 3 inner exceptions.

2 of them indicate that there is no IMapper registered (it appears you are using Mapster).

Add this above your AddDbContext call in Program.cs (see here) for more info):

builder.Services.AddMapster()

This should take care of the first two errors in your aggregate exception.

The 3rd exception indicates that there is no UserManager<Domain.Models.User> registered. Your class, Tavrida.Backend.Auth.Users.Queries.AuthUser.LoginDefault.LoginDefaultQueryHandler evidently has a constructor parameter of type UserManager<Domain.Models.User>, but your host doesn't now how to create that object type.

Considering that you are using your own custom-implemented user model (Domain.Models.User), make sure this class implements the built in ASP.NET Core IdentityUser class

using System;
using Microsoft.AspNetCore.Identity;

public class User : IdentityUser&lt;Guid&gt;
{
   // your custom properties here
}

Then in your Program.cs, the following should register ASP.Net Core identity-related classes in DI for you, such as UserManager.

builder.services.AddDefaultIdentity&lt;Domain.Models.User&gt;()
app.UseAuthentication();
app.UseAuthorization();

I suggest reviewing the ASP.Net Core Identity documentation for the recommended way to implement identity using built in functionality.

huangapple
  • 本文由 发表于 2023年5月11日 03:42:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76222067.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定