无法解析范围服务 [英] Cannot resolve scoped service

查看:19
本文介绍了无法解析范围服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在理解代码中的错误来源时遇到问题.我尝试在 .net core 中学习关于微服务的课程.运行构建解决方案后,我得到:

I have problem with understanding source of errors in my code. I try to get throw course about microservices in .net core. After running build solution I get:

------- Project finished: CrossX.Services.Identity. Succeeded: True. Errors: 0. Warnings: 0

但是当我运行它时,我得到:

But when I run it I get:

/opt/dotnet/dotnet /RiderProjects/crossx/src/CrossX.Services.Identity/bin/Debug/netcoreapp2.2/CrossX.Services.Identity.dll

Unhandled Exception: System.InvalidOperationException: Cannot resolve scoped service 'CrossX.NETCore.Commands.ICommandHandler`1[CrossX.NETCore.Commands.CreateUser]' from root provider.
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at CrossX.NETCore.Services.ServiceHost.BusBuilder.SubscribeToCommand[TCommand]() in /RiderProjects/crossx/src/CrossX.NETCore/Services/ServiceHost.cs:line 78
   at CrossX.Services.Identity.Program.Main(String[] args) in /RiderProjects/crossx/src/CrossX.Services.Identity/Program.cs:line 11

当我添加到 webHostBuilder .UseDefaultServiceProvider(options => options.ValidateScopes = false) 时,我的问题就解决了.但据我所知,关闭验证并不是一个好主意.此外,当我将 AddScope 更改为 AddTransient 时,问题得到了解决(或至少它运行了).

When I added to webHostBuilder .UseDefaultServiceProvider(options => options.ValidateScopes = false) my problem was solved. But turning off validations isn't good idea from what I know. Also When I changed AddScope to AddTransient problem was solved (or at least it run).

问题是我不知道去哪里寻找这个错误的来源.我想我不明白出了什么问题,所以如果有人能帮助我,或者至少给出一个提示,我将不胜感激.

Problem is that I have no idea where to look for source of this error. I guess I lack of understanding what is wrong, so I would appreciate if someone would help me, or at least give a hint.

这是我的

Startup.cs:

Startup.cs:

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

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddRabbitMq(Configuration);
            services.AddScoped<ICommandHandler<CreateUser>, CreateUserHandler>();       
            services.AddScoped<IEncrypter, Encrypter>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }

程序.cs

public class Program
    {
        public static void Main(string[] args)
        {
            ServiceHost.Create<Startup>(args)
                .UseRabbitMq()
                .SubscribeToCommand<CreateUser>()
                .Build()
                .Run();
        }
    }

ServiceHost.cs

ServiceHost.cs

public class ServiceHost : IServiceHost
    {
        private readonly IWebHost _webHost;

        public ServiceHost(IWebHost webHost)
        {
            _webHost = webHost;
        }

        public void Run() => _webHost.Run();

        public static HostBuilder Create<TStartup>(string[] args) where TStartup : class
        {
            Console.Title = typeof(TStartup).Namespace;
            var config = new ConfigurationBuilder()
                .AddEnvironmentVariables()
                .AddCommandLine(args)
                .Build();
            var webHostBuilder = WebHost.CreateDefaultBuilder(args)
                .UseConfiguration(config)
//                .UseDefaultServiceProvider(options => options.ValidateScopes = false)
                .UseStartup<TStartup>();

            return new HostBuilder(webHostBuilder.Build());
        }

        public abstract class BuilderBase
        {
            public abstract ServiceHost Build();
        }

        public class HostBuilder : BuilderBase
        {
            private readonly IWebHost _webHost;
            private IBusClient _bus;

            public HostBuilder(IWebHost webHost)
            {
                _webHost = webHost;
            }

            public BusBuilder UseRabbitMq()
            {
                _bus = (IBusClient) _webHost.Services.GetService(typeof(IBusClient));
                return new BusBuilder(_webHost, _bus);
            }

            public override ServiceHost Build()
            {
                return new ServiceHost(_webHost);
            }
        }

        public class BusBuilder : BuilderBase
        {
            private readonly IWebHost _webHost;
            private IBusClient _bus;

            public BusBuilder(IWebHost webHost, IBusClient bus)
            {
                _webHost = webHost;
                _bus = bus;
            }

            public BusBuilder SubscribeToCommand<TCommand>() where TCommand : ICommand
            {
                var handler = (ICommandHandler<TCommand>) _webHost.Services.GetService(typeof(ICommandHandler<TCommand>));
                _bus.WithCommandHandlerAsync(handler);

                return this;
            }

            public BusBuilder SubscribeToEvent<TEvent>() where TEvent : IEvent
            {
                var handler = (IEventHandler<TEvent>) _webHost.Services.GetService(typeof(IEventHandler<TEvent>));
                _bus.WithEventHandlerAsync(handler);

                return this;
            }

            public override ServiceHost Build()
            {
                return new ServiceHost(_webHost);
            }
        }
    }

推荐答案

无法从根提供程序解析范围服务 ICommandHandler

正如错误所说,您无法从根提供程序创建范围服务实例.根提供者是存在于服务范围之外的根服务提供者.因此,它无法解析应该只在 服务范围内使用的服务.

As the error says, you cannot create a scoped service instance from the root provider. The root provider is the root service provider that exists outside of service scopes. As such, it cannot resolve services that should only be consumed within service scopes.

如果您想从根提供程序解析范围服务,例如当您从单例服务使用它时,您应该首先使用 IServiceScopeFactory:

If you want to resolve a scoped service from the root provider, for example when you are consuming it from a singleton service, you should create a service scope first using the IServiceScopeFactory:

var serviceScopeFactory = _webHost.Services.GetService<IServiceScopeFactory>();
using (var scope = serviceScopeFactory.CreateScope())
{
    var handler = (IEventHandler<TEvent>)scope.ServiceProvider.GetService(typeof(IEventHandler<TEvent>))
    // …
}

请注意,服务范围应该是短暂的,您需要在之后处理它们以进行清理.

Note that service scopes are supposed to be short lived, and that you need to dispose them afterwards to clean up.

查看您的实现,似乎您将范围服务传递给其他服务以订阅事件.这通常似乎是一个坏主意,因为这意味着对作用域服务的引用将由(可能的)单例服务在应用程序的整个生命周期内保存.这通常是一个坏主意(正如我所说,范围服务应该只存在很短的时间).

Looking at your implementation, it seems as if you pass your scoped services to some other service in order to subscribe to events. This generally seems like a bad idea since that means that a reference to a scoped service will be kept by a (likely) singleton service for the whole lifetime of the application. This is generally a bad idea (as I said, scoped services are supposed to live only a short time).

您应该问问自己为什么需要将服务范围限定在那里,以及是否不能将它们设为单例.或者,如果您确实需要基于实例的订阅机制(而不仅仅是类型、使用工厂模式或其他东西).

You should ask yourself why you need the services to be scoped there, and whether you cannot make them singleton instead. Or if you actually need the subscribe mechanism to be based on the instance (instead of for example just the type, using a factory pattern or something).

这篇关于无法解析范围服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆