I don't want to use CreateDefaultBuilder and ConfigureWebHostDefaults in Program.cs file. Both of these functions make certain assumptions, that I am not comfortable with, also I don't want to rely on ASP.net defaults. I want to setup builder myself but don't know how to do that
I want to replace following code with my own builder
var host = Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder =>
{
builder.Sources.Clear();
...
})
.ConfigureWebHostDefaults(webBuilder =>
{
...
})
.ConfigureServices((context, services) =>
services.Configure<...>(
context.Configuration.GetSection("...")))
.Build();
You can create an instance of HostBuilder directly:
var host = new HostBuilder()
.Build();
HostBuilder has a number of useful methods, such as ConfigureServices, ConfigureAppConfiguration, etc:
var host = new HostBuilder()
.ConfigureAppConfiguration(builder =>
{
// ...
})
.ConfigureServices((context, services) =>
{
// ...
})
.Build();
To configure the WebHost, without the defaults, use ConfigureWebHost:
var host = new HostBuilder()
.ConfigureWebHost(webHostBuilder =>
{
})
.Build();
Related
How can I setup listening multiple ports? On first port I want to have default app with https, on another I want to use HTTPS and require SSL based authentication with client certificates. How to do it? This is my current Startup.cs code:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(kestrelOptions =>
{
kestrelOptions.ConfigureHttpsDefaults(httpOptions =>
{
httpOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
});
});
var services = builder.Services;
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, cfg =>
{
cfg.ReturnUrlParameter = "returnUrl";
cfg.LoginPath = "/account/login";
cfg.LogoutPath = "/account/logout";
})
.AddCertificate(CertificateAuthenticationDefaults.AuthenticationScheme, cfg =>
{
cfg.AllowedCertificateTypes = CertificateTypes.All;
cfg.RevocationMode = X509RevocationMode.Online;
});
services.AddControllersWithViews();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
My goal is to use Certificate authentication on some endpoints (and don't display certificate request e.g. for web explorer users) and not use delayed certificates.
I did it with kestrelOptions.ListenLocalhost:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(kestrelOptions =>
{
kestrelOptions.ListenLocalhost(8080, cfg =>
{
cfg.UseHttps(httpOptions =>
{
httpOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
});
});
kestrelOptions.ListenLocalhost(8081, cfg =>
{
cfg.UseHttps(httpOptions =>
{
httpOptions.ClientCertificateMode = ClientCertificateMode.NoCertificate;
});
});
});
Now one port is for mTLS (8080) and another don't require certificate! Works really nice.
I've got app in .net core 5.
And this is the code in Startup.cs
'''''
public static IHostBuilder CreateHostBuilder(string[] args) =>
//Host.CreateDefaultBuilder(args)
// .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder
.UseStartup<Startup>()
.UseKestrel(o =>
{
o.Listen(IPAddress.Any, 443, opt =>
{
opt.UseHttps("pathfto.pfx", "passwordtocert");
});
});
});
I would like to take upgrade it to .net core 6
I thought that it would be like this
var builder = WebApplication.CreateBuilder(args);
builder.Host
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseKestrel(o =>
{
o.Listen(IPAddress.Any, 443, opt => { opt.UseHttps("pathto.pfx", "passwordtocert"); });
});
});
But it doesn't work when I try compile it.
Thank you in advance for any solutions.
Try to use builder.WebHost
builder.WebHost.ConfigureKestrel(options =>
{
options.Listen(IPAddress.Any, int.Parse(builder.Configuration.GetSection("SSL")["port"]), listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
if (builder.Configuration.GetSection("SSL")["sertificateName"].Trim() != "")
listenOptions.UseHttps(Path.Combine(AppContext.BaseDirectory, "cfg", builder.Configuration.GetSection("SSL")["sertificateName"]), builder.Configuration.GetSection("SSL")["password"]);
});
});
More details you find on https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0
Your problem is your trying builder.Host instead of builder.WebHost. I think this would be the equivalent.
Program.cs
builder.WebHost.ConfigureKestrel(opt => {
opt.ListenAnyIP(443, listOpt =>
{
listOpt.UseHttps(#"pathto.pfx", "passwordtocert");
});
});
var app = builder.Build();
I am creating a Worker application using Net 6 and I have in Program.cs:
IHostBuilder builder = Host.CreateDefaultBuilder(args);
builder.ConfigureHostConfiguration(x => {
x.AddJsonFile("settings.json", false, true);
x.AddJsonFile($"settings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", false, true);
x.AddEnvironmentVariables();
});
builder.UseSerilog(new LoggerBuilder(
new LoggerOptions {
ConnectionString = builder.Configuration.Get<Options>().ConnectionString
},
).CreateLogger());
In LoggerOptions I need to get Options and the ConnectionString from it.
I tried the following because that is what I do when using WebApplicationBuilder:
builder.Configuration.Get<Options>().ConnectionString
But this does not compile as it seems IHostBuilder does not have a Configuration property.
How can I do this?
Simple example:
var hostBuilder = Host.CreateDefaultBuilder(args);
hostBuilder.UseSerilog((hostContext, services) =>
{
var connectionString = hostContext.Configuration.GetConnectionString("MyConnectionString");
});
hostBuilder.ConfigureServices((hostContext, services) =>
{
var connectionString = hostContext.Configuration.GetConnectionString("MyConnectionString");
}
You can access it by using the configure services overload that accepts the HostBuilderContext. I don't typically use the LoggerBuilder:
IHost host = Host.CreateDefaultBuilder(args)
.UseSerilog((context, loggerConfiguration) =>
{
loggerConfiguration.ReadFrom.Configuration(context.Configuration);
})
.Build();
await host.RunAsync();
I want to start logging before webhost, so startup errors are logged. So I followed Serilog's recommended init order: 1) configuration, 2) logging, 3) webhost. I'm not using CreateDefaultBuilder().
So my Program.cs has:
// setup config
var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional:false, reloadOnChange:true)
.AddJsonFile($"appsettings.{envName}.json", optional:true, reloadOnChange:true)
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
// setup Serilog logging
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration) // <<< uses config from above
.CreateLogger()
// setup webhost
new WebHostBuilder()
.UseConfiguration(configuration) // <<< uses config from above
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseSerilog()
.Build()
.Run();
This works, but changes in appsettings.json are not detected even though I specified reloadOnChange:true.
However when I use ConfigureAppConfiguration() then changes are detected:
new WebHostBuilder()
.ConfigureAppConfiguration((context, config) => {
// .. duplicate config here
})
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseSerilog()
.Build()
.Run();
But that means duplication and possibly unforseen problems - i.e. this is a hack. How do I solve this?
UPDATE
As per #StephenZeng's answer, UseConfiguration won't help me here, so I suppose I need to use ConfigureAppConfiguration. But the problem remains - how do I init my config first, then use it multiple times without redefining it?
From the document it is by design:
"UseConfiguration only copies keys from the provided IConfiguration to the host builder configuration. Therefore, setting reloadOnChange: true for JSON, INI, and XML settings files has no effect."
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-2.1&tabs=aspnetcore2x
I've run into the same issue, and I created a method with the responsibility to configure the builder. I then call the method from both Main and when I build the web host. Something like this:
public static class Program
{
public static int Main()
{
var configuration = new ConfigurationBuilder()
.AddConfiguration()
.Build();
// setup Serilog logging
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
// Code removed for brevity...
}
private static IWebHost BuildWebHost() =>
WebHost.CreateDefaultBuilder()
.UseSerilog()
.UseStartup<Startup>()
.ConfigureAppConfiguration((hostingContext, config) =>
{
// Clear default configuration
config.Sources.Clear();
// Replace with our own configuration
config.AddConfiguration();
})
.Build();
private static IConfigurationBuilder AddConfiguration(this IConfigurationBuilder self) =>
self
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional:false, reloadOnChange:true)
.AddJsonFile($"appsettings.{envName}.json", optional:true, reloadOnChange:true)
.AddEnvironmentVariables();
}
The solution is to avoid UseConfiguration and use ConfigureAppConfiguration instead:
// setup config
// ..as before
// ..this is done only once
// setup Serilog logging
// ...as before
// setup webhost
new WebHostBuilder()
.ConfigureAppConfiguration((context, config) => {
config.AddConfiguration(configuration); // <<< uses config from above
})
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseSerilog()
.Build()
.Run();
I am trying to use cookie based authentication in ASP.Net Core 2.0 Web API and trying to activate that using the following code. The signin page is hosted inan separate domain than the one the app is hosted. And I have added [Authorize] attribute to the controller.
At startup I can see the service code invoked in debugger.
My expectation is that when my web client use the web api service, the middleware will detect that header does not have the cookie and will redirect the client to the login page. Yet I am able to invoke the controller freely.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("AllowAll",
builder => builder.SetIsOriginAllowed(s => true)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()));
services.TryAddTransient<CorsAuthorizationFilter, CorsAuthorizationFilter>();
services.AddSwaggerGen(c =>
{
c.OperationFilter<FileOperationFilter>();
c.SwaggerDoc("v1", new Info
{
Title = "Collateral Management API",
Version = "v1"
});
});
services.AddMvcCore(options =>
{
options.Filters.Add(new CorsAuthorizationFilterFactory("AllowAll"));
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.AddApiExplorer()
.AddJsonFormatters(s => s.NullValueHandling = NullValueHandling.Ignore);
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(auth =>
{
auth.Cookie.Domain = "xxx.com";
auth.Cookie.Name = "xxx";
auth.LoginPath = "/signin";
auth.AccessDeniedPath = "/signin";
});
services.AddAuthorization(auth =>
{
auth.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
});
//...
}
and later ...
app.UseAuthentication()
Try adding:
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
});
After services.AddMvc()
EDIT
Given the way you are adding MVC can you try:
// requires: using Microsoft.AspNetCore.Authorization;
// using Microsoft.AspNetCore.Mvc.Authorization;
services.AddMvcCore(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
AddMvcCore doesn't add the authorization services by default. You will also need to do AddMvcCore(...).AddAuthorization()