I have an ASP.NET Core 2.1 Web Application with Razor Pages which has AAD authentication information defined in the appsettings.json
file (courtesy of the default application template - see below on how I got there). However, when trying to configure the authentication in Startup.cs
the configuration does not have any of the config values from my appsettings.json
. If I inspect the IConfiguration
object in the debugger then it appears to only have the environment variable configurations:
Here's the Startup.ConfigureServices
method where the issue lies:
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);
}
And the service configuration in case it's important (note that this is being built on top of a service fabric stateless 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();
}))
};
}
To create this service, I used the wizard in VS2017. I selected an existing service fabric project (.sfproj
) and chose Services > Add > New Service Fabric Service
and chose Stateless ASP.NET Core [for .NET Framework]
, then on the next page I chose Web Application
(the one with Razor Pages, not MVC) and clicked Change Authentication
where I chose Work or School Accounts
and entered my AAD info. The only changes I have made to this template were adding the code inside the call to AddAzureAD
in Startup.ConfigureServices
and setting the appsettings.json
files to always be copied to the output directory.
Why doesn't the appsettings.json
file get loaded into the configuration? As I understand, this is supposed to happen by default, but something seems to be missing...
The appsettings. json file is an application configuration file used to store configuration settings such as database connections strings, any application scope global variables, etc. If you open the ASP.NET Core appsettings. json file, then you see the following code by default which is created by visual studio.
Application configuration in ASP.NET Core is performed using one or more configuration providers. Configuration providers read configuration data from key-value pairs using a variety of configuration sources: Settings files, such as appsettings. json.
WebHostBuilder
doesn't load appsettings.json
by default, you need to manually call AddJsonFile
. For example:
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();
Alternatively you can use WebHost.CreateDefaultBuilder
which will load more defaults.
Another approach, would be to manually create the configuration via ConfigurationBuilder
then use the UseConfiguration
method.
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(configuration)
.UseKestrel()
.UseStartup<Startup>();
The primary intent is core to provide a bit of flexibility when implementing, they often error on less is more. You have to explicitly say what you would like, that way the pipeline remains relatively small.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With