Blazor 如何修复 IMediator InvalidOperationException 无法从根提供程序解析,因为它需要范围服务 IDbContext

Sal*_*des 0 c# dependency-injection mediatr asp.net-core blazor

我创建了一个应用程序程序集,并引用了 REST-Api 和 Blazor 应用程序。REST-Api 工作正常,但 Blazor 应用程序出现以下错误:

InvalidOperationException:无法从根提供程序解析“MediatR.IRequestHandler`2[Application.Customers.Queries.GetCustomersList.GetCustomersListQuery,Application.Common.Viewmodels.CustomerListVm]”,因为它需要范围服务“Application.Common.Interfaces.IWegisterDbContext”。Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(类型 serviceType、IServiceScope 范围、IServiceScope rootScope)

InvalidOperationException:为 MediatR.IRequestHandler`2[Application.Customers.Queries.GetCustomersList.GetCustomersListQuery,Application.Common.Viewmodels.CustomerListVm] 类型的请求构造处理程序时出错。向容器注册您的处理程序。有关示例,请参阅 GitHub 中的示例。MediatR.Internal.RequestHandlerBase.GetHandler(ServiceFactory工厂)

在下面的代码示例中,我放置了我的 Starup 文件,两个项目都位于同一解决方案中,引用相同的项目。我已经尝试添加授权,但这显然不起作用。我不知道问题是什么,是我遗漏了什么还是这就是 Blazor?两个程序集中的 MediatR 版本相同。

这是我从 REST-Api 启动的:

using Application;
using Application.Common.Interfaces;
using Infrastructure;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Persistence;
using WebApi.Services;

namespace Wegister.WebApi
{
    public class Startup
    {
        public IWebHostEnvironment Environment { get; }
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddPersistence(Configuration);
            services.AddInfrastructure();
            services.AddApplication();

            if (Environment.IsDevelopment())
            {
                services.AddScoped<ICurrentUserService, CurrentUserServiceDev>();
            }

            services.AddAuthorization(x =>
            {
                if (Environment.IsDevelopment())
                    x.DefaultPolicy = new AuthorizationPolicyBuilder()
                    .RequireAssertion(_ => true)
                    .Build();
            });

            services.AddControllers().AddNewtonsoftJson(options =>
                options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
            );
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseHsts();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我在 Blazor 应用程序中的启动:

using Application;
using Application.Common.Interfaces;
using Infrastructure;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Persistence;
using WebUI.Services;

namespace WebUI
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<SessionService>();
            services.AddSingleton<WorkHourService>();
            services.AddSingleton<ItemService>();
            services.AddSingleton<CustomerService>();

            services.AddPersistence(Configuration);
            services.AddInfrastructure();
            services.AddApplication();

            services.AddRazorPages();
            services.AddServerSideBlazor();

            services.AddScoped<ICurrentUserService, CurrentUserServiceDev>();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

AddApplication依赖注入方法如下:

public static IServiceCollection AddApplication(this IServiceCollection services)
        {
            services.AddScoped<IRequestHandler<GetCustomersListQuery, CustomerListVm>, GetCustomersListQueryHandler>();
            services.AddMediatR(Assembly.GetExecutingAssembly());

            services.AddTransient<ICustomerFactory, CustomerFactory>();

            return services;
        }
Run Code Online (Sandbox Code Playgroud)

添加持久性:

public static IServiceCollection AddPersistence(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddDbContext<WegisterDbContext>(options =>
                options.UseSqlServer(configuration.GetConnectionString("WegisterDbConnectionString")));

            services.AddScoped<IWegisterDbContext>(provider => provider.GetService<WegisterDbContext>());

            return services;
        }
Run Code Online (Sandbox Code Playgroud)

基础设施:

public static IServiceCollection AddInfrastructure(this IServiceCollection services)
        {
            services.AddTransient<IDateTime, MachineDateTime>();
            services.AddTransient<INotificationService, NotificationService>();

            return services;
        }
Run Code Online (Sandbox Code Playgroud)

小智 5

不幸的是,“注册你的处理程序”可能有许多不同的原因(正如我自己发现的那样)。您将需要阅读 这篇关于此事的文章。当您的数据库上下文位于不同的程序集中时,我将您直接链接到对我来说是最终修复的那个。但这只是在我修复了文章中提到的其他几个问题之后才出现的问题。

总结一下:

  1. 告诉serviceprovider不要验证 中的范围 CreateHostBuilder。(感谢莎拉·阿克巴里)
Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    }).UseDefaultServiceProvider(options =>
    options.ValidateScopes = false); // needed for mediatr DI
Run Code Online (Sandbox Code Playgroud)
  1. 确保您的存储库在那里:
    services.AddScoped<IRepo1, Repo1>();
Run Code Online (Sandbox Code Playgroud)
  1. 添加存储库后添加 MediatR,并为您拥有处理程序的每个程序集提供程序集,如下所示:
    var assembly = AppDomain.CurrentDomain.Load("HandlersDomain");
    var assembly2 = AppDomain.CurrentDomain.Load("HandlersDomain2");
    services.AddMediatR(assembly, assembly);
Run Code Online (Sandbox Code Playgroud)

遵循这个食谱,你真的应该是gtg。

  • 谢谢!。它通过添加这个 .UseDefaultServiceProvider(options =&gt; options.ValidateScopes = false) 对我起作用 (2认同)