web-dev-qa-db-fra.com

Le service Web ASP.NET Core ne charge pas appsettings.json dans la configuration

J'ai une application Web ASP.NET Core 2.1 avec des pages Razor qui a des informations d'authentification AAD définies dans le appsettings.json fichier (gracieuseté du modèle d'application par défaut - voir ci-dessous comment j'y suis arrivé). Cependant, lorsque vous essayez de configurer l'authentification dans Startup.cs la configuration n'a aucune des valeurs de configuration de mon appsettings.json. Si j'inspecte l'objet IConfiguration dans le débogueur, il semble n'avoir que les configurations de variables d'environnement:

enter image description here

Ici se trouve le Startup.ConfigureServices méthode où réside le problème:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
        .AddAzureAD(options =>
        {
            // This is from the default template. It should work, but the relevant settings aren't there so options isn't populated.
            this.Configuration.Bind("AzureAd", options);

            // This of course works fine
            options.Instance = "MyInstance";
            options.Domain = "MyDomain";
            options.TenantId = "MyTenantId";
            options.ClientId = "MyClientId";
            options.CallbackPath = "MyCallbackPath";
        });

    services.AddMvc(options =>
    {
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
        options.Filters.Add(new AuthorizeFilter(policy));
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

Et la configuration du service au cas où cela serait important (notez que cela est construit au-dessus d'un service sans état de structure de service):

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new ServiceInstanceListener[]
    {
        new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            {
                ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

                return new WebHostBuilder()
                            .UseKestrel(opt =>
                            {
                                int port = serviceContext.CodePackageActivationContext.GetEndpoint("ServiceEndpoint").Port;
                                opt.Listen(IPAddress.IPv6Any, port, listenOptions =>
                                {
                                    listenOptions.UseHttps(GetCertificateFromStore());
                                    listenOptions.NoDelay = true;
                                });
                            })
                            .ConfigureServices(
                                services => services
                                    .AddSingleton<StatelessServiceContext>(serviceContext))
                            .UseContentRoot(Directory.GetCurrentDirectory())
                            .UseStartup<Startup>()
                            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                            .UseUrls(url)
                            .Build();
            }))
    };
}

Pour créer ce service, j'ai utilisé l'assistant dans VS2017. J'ai sélectionné un projet de structure de service existant (.sfproj) et choisi Services > Add > New Service Fabric Service et a choisi Stateless ASP.NET Core [for .NET Framework], puis sur la page suivante, j'ai choisi Web Application (celui avec Razor Pages, pas MVC) et cliqué sur Change Authentication où j'ai choisi Work or School Accounts et entré mes informations AAD. Les seules modifications que j'ai apportées à ce modèle étaient l'ajout du code à l'intérieur de l'appel à AddAzureAD dans Startup.ConfigureServices et en définissant le appsettings.json fichiers à toujours copier dans le répertoire de sortie.

Pourquoi le appsettings.json le fichier est-il chargé dans la configuration? Si je comprends bien, cela est censé se produire par défaut, mais quelque chose semble manquer ...

11
wlyles

WebHostBuilder ne se charge pas appsettings.json par défaut, vous devez appeler manuellement AddJsonFile. Par exemple:

return new WebHostBuilder()
            .UseKestrel(opt =>
            {
                //snip
            })
            .ConfigureAppConfiguration((builderContext, config) =>
            {
                config.AddJsonFile("appsettings.json", optional: false);
            })
            .ConfigureServices(
                services => services
                    .AddSingleton<StatelessServiceContext>(serviceContext))
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
            .UseUrls(url)
            .Build();

Vous pouvez également utiliser WebHost.CreateDefaultBuilder qui chargera plus de valeurs par défaut.

11
DavidG

Une autre approche serait de créer manuellement la configuration via ConfigurationBuilder puis d'utiliser la méthode UseConfiguration.

var configuration = new ConfigurationBuilder()
     .SetBasePath(Directory.GetCurrentDirectory())
     .AddJsonFile("appsettings.json", false, true)
     .Build();

var Host = new WebHostBuilder()
     .UseConfiguration(configuration)
     .UseKestrel()
     .UseStartup<Startup>();

L'intention principale est essentielle pour fournir un peu de flexibilité lors de la mise en œuvre, ils font souvent erreur sur less is more. Vous devez dire explicitement ce que vous souhaitez, de cette façon le pipeline reste relativement petit.

2
Greg