Pass dependency to app.[Methods()] in program.cs in .NET 6 - c#

In .Net 5 and previous, we used to have a startup.cs file, with ConfigureServices and Configure Method inside. In below function I have added ILoggerManager as parameter of the function and then passed it to app.ConfigureExceptionHandler function.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerManager logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.ConfigureExceptionHandler(logger);
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
But with .Net 6 there is no startup.cs file and only program.cs file. There is no ConfigureService or Configure methods inside program.cs and all methods or functions are being called in a procedural way without any class or methods declaration like below:
var builder = WebApplication.CreateBuilder(args);
var logger = new LoggerManager();
builder.Services.AddControllers();
builder.Services.AddDbContext<DocumentDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DocumentStore")));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<ILoggerManager, LoggerManager>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.ConfigureExceptionHandler(<how to pass dependency here>);
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
My question is how can I pass a dependency to app.ConfigureExceptionHandler() function in .Net 6. I could not find any documentation on it.

Since you are creating LoggerManager yourself (var logger = new LoggerManager();) you can simply do:
app.ConfigureExceptionHandler(logger);
If you prefer to use the DI you can utilize IServiceProvider exposed via WebApplication.Services property:
var resolvedLoggerManager = app.Services.GetRequiredService<ILoggerManager>();
app.ConfigureExceptionHandler(resolvedLoggerManager);

For anyone trying obtain dependencies prior to calling builder.Build() (e.g. for use in services set-up), you can use an intermediate WebApplicationBuilder to build an additional WebApplication instance as below (Note that you cannot call builder.Build() twice, hence the need for the intermediate builder).
var builder = WebApplication.CreateBuilder(args);
// Use intermediate builder to obtain configuration etc
var intermediateBuilder = WebApplication.CreateBuilder(args);
var intermediateApp = intermediateBuilder.Build();
// Add services to the container.
var webHostEnvironment = intermediateApp.Services.GetRequiredService<IWebHostEnvironment>();
var configuration = new ConfigurationBuilder()
.AddJsonFile($"appsettings.{webHostEnvironment.EnvironmentName}.json", optional: false, reloadOnChange: false)
.Build();
...

Related

How do I create a MySql connection in .NET 6.0 Program.cs vs .NET 5.0 Startup.cs? [duplicate]

In earlier versions, we had Startup.cs class and we get configuration object as follows in the Startup file.
public class Startup
{
private readonly IHostEnvironment environment;
private readonly IConfiguration config;
public Startup(IConfiguration configuration, IHostEnvironment environment)
{
this.config = configuration;
this.environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
// Add Services
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Add Middlewares
}
}
Now in .NET 6 (With Visual Studio 2022), we don't see the Startup.cs class. Looks like its days are numbered. So how do we get these objects like Configuration(IConfiguration) and Hosting Environment(IHostEnvironment)
How do we get these objects, to say read the configuration from appsettings? Currently the Program.cs file looks like this.
using Festify.Database;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddDbContext<FestifyContext>();
////////////////////////////////////////////////
// The following is Giving me error as Configuration
// object is not avaible, I dont know how to inject this here.
////////////////////////////////////////////////
builder.Services.AddDbContext<FestifyContext>(opt =>
opt.UseSqlServer(
Configuration.GetConnectionString("Festify")));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// 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.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
I want to know how to read the configuration from appsettings.json ?
WebApplicationBuilder returned by WebApplication.CreateBuilder(args) exposes Configuration and Environment properties:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
...
ConfigurationManager configuration = builder.Configuration; // allows both to access and to set up the config
IWebHostEnvironment environment = builder.Environment;
WebApplication returned by WebApplicationBuilder.Build() also exposes Configuration and Environment:
var app = builder.Build();
IConfiguration configuration = app.Configuration;
IWebHostEnvironment environment = app.Environment;
Also check the migration guide and code samples.
In Program.cs, the WebApplicationBuilder is created shown below.
var builder = WebApplication.CreateBuilder(args);
Once we have the builder created, the configuration is available.
Let's assume you have the default appSettings.json in place. The example code below would return the configuration Default log level setting from the JSON configuration file.
builder.Configuration["Logging:LogLevel:Default"] // returns "Warning"
Once the app is running, you can access the Configuration settings via dependency injection in other classes of your application.
public MyClass(IConfiguration configuration)
{
var logLevel = configuration["Logging:LogLevel:Default"];
}
A nice feature worth considering it to create a class that represents your settings and then bind the configuration to an instance of that class type. For example, let's assume you create a new class called MyAppSettings with the same structure as your appSettings.json, you can do the following:
var myAppSettings = builder.Configuration.Get<MyAppSettings>();
string logLevel = myAppSettings.Logging.LogLevel.Default;
.NET 6 already gives builder object in Program.cs
var builder = WebApplication.CreateBuilder(args);
Just use this builder to access configuration and Environment as an example to get ConnectionString from app.settings.cs as follows:
builder.Services.AddDbContext<DataContext>( options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnectiion"));
});
//.NET6 Program.cs -(to get the application configuration properties)
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
builder.Configuration.AddJsonFile($"appsettings.Dev.json", optional: true);
builder.Configuration.AddEnvironmentVariables();
// projectwide instances
public IConfiguration _configuration;
public AccountsAPIController(IConfiguration configuration)
{
_configuration = configuration;
}
// _configuration.GetConnectionString("DefaultConnection");
I know the question originally asks for ASPNetCore but if you happen to looking to do the same for a worker service, and landed here like I did, hopefully, this answer helps you.
Worker Service user IHostBuilder instead of IWebApplicationBuilder and that does not expose a Configuration property, but you can accept an instance of IHostBuilderContext into the ConfigureServices method, which does expose a Configuration instance.
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
var settings = context.Configuration.Get<Settings>();
})
.Build();
All you need is to add "builder." before your Configuration
Like:
builder.Services
.AddDbContext<FestifyContext>
(opt =>opt.UseSqlServer(builder.Configuration
.GetConnectionString("Festify")));
This worked for me ---
// Read in from JSON file
builder.Services.Configure<ConnectionKeys>(builder.Configuration.GetSection("ConnectionKeys"));
This is slightly different than prior answers and I include this since I was reviewing something like this.
In your Program.cs you can also group code in a method and call that to keep it less run-on a bit or to group similar things. I will not put all the code in; I will not put a full list of using directives here but just enough to demonstrate the technique and I will leave out some method code. This is not enough or even perhaps too much for your solution and will need your custom touchup.
using AutoMapper;
using MicroKnights.Log4NetHelper;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
...
//all your using directives
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
//a variable to hold configuration
IConfiguration Configuration;
var builder = WebApplication.CreateBuilder(args);
Configuration = builder.Configuration;
// call some methods
ConfigureAuth(builder.Services);
ConfigureRedis(builder.Services);
ConfigureSession(builder.Services);
ConfigureMvc(builder.Services);
ConfigureServices(builder.Services);
var app = builder.Build();
ConfigureMiddleWare(app);
app.Run();
// we are done with the main part, now the methods
void ConfigureMvc(IServiceCollection services)
{
builder.Services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
config.Filters.Add(new AuthorizeFilter(policy));
})
.AddRazorPagesOptions(options => { options.Conventions.AddPageRoute("/Home/Login", ""); })
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
}
void ConfigureSession(IServiceCollection services)
{
builder.Services.AddSession(options =>
{
options.Cookie.Name = "mygreatsite_session";
options.IdleTimeout = TimeSpan.FromMinutes(60);
});
}
void ConfigureRedis(IServiceCollection services)
{
var redisConfig = new RedisOptions();
Configuration.GetSection(RedisOptions.RedisConfig).Bind(redisConfig);
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = redisConfig.ConnectionString;
options.InstanceName = "mygreatsite_";
});
services.AddDataProtection()
.SetApplicationName("MyGreatSite.Website")
.PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect(redisConfig.ConnectionString), "DataProtection-Keys");
}
void ConfigureMiddleWare(WebApplication app)
{
if (builder.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseRouting();
app.UseCors("default");
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute().RequireAuthorization();
endpoints.MapControllerRoute(
name: "Default",
pattern: "{controller=Home}/{action=Login}"
);
});
}
The following codes worked for me:
Program.cs:
var builder = WebApplication.CreateBuilder(args);
string connString = builder.Configuration.GetConnectionString("conStr");
ConnectionString = connString;
...
partial class Program
{
public static string? ConnectionString { get; private set; }
}
calling class:
string cnStr = Program.ConnectionString;
I resolved this issue by simple way:
In Program.cs:
using SomeAppName.Startup;
WebApplication.CreateBuilder(args)
.RegisterServices()
.Build()
.SetupMiddleware()
.Run();
Next:
public static WebApplicationBuilder RegisterServices(this WebApplicationBuilder builder)
{
BuildConfiguration(builder.Environment);
//// Any code
}
Finally:
private static IConfiguration BuildConfiguration(IHostEnvironment env)
{
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("./Configuration/appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile("./Configuration/appsettings.other.json", optional: false, reloadOnChange: true)
.AddJsonFile($"./Configuration/appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile($"./Configuration/appsettings.other.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = configurationBuilder.Build();
return Configuration;
}

How to use startup class inside program file on .NET 6?

I working on an ASP.NET Core 2.2 web application. I have some issues when upgrade my application to .NET 6.
My issue is that there's no startup class in .NET 6.0 and I found program.cs file only.
I add startup class on my web application but I don't know how to use it inside Program.cs.
How to add or use startup class inside my program.cs?
This is the startup.cs file in .NET Core 2.2:
public class Startup
{
private readonly IConfigurationRoot configRoot;
private AppSettings AppSettings { get; set; }
public Startup(IConfiguration configuration)
{
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
Configuration = configuration;
IConfigurationBuilder builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");
configRoot = builder.Build();
AppSettings = new AppSettings();
Configuration.Bind(AppSettings);
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddController();
services.AddDbContext(Configuration, configRoot);
services.AddIdentityService(Configuration);
services.AddAutoMapper();
services.AddScopedServices();
services.AddTransientServices();
services.AddSwaggerOpenAPI();
services.AddMailSetting(Configuration);
services.AddServiceLayer();
services.AddVersion();
services.AddHealthCheck(AppSettings, Configuration);
services.AddFeatureManagement();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory log)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(options =>
options.WithOrigins("http://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod());
app.ConfigureCustomExceptionMiddleware();
log.AddSerilog();
//app.ConfigureHealthCheck();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.ConfigureSwagger();
app.UseHealthChecks("/healthz", new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
ResultStatusCodes =
{
[HealthStatus.Healthy] = StatusCodes.Status200OK,
[HealthStatus.Degraded] = StatusCodes.Status500InternalServerError,
[HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable,
},
}).UseHealthChecksUI(setup =>
{
setup.ApiPath = "/healthcheck";
setup.UIPath = "/healthcheck-ui";
//setup.AddCustomStylesheet("Customization/custom.css");
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
And this is my .NET 6 program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// 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.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
How to use the startup class inside program.cs class ?
Updated Post
every thing is working but configure service not working
because i don't know how to implement ILoggerFactory
on startup
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory log)
{
}
on program.cs
startup.Configure(app, app.Environment,???);
How to add logger factory as third paramter on program.cs
ILoggerFactory is buit in class
Updated it solved using
var app = builder.Build();
startup.Configure(
app,
builder.Environment,
app.Services.GetRequiredService<FooService>(),
app.Services.GetRequiredService<ILoggerFactory>()
);
can you please tell me how to apply swagger ui to check my api
New templates use the so called minimal hosting model but nobody prevents from switching back to the generic hosting one used previously (or via WebHost).
If you want to work with top-level statements you can copy contents of Main method to the Program.cs file and then copy all other methods declared in the old Program class. New Program.cs potentially can look something like this:
await CreateHostBuilder(args)
.Build()
.RunAsync();
// do not forget to copy the rest of the setup if any
static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Or just remove the Startup class completely and move configure methods to corresponding parts of new file (maybe extracting some to concise extension methods).
You can manually instantiate the Startup and manually call the method ConfigureServices and Configure :
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, builder.Environment);
In ASP.NET Core 2.*, Startup.Configure accepted injected service :
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<IFooService, FooService>();
}
public void Configure(WebApplication app, IWebHostEnvironment env, IFooService fooService, ILoggerFactory loggerFactory)
{
fooService.Init();
...
}
}
Then you can :
var app = builder.Build();
startup.Configure(
app,
builder.Environment,
app.Services.GetRequiredService<FooService>(),
app.Services.GetRequiredService<ILoggerFactory>()
);
When I migrated my APIs, first I consider to reuse the Startup class... but finally I moved the configuration in extension methods.

How to move code in Startup.cs in ASP.NET Core 3.1 to ASP.NET Core 6?

I re-use source code from this project https://www.c-sharpcorner.com/article/custome-jwt-token-and-asp-net-core-web-api/ , download project at https://www.c-sharpcorner.com/article/custome-jwt-token-and-asp-net-core-web-api//download/JWTTokenPOC.zip
This is ASP.NET Core API version 3.x , it has
File Startup.cs
using JWTTokenPOC.Helper;
using JWTTokenPOC.Service;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace JWTTokenPOC
{
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddControllers();
// configure to get Appsetting section from appsetting.json
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddScoped<IUserService, UserService>();
services.AddScoped<IAuthenticationService, AuthenticationService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
// set global cors policy
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
// Custom jwt auth middleware to authenticate the token
app.UseMiddleware<JwtMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Now, I code ASP.NET Core WebAPI 6.x project.
I dont' have Startup.cs in project, I just have file Program.cs
using acc7.Data;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
namespace acc7
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
// builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseNpgsql(connectionString));
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseNpgsql("Server=127.0.0.1;Port=5432;Database=acc200;User Id=postgres;Password=postgres;"));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
Please guide me migration code from ASP.NET Core WebAPI version 3.1 project --> ASP.NET Core WebAPI version 6.x project. I need feature JWT authentication.
(I don't program C# and ASP.NET Core frequently, every day code Java server-side)
You can re-use your Startup class like this:
var builder = WebApplication.CreateBuilder(args);
// Manually create an instance of the Startup class
var startup = new Startup(builder.Configuration);
// Manually call ConfigureServices()
startup.ConfigureServices(builder.Services);
var app = builder.Build();
// Fetch all the dependencies from the DI container
// var hostLifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
// As pointed out by DavidFowler, IHostApplicationLifetime is exposed directly on ApplicationBuilder
// Call Configure(), passing in the dependencies
startup.Configure(app, app.Lifetime);
app.Run();
Source:
https://andrewlock.net/exploring-dotnet-6-part-12-upgrading-a-dotnet-5-startup-based-app-to-dotnet-6/#option-2-re-use-your-startup-class
In configure services, you are adding your dependencies to register. So .NET 6 equivalent is to use builder.Services
For example
builder.Services.AddCors();
builder.Services.AddControllers();
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings"));
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
To configure the request pipeline in .NET 6
var app = builder.Build();
use the app here to build your request pipeline, For example
app.UseRouting();
// set global cors policy
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
// Custom jwt auth middleware to authenticate the token
app.UseMiddleware<JwtMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});

How to add ApplicationService in .Net 6 [duplicate]

In earlier versions, we had Startup.cs class and we get configuration object as follows in the Startup file.
public class Startup
{
private readonly IHostEnvironment environment;
private readonly IConfiguration config;
public Startup(IConfiguration configuration, IHostEnvironment environment)
{
this.config = configuration;
this.environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
// Add Services
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Add Middlewares
}
}
Now in .NET 6 (With Visual Studio 2022), we don't see the Startup.cs class. Looks like its days are numbered. So how do we get these objects like Configuration(IConfiguration) and Hosting Environment(IHostEnvironment)
How do we get these objects, to say read the configuration from appsettings? Currently the Program.cs file looks like this.
using Festify.Database;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddDbContext<FestifyContext>();
////////////////////////////////////////////////
// The following is Giving me error as Configuration
// object is not avaible, I dont know how to inject this here.
////////////////////////////////////////////////
builder.Services.AddDbContext<FestifyContext>(opt =>
opt.UseSqlServer(
Configuration.GetConnectionString("Festify")));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// 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.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
I want to know how to read the configuration from appsettings.json ?
WebApplicationBuilder returned by WebApplication.CreateBuilder(args) exposes Configuration and Environment properties:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
...
ConfigurationManager configuration = builder.Configuration; // allows both to access and to set up the config
IWebHostEnvironment environment = builder.Environment;
WebApplication returned by WebApplicationBuilder.Build() also exposes Configuration and Environment:
var app = builder.Build();
IConfiguration configuration = app.Configuration;
IWebHostEnvironment environment = app.Environment;
Also check the migration guide and code samples.
In Program.cs, the WebApplicationBuilder is created shown below.
var builder = WebApplication.CreateBuilder(args);
Once we have the builder created, the configuration is available.
Let's assume you have the default appSettings.json in place. The example code below would return the configuration Default log level setting from the JSON configuration file.
builder.Configuration["Logging:LogLevel:Default"] // returns "Warning"
Once the app is running, you can access the Configuration settings via dependency injection in other classes of your application.
public MyClass(IConfiguration configuration)
{
var logLevel = configuration["Logging:LogLevel:Default"];
}
A nice feature worth considering it to create a class that represents your settings and then bind the configuration to an instance of that class type. For example, let's assume you create a new class called MyAppSettings with the same structure as your appSettings.json, you can do the following:
var myAppSettings = builder.Configuration.Get<MyAppSettings>();
string logLevel = myAppSettings.Logging.LogLevel.Default;
.NET 6 already gives builder object in Program.cs
var builder = WebApplication.CreateBuilder(args);
Just use this builder to access configuration and Environment as an example to get ConnectionString from app.settings.cs as follows:
builder.Services.AddDbContext<DataContext>( options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnectiion"));
});
//.NET6 Program.cs -(to get the application configuration properties)
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
builder.Configuration.AddJsonFile($"appsettings.Dev.json", optional: true);
builder.Configuration.AddEnvironmentVariables();
// projectwide instances
public IConfiguration _configuration;
public AccountsAPIController(IConfiguration configuration)
{
_configuration = configuration;
}
// _configuration.GetConnectionString("DefaultConnection");
I know the question originally asks for ASPNetCore but if you happen to looking to do the same for a worker service, and landed here like I did, hopefully, this answer helps you.
Worker Service user IHostBuilder instead of IWebApplicationBuilder and that does not expose a Configuration property, but you can accept an instance of IHostBuilderContext into the ConfigureServices method, which does expose a Configuration instance.
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
var settings = context.Configuration.Get<Settings>();
})
.Build();
All you need is to add "builder." before your Configuration
Like:
builder.Services
.AddDbContext<FestifyContext>
(opt =>opt.UseSqlServer(builder.Configuration
.GetConnectionString("Festify")));
This worked for me ---
// Read in from JSON file
builder.Services.Configure<ConnectionKeys>(builder.Configuration.GetSection("ConnectionKeys"));
This is slightly different than prior answers and I include this since I was reviewing something like this.
In your Program.cs you can also group code in a method and call that to keep it less run-on a bit or to group similar things. I will not put all the code in; I will not put a full list of using directives here but just enough to demonstrate the technique and I will leave out some method code. This is not enough or even perhaps too much for your solution and will need your custom touchup.
using AutoMapper;
using MicroKnights.Log4NetHelper;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
...
//all your using directives
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
//a variable to hold configuration
IConfiguration Configuration;
var builder = WebApplication.CreateBuilder(args);
Configuration = builder.Configuration;
// call some methods
ConfigureAuth(builder.Services);
ConfigureRedis(builder.Services);
ConfigureSession(builder.Services);
ConfigureMvc(builder.Services);
ConfigureServices(builder.Services);
var app = builder.Build();
ConfigureMiddleWare(app);
app.Run();
// we are done with the main part, now the methods
void ConfigureMvc(IServiceCollection services)
{
builder.Services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
config.Filters.Add(new AuthorizeFilter(policy));
})
.AddRazorPagesOptions(options => { options.Conventions.AddPageRoute("/Home/Login", ""); })
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
}
void ConfigureSession(IServiceCollection services)
{
builder.Services.AddSession(options =>
{
options.Cookie.Name = "mygreatsite_session";
options.IdleTimeout = TimeSpan.FromMinutes(60);
});
}
void ConfigureRedis(IServiceCollection services)
{
var redisConfig = new RedisOptions();
Configuration.GetSection(RedisOptions.RedisConfig).Bind(redisConfig);
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = redisConfig.ConnectionString;
options.InstanceName = "mygreatsite_";
});
services.AddDataProtection()
.SetApplicationName("MyGreatSite.Website")
.PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect(redisConfig.ConnectionString), "DataProtection-Keys");
}
void ConfigureMiddleWare(WebApplication app)
{
if (builder.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseRouting();
app.UseCors("default");
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute().RequireAuthorization();
endpoints.MapControllerRoute(
name: "Default",
pattern: "{controller=Home}/{action=Login}"
);
});
}
The following codes worked for me:
Program.cs:
var builder = WebApplication.CreateBuilder(args);
string connString = builder.Configuration.GetConnectionString("conStr");
ConnectionString = connString;
...
partial class Program
{
public static string? ConnectionString { get; private set; }
}
calling class:
string cnStr = Program.ConnectionString;
I resolved this issue by simple way:
In Program.cs:
using SomeAppName.Startup;
WebApplication.CreateBuilder(args)
.RegisterServices()
.Build()
.SetupMiddleware()
.Run();
Next:
public static WebApplicationBuilder RegisterServices(this WebApplicationBuilder builder)
{
BuildConfiguration(builder.Environment);
//// Any code
}
Finally:
private static IConfiguration BuildConfiguration(IHostEnvironment env)
{
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("./Configuration/appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile("./Configuration/appsettings.other.json", optional: false, reloadOnChange: true)
.AddJsonFile($"./Configuration/appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile($"./Configuration/appsettings.other.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = configurationBuilder.Build();
return Configuration;
}

How to access Azure app service settings/configuration in .NET 6? [duplicate]

This question already has answers here:
ASP.NET Core 6 how to access Configuration during startup
(10 answers)
Closed 12 months ago.
I have a web app running in Azure which is currently running on .NET 5, which I'm trying to upgrade to 6. I have refactored the code to remove the Startup.cs file and refactored Program.cs to suit the new structure of .NET 6 apps. Before anybody else tells me that the old way with two files still works, yes I know, but I want to move to the new standard so that this can serve as a template for future apps, which by default when first created in VS only use the one file.
In the existing Startup.cs file, I have something like this:
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Web;
namespace MyApp.Web.Server
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection(Constants.AzureAdB2C))
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "https://example.com/api/query" })
.AddInMemoryTokenCaches();
// Other services added here
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(
endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
When the Startup constructor is called, an IConfiguration instance is injected in, which I understand is done dynamically when running on DevOps to include all app settings set in the App Service -> Settings -> Configuration -> Application settings page. This all works fine at the moment.
However, the new Program.cs file with the .NET 6 syntax looks like this:
using System.Reflection;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
IConfiguration configuration;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
string appSettingsPath = Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"appsettings.json");
configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(appSettingsPath, optional: false, reloadOnChange: true)
.Build();
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(configuration.GetSection(Constants.AzureAdB2C))
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "https://example.com/api/query" })
.AddInMemoryTokenCaches();
// Other services added here
WebApplication app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(
endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
app.Run();
As you can see above, there is no constructor and therefore I have no way of injecting the IConfiguration instance, so at the moment I'm presuming there is an appsettings.json file and creating it from that. This won't work when running in the Azure environment as the settings specified in the dashboard don't get added to the appsettings.json file, they are set as environment variables.
I can retrieve environment variables but I can't retrieve variable groups, as is the requirement in this particular case of adding Microsoft.Identity authentication. Is there no way of dynamically resolving/injecting the IConfiguration instance as before?
Turns out I was over-thinking this. I figured that there is still an IServiceCollection being created and/or dynamically added to by the Azure app service runtime so tried removing all code that tries to create an IConfiguration instance and just presume that there is already one there after creating the .NET 6 WebApplicationBuilder instance.
Sure enough, there is. All I needed to do was reference the builder.Configuration instance, which already has the IConfiguration injected from the Azure container:
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddApplicationInsightsTelemetry();
builder.Services.AddRazorPages();
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection(Constants.AzureAdB2C))
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "https://example.com/api/query" })
.AddInMemoryTokenCaches();
builder.Services.Configure<OpenIdConnectOptions>(builder.Configuration.GetSection("AzureAdB2C"));
// Other services added here
WebApplication app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(
endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
app.Run();
Just for info, if like me you have local appsettings.json files for running in debug or testing, I have the following methods in a helper class:
public static IConfiguration GetConfigurationFromAssembly(string appSettingsFileName)
{
Assembly dataAssembly = Assembly.LoadFrom(
Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"MyApp.Web.Data.dll")); // Put your own project DLL containing the embedded resource here
Stream jsonStream =
dataAssembly.GetManifestResourceStream($"MyApp.Web.Data.{appSettingsFileName}");
return new ConfigurationBuilder()
.AddJsonStream(jsonStream)
.SetBasePath(Directory.GetCurrentDirectory())
.Build();
}
public static IConfiguration GetConfigurationFromFile(string appSettingsFileName)
{
string appSettingsPath = Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
appSettingsFileName);
return new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(appSettingsPath, optional: false, reloadOnChange: true)
.Build();
}
You can then add the returned IConfiguration object to the WebApplicationBuilder like this:
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
#if DEBUG
configuration = Configurations.GetConfigurationFromAssembly("appsettings.Development.json");
builder.Configuration.AddConfiguration(configuration);
#endif
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection(Constants.AzureAdB2C))
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "https://example.com/api/query" })
.AddInMemoryTokenCaches();

Categories