简体   繁体   English

带ASP.Net Core 2.0 IOptions的简单注入器快照注入

[英]Simple Injector w/ ASP.Net Core 2.0 IOptionsSnapshot injection

I was trying what was suggested in bug #429 and am getting the same error he reported there but then never provided the stack trace for. 我正在尝试在错误#429中提出的建议,并且遇到了他在该位置报告的错误,但是从没有提供堆栈跟踪。 I have also read, and have used until recently, your guidance on not using IOptions and related classes. 我还阅读并使用了直到最近的有关不使用IOptions和相关类的指南。 We are at a point where the IOptionsSnapshot is really needed as we are running stuff in Azure and need to be able to flip options on/off on the fly as we hit limits and restarting the service is not an option as it takes upwards of 5 minutes to start initially due to some third party pieces we require. 当我们在Azure中运行某些东西时,确实需要IOptionsSnapshot ,并且当我们达到极限时,需要能够即时打开/关闭选项,并且重启服务不是选项,因为它最多需要5个最初需要几分钟,这是由于我们需要一些第三方产品。

This is what we have setup: 这是我们设置的内容:

  • Simple Injector 4.3.0 简单注射器4.3.0
  • .NET Core 2.0 Web API .NET Core 2.0 Web API

interface ISearchSettings -> class SearchSettings 接口ISearchSettings >类SearchSettings
(basically all of the properties in here except for 1 boolean we can singleton if needed. The one boolean is a bit telling us whether to use inhouse or azure searching) (基本上,这里的所有属性,除了1个布尔值,我们都可以根据需要单身。一个布尔值有点告诉我们是使用内部搜索还是使用天蓝色搜索)

When the app is starting, I receive the following error: 应用启动时,出现以下错误:

System.InvalidOperationException: The configuration is invalid. System.InvalidOperationException:配置无效。 Creating the instance for type IOptionsSnapshot<SearchSettings> failed. 创建类型为IOptionsSnapshot <SearchSettings>的实例失败。 The registered delegate for type IOptionsSnapshot<SearchSettings> threw an exception. 类型为IOptionsSnapshot <SearchSettings>的注册委托引发了异常。 Unable to request service 'IOptionsSnapshot<SearchSettings> from ASP.NET Core request services. 无法从ASP.NET Core请求服务请求服务'IOptionsSnapshot <SearchSettings>。 Please make sure this method is called within the context of an active HTTP request. 请确保在活动HTTP请求的上下文中调用此方法。

In Configure Services: 在“配置服务”中:

services.AddOptions();  
services.Configure<ISearchSettings>(
    this.Configuration.GetSection("AzureSearchSettings"));  
services.Configure<SearchSettings>(
    this.Configuration.GetSection("AzureSearchSettings"));  
// The next line was added trying some other suggestions from similar
// errors. It didn't resolve the issue  
services.AddScoped(
    cfg => cfg.GetService<IOptionsSnapshot<SearchSettings>>().Value);  
...  
services.AddMvc();  
...  
IntegrateSimpleInjector();  

In IntegrateSimpleInjector: 在IntegrateSimpleInjector中:

this.container.Options.DefaultScopedLifestyle =
    new AsyncScopedLifestyle();

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IControllerActivator>(
    new SimpleInjectorControllerActivator(this.container));
services.AddSingleton<IViewComponentActivator>(
    new SimpleInjectorViewComponentActivator(this.container));

services.EnableSimpleInjectorCrossWiring(this.container);
services.UseSimpleInjectorAspNetRequestScoping(this.container);

In InitializeContainer: 在InitializeContainer中:

// I have tried both Lifestyle Transient and Scoped
this.container.Register<IOptionsSnapshot<SearchSettings>>(
    () => app.GetRequestService<IOptionsSnapshot<SearchSettings>>(),
    Lifestyle.Transient);
...
this.container.AutoCrossWireAspNetComponents(app);

Stacktrace: 堆栈跟踪:

at SimpleInjector.SimpleInjectorAspNetCoreIntegrationExtensions.GetRequestServiceProvider(IApplicationBuilder builder, Type serviceType)
at SimpleInjector.SimpleInjectorAspNetCoreIntegrationExtensions.GetRequestService[T](IApplicationBuilder builder)
at QuotingService.Startup.<>c__DisplayClass9_0.<InitializeContainer>b__0() in E:\Repos\QuotingService\QuotingService\Startup.cs:line 299
at lambda_method(Closure )
at SimpleInjector.InstanceProducer.BuildAndReplaceInstanceCreatorAndCreateFirstInstance()
at SimpleInjector.InstanceProducer.GetInstance()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.InstanceProducer.VerifyInstanceCreation()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.VerifyInstanceCreation()
at SimpleInjector.Container.VerifyInstanceCreation(InstanceProducer[] producersToVerify)
at SimpleInjector.Container.VerifyInternal(Boolean suppressLifestyleMismatchVerification)
at SimpleInjector.Container.Verify()
at QuotingService.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime) in E:\Repos\QuotingService\QuotingService\Startup.cs:line 229
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app)
at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

Any ideas on what needs to be changed to get this working? 关于什么需要更改才能使此工作有任何想法?
Thanks for the awesome product and any help provided. 感谢您提供的出色产品以及所提供的任何帮助。

You should prevent making calls to GetRequestService inside a Simple Injector-registered delegate, since this such call requires the existence of an active HTTP request, which will not be available during application startup. 您应该避免在简单的Injector注册的委托中调用GetRequestService ,因为这种调用要求存在一个活动的HTTP请求,该请求在应用程序启动期间将不可用。

Instead, rely upon AutoCrossWireAspNetComponents to get IOptionsSnapshot<SearchSettings> from ASP.NET Core. 而是依靠AutoCrossWireAspNetComponents从ASP.NET Core获取IOptionsSnapshot<SearchSettings>

For this to work, however, you need to have called services.Configure<SearchSettings> . 但是,要使其正常工作,您需要调用services.Configure<SearchSettings>

Here is a working configuration: 这是一个有效的配置:

public class Startup
{
    private Container container = new Container();

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json");
        this.Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // ASP.NET default stuff here
        services.AddMvc();

        this.IntegrateSimpleInjector(services);

        services.Configure<SearchSettings>(
            Configuration.GetSection("SearchSettings"));
    }

    private void IntegrateSimpleInjector(IServiceCollection services)
    {
        container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

        services.AddSingleton<IControllerActivator>(
            new SimpleInjectorControllerActivator(container));

        services.EnableSimpleInjectorCrossWiring(container);
        services.UseSimpleInjectorAspNetRequestScoping(container);
    }

    public void Configure(IApplicationBuilder app)
    {
        container.AutoCrossWireAspNetComponents(app);
        container.RegisterMvcControllers(app);

        container.Verify();

        // ASP.NET default stuff here
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

With this config, you can inject IOptionsSnapshot<T> everywhere. 使用此配置,您可以在所有位置注入IOptionsSnapshot<T> For instance inside your HomeController : 例如在您的HomeController内部:

public class HomeController : Controller
{
    private readonly IOptionsSnapshot<SearchSettings> snapshot;

    public HomeController(
        IOptionsSnapshot<SearchSettings> snapshot)
    {
        this.snapshot = snapshot;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM