asp.net-core - 如何正确解析要在 ASP.NET Core 3.1 的 ConfigureServices() 中使用的服务?

标签 asp.net-core .net-core asp.net-core-mvc asp.net-core-3.0 asp.net-core-3.1

我有一个基于 ASP.NET Core 3.1 的应用程序。在应用程序启动期间,在 ConfigureServices(IServiceCollection services)我想注册我的服务。但是在配置服务期间,我想根据数据库中的设置启动应用程序。

这是我的代码

public void ConfigureServices(IServiceCollection services)
{
    // Register context
    services.AddDbContext<AppDbContext>(options =>
    {
        options.UseMySql(Configuration.GetConnectionString("MySqlServerConnection"));
    });

    // Reister the setting provider
    services.AddSingleton<IAppSetting, AppSettings>();

    // Create a resolver which is WRONG!!
    var resolver = services.BuildServiceProvider();

    var setting = resolver.GetService<IAppSetting>();

    List<string> allowedCors = new List<string>()
    {
         setting.MainUrl.ToString()
    };

    if (setting.HasCustomAssetsUri)
    {
        allowedCors.Add(settings.AssetsUrl.ToString());
    }

    if (settings.HasCustomPhotosUri)
    {
        allowedCors.Add(settings.PhotosUrl.ToString());
    }

    services.AddCors(options =>
    {
        options.AddPolicy("AllowSubDomainTraffic",
        builder =>
        {
            builder.WithOrigins(allowedCors.ToArray())
                   .AllowAnyHeader()
                   .AllowAnyMethod();
        });
    });

    // More services
}

正如您在上面的代码中看到的,我注册了 IAppSetting但我立即想使用来访问数据库所以获取当前配置。我目前正在调用services.BuildServiceProvider()创建一个新的解析器,然后我可以在其中使用它来创建 IAppSetting 的实例.

我的 AppSetting实现取决于 AppDbContext这也是注册的。这是我的应用程序设置

public class AppSetting : IAppSetting
{
    private AppDbContext context;

    public AppSetting(AppDbContext context)
    {
        this.context = context;
    }

    // methods...
}

调用BuildServiceProvider()将导致创建单例服务的附加副本。所以我试图避免这样做。

如何正确注册然后解析IAppSettingConfigureServices()方法,所以我可以使用它来访问在数据库中找到的设置?

更新

我尝试使用 Nkosi 提供的解决方案,但出现以下错误

System.InvalidOperationException: 'Cannot resolve scoped service 'IAppSetting' from root provider.'



这是完整的堆栈跟踪。

This exception was originally thrown at this call stack:
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(System.Type, Microsoft.Extensions.DependencyInjection.IServiceScope, Microsoft.Extensions.DependencyInjection.IServiceScope)
    Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(System.Type, Microsoft.Extensions.DependencyInjection.IServiceScope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(System.Type, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(System.Type)
    Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(System.IServiceProvider, System.Type)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(Microsoft.Extensions.DependencyInjection.ServiceLookup.FactoryCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
    ...
    [Call Stack Truncated]

最佳答案

引用 Use DI services to configure options

使用 DI 配置 CORS 选项,将所有逻辑移动到配置委托(delegate)中

//...

// Register context
services.AddDbContext<AppDbContext>(options => {
    options.UseMySql(Configuration.GetConnectionString("MySqlServerConnection"));
});

// Reister the setting provider
services.AddScoped<IAppSetting, AppSettings>(); 

//configure CORS options using DI
services.AddOptions<CorsOptions>()
    .Configure<IServiceScopeFactory>((options, sp) => {
        using(var scope = sp.CreateScope()) {
            IAppSetting settings = scope.ServiceProvider.GetRequiredService<IAppSetting>();
            List<string> allowedCors = new List<string>() {
                 setting.MainUrl.ToString()
            };

            if (setting.HasCustomAssetsUri) {
                allowedCors.Add(settings.AssetsUrl.ToString());
            }

            if (settings.HasCustomPhotosUri) {
                allowedCors.Add(settings.PhotosUrl.ToString());
            }
            options.AddPolicy("AllowSubDomainTraffic", builder => {
                builder.WithOrigins(allowedCors.ToArray())
                       .AllowAnyHeader()
                       .AllowAnyMethod();
            });
        }
    });

services.AddCors();

//...

这样一来,现在一切都被推迟到真正需要它们的时候,并且您不必过早地构建服务集合。

关于asp.net-core - 如何正确解析要在 ASP.NET Core 3.1 的 ConfigureServices() 中使用的服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60084994/

相关文章:

dependency-injection - Xunit项目中的依赖注入(inject)

asp.net-core-mvc - Asp.Net 核心 2.0 MVC anchor 标签助手不起作用

c# - .AspNetCore.相关性。未找到国家属性(property)。未知位置

asp.net - 如何在没有用户名或密码的情况下配置与 Azure Database for PostgreSQL 灵活服务器的连接?

xamarin - ASP.NET Core Web API 与 ASP.NET Core 应用程序

c# - 获取不同 HttpContext 的端点

c# - 在 .NET Core 中反编译匿名方法 IL

c# - 如何创建或使用现成的垫片从 .net 框架移植到 .net 核心/标准?

c# - 控制台应用程序更新到.Net Core 3.1错误找不到框架 'Microsoft.AspNetCore.App',版本 '3.1.0'

c# - Entity Framework 7 RC 1 和 ASP.NET MVC 6 中的种子初始数据