英文:
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:
- Handler was not found for request of type MediatR.IRequestHandler
- 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<Guid>
{
// 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<Domain.Models.User>()
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<Guid>
{
// 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<Domain.Models.User>()
app.UseAuthentication();
app.UseAuthorization();
I suggest reviewing the ASP.Net Core Identity documentation for the recommended way to implement identity using built in functionality.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论