ASP.NET Core 7.0 - configure Kestrel applicationURL - c#

.netAt the moment, this is the code I have:
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseWindowsService(options => {
options.ServiceName = "My Server";
}).ConfigureServices(services => {
services.AddHostedService<WindowsBackgroundService>();
});
...
and
"profiles": {
"MyProj": {
"applicationUrl": "http://127.0.0.1:5000;",
How do I instead set applicationUrl (with port) in the builder configuration?
I saw various answers but not sure how to proceed with ASP.NET Core 7.0, here it says to use:
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
// ...
});
});
but I am not sure how to set the applicationUrl and if WebHost is what I need (as I am using a Windows service as above).

It's perfectly valid to use WebApplicationBuilder.WebHost in combination with the Windows Service functionality, as the WebHost still runs when using WebApplicationBuilder.
Because of that, I think the simplest method for setting the URL for your scenario is to use UseUrls:
builder.WebHost.UseUrls("http://127.0.0.1:5000");
This doesn't require setting anything that's specific to Kestrel, yet the configuration does make its way down to Kestrel.
To configure Kestrel directly, you can use ConfigureKestrel, as suggested in your question. To set the URL this way, use the Listen method:
builder.WebHost.ConfigureKestrel(kestrelServerOptions =>
{
kestrelServerOptions.Listen(IPAddress.Loopback, 5001);
});
There are a number of options for configuring the URL, such as configuring HTTPS, using DnsEndPoint, etc. This approach offers a lot more flexibility, but if you simply want to set the URL programmatically, I'd still recommend the UseUrls approach.

Just run the following command in cmd start-url-in-aspnet-core
setx ASPNETCORE_URLS "http://127.0.0.1:5001;https://127.0.0.1:5002"

Related

CheckMarx Medium severity warning - HttpOnly cookie at Startup

CheckMarx is flagging an error which looks like a false positive to me. Our application is written in C# and uses ASP.NET Core.
The error is:
The web application's Startup method creates a cookie Startup, at line 22 of Startup.cs, and returns it in the response. However, the application is not configured to automatically set the cookie with the "httpOnly" attribute, and the code does not explicitly add this to the cookie.
This is line 22:
public class Startup
And we do have the cookie policy set correctly:
app.UseCookiePolicy(new CookiePolicyOptions
{
HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always
});
But CheckMarx is still flagging this warning. And I do not think that my Startup class creates a cookie called Startup.
I found a similar post here (unanswered) - https://github.com/Azure/azure-functions-vs-build-sdk/issues/469.
So is this a false positive? And how do I get CheckMarx to stop flagging it?
The only way to remove those warnings was to rename the Startup class to something else, for example to Startup123.
Nothing else removes the warning, and I think it is definitely a false positive.
For .NET Core 3.1, I fixed this vulnerability warning by configuring the service in Startup class and then using CookiePolicy middleware.
In ConfigureServices function:
services.Configure<CookiePolicyOptions>(options =>
{
options.Secure = CookieSecurePolicy.Always;
});
In Configure function:
app.UseCookiePolicy();
This could be also used to fix HttpOnlyPolicy vulnerability in middleware like:
services.Configure<CookiePolicyOptions>(options =>
{
options.HttpOnly = HttpOnlyPolicy.Always;
options.Secure = CookieSecurePolicy.Always;
});
Remember to use the correct order for middlewares. You could refer to ASP.NET Core Middleware Docs to read more about and get some examples.

Turn `ReloadOnChange` off in config source for WebApplicationFactory

This is both a question and an answer. I've fixed my problem, but it seems a bit wrong.
My original problem is running my asp.net core integration tests in a bitbucket pipeline causes System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached. Some solutions call for changing some setting through sysctl, but that is restricted by bitbucket, so that isn't an option for me.
The second way of fixing this, as noted in these stackoverflow answers, is to turn reloadOnChange off.
My new problem is now, how do we best do this for the test WebApplicationFactory?
One solution that has worked for me, which is the least amount of code, seems like a total hack. I iterate through all the JsonConfigurationSource and set ReloadOnChange to false.
Full solution:
public class TestApplicationFactory : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration(config =>
{
foreach (var source in config.Sources)
{
if (source is JsonConfigurationSource)
{
var jsonConfigSource = (JsonConfigurationSource) source;
jsonConfigSource.ReloadOnChange = false;
}
}
});
}
}
Another solution, that I haven't tried, may be to override CreateWebHostBuilder(). However, it seems like more code and a lot of copy and paste from the default one.
Am I missing something? Is there a better way to do this?
Just experienced this issue myself running integration tests within a Linux container and followed the previous suggestions to switch off the ReloadOnChange within the WebApplicationFactory. Unfortunately that did not resolve the problem and integration tests were still failing with the same error:
System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached.
I also tried to configure xUnit to run the integration tests sequentially rather than in parallel, but that did not work either.
The solution that did work for me was to set the appropriate environment variable within the container that runs the integration tests:
export ASPNETCORE_hostBuilder__reloadConfigOnChange=false
builder.ConfigureAppConfiguration is there to configure your (main) application.
You can use builder.ConfigureHostConfiguration (see docs) to explicitly configure files to be read for the host.
builder.ConfigureHostConfiguration((hostingContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false);
});
The host configuration is loaded. ASP.NET Core from 3.0 is built based on Generic host (rather than the Web Host of the former versions).
You can do this without inheriting from WebApplicationFactory by using the WithWebHostBuilder and ConfigureAppConfiguration extension methods:
var webAppFactory = new WebApplicationFactory<Startup>().WithWebHostBuilder(webHostBuilder =>
{
webHostBuilder.ConfigureAppConfiguration((hostingContext, configBuilder) =>
configBuilder.Sources.Where(s => s is FileConfigurationSource).ToList()
.ForEach(s => ((FileConfigurationSource)s).ReloadOnChange = false));
});
This accomplishes the same thing as your original idea (which helped me a lot!), but more compact and without the need for a separate class definition.
I just encountered the same issue.
Setting the env variable DOTNET_hostBuilder:reloadConfigOnChange to false fixed it.
This solution works for net6 when you use the Generic Host. For other hosts, maybe try replacing DOTNET_ prefix with ASPNETCORE_
To make it simple, I set it in my code before creating the WebApplicationFactory
Environment.SetEnvironmentVariable("DOTNET_hostBuilder:reloadConfigOnChange", "false");

what is this ASP.NET Core log message: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager

I have this at every app start.
Does anyone know where this comes from?
info:
Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]
User profile is available. Using '/Users/thomas/.aspnet/DataProtection-Keys' as key repository; keys
will not be encrypted at rest.
// run the web host
var PathToContentRoot = Directory.GetCurrentDirectory();
var Host = WebHost.CreateDefaultBuilder()
.UseKestrel()
.UseContentRoot(PathToContentRoot)
.UseStartup<WebStartup>()
.UseNLog()
.Build();
I don't have anything about 'dataprotection', 'keys', etc nor do I want any form of security features.
The code in the ConfigureServices part is:
// find all controllers
var Controllers =
from a in AppDomain.CurrentDomain.GetAssemblies().AsParallel()
from t in a.GetTypes()
let attributes = t.GetCustomAttributes(typeof(ControllerAttribute), true)
where attributes?.Length > 0
select new { Type = t };
var ControllersList = Controllers.ToList();
Logging.Info($"Found {ControllersList.Count} controllers");
// register them
foreach (var Controller in ControllersList)
{
Logging.Info($"[Controller] Registering {Controller.Type.Name}");
Services
.AddMvc()
.AddJsonOptions(Options => Options.SerializerSettings.ContractResolver = new DefaultContractResolver())
.AddApplicationPart(Controller.Type.Assembly);
}
// add signalR
Services.AddSignalR();
It is done to allow controllers from external assemblies to be used.
Depending on what ASP.NET features you are using, the Core Data Protection middleware may be setup and added into the dependency injection container.
This provides a mechanism for storing sensitive data. Depending on what environment you are running in this sensitive data will be stored in different locations. In your case you are getting the message that it is being stored in the user profile (a folder on the system) and in plain text (I'm assuming because you are running on Linux as they would by default get encrypted on Windows). This article has a nice description of the default location for storing the sensitive data.
In your case I suspect it is the use of SignalR that is causing the Core Data Protection middle ware to be added. Another common cause for it being added is calling
IServiceCollection.AddAuthentication

How to change the port number for Asp.Net core app?

I added the following section in project.json.
"commands": {
"run": "run server.urls=http://localhost:8082",
"web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:8082",
"weblistener": "Microsoft.AspNet.Hosting --server WebListener --server.urls http://localhost:8082"
},
However, it still shows "Now listening on: http://localhost:5000" when run it using dotnet myapp.dll?
BTW, will clients from other machine be able to access the service?
Yes this will be accesible from other machines if you bind on any external IP address. For example binding to http://*:80 . Note that binding to http://localhost:80 will only bind on 127.0.0.1 interface and therefore will not be accesible from other machines.
Visual Studio is overriding your port. You can change VS port editing this file Properties\launchSettings.json or else set it by code:
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseUrls("http://localhost:80") // <-----
.Build();
host.Run();
A step by step guide using an external config file is available here.
It's working to me.
I use Asp.net core 2.2 (this way supported in asp.net core 2.1 and upper version).
add Kestrel section in appsettings.json file.
like this:
{
"Kestrel": {
"EndPoints": {
"Http": {
"Url": "http://localhost:4300"
}
}
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
and in Startup.cs:
public Startup(IConfiguration configuration, IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
Use simply dotnet YouApp.dll --urls http://0.0.0.0:80.
P.S. I don't know why I need to google this everytime and everytime it doesn't show up. So here it is.
In Asp.net core 2.0 WebApp, if you are using visual studio search LaunchSettings.json. I am adding my LaunchSettings.json, you can change port no as u can see.
In visual studio 2017 we can change the port number from LaunchSetting.json
In Properties-> LaunchSettings.json.
Open LaunchSettings.json and change the Port Number.
Change the port Number in json file
Use following one line of code .UseUrls("http://*:80") in Program.csThus changing .UseStartup<Startup>() to.UseStartup<Startup>()
.UseUrls("http://*:80")
3 files have to changed appsettings.json (see the last section - kestrel ), launchsettings.json - applicationurl commented out, and a 2 lines change in Startup.cs
Add below code in appsettings.json file and port to any as you wish.
},
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5003"
}
}
}
}
Modify Startup.cs with below lines.
using Microsoft.AspNetCore.Server.Kestrel.Core;
services.Configure<KestrelServerOptions>(Configuration.GetSection("Kestrel"));
Go to your program.cs file add UseUrs method to set your url, make sure you don't use a reserved url or port
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
// params string[] urls
.UseUrls(urls: "http://localhost:10000")
.Build();
}
We can use this command to run our host project via Windows Powershell without IIS and visual studio on a separate port. Default of krestel web server is 5001
$env:ASPNETCORE_URLS="http://localhost:22742" ; dotnet run
will clients from other machine be able to access the service?
add to appsettings.json
"Urls": "http://0.0.0.0:8082",
All the other answer accounts only for http URLs. If the URL is https, then do as follows,
Open launchsettings.json under Properties of the API project.
Change the sslPort under iisSettings -> iisExpress
A sample launchsettings.json will look as follows
{
"iisSettings": {
"iisExpress": {
"applicationUrl": "http://localhost:12345",
"sslPort": 98765 <== Change_This
}
},
in appsetting.json
{
"DebugMode": false,
"Urls": "http://localhost:8082"
}
Building on #Abdus Salam Azad's answer...
In Visual Studio 2022 if you right click an ASP.NET Core Web API project for example, you have access to this UI where you can set up ASPNETCORE variables like this:
There you can enter a custom URL:port for ASPNETCORE_URLS like this:
The following works in ASP.Net Core 6.0. Inside Program.cs have this:
var builder = WebApplication.CreateBuilder(args);
if (!app.Environment.IsDevelopment())
{
builder.WebHost.UseUrls("http://*:80", "https://*.443");
}
I find it is useful to wrap it in a conditional statement when publishing to production, but this isn't necessary.
This works running from a Kestrel server on Mac OS 12.
you can also code like this
IConfiguration config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
and set up your application by command line :dotnet run --server.urls http://*:5555
in your hosting.json
replace"Url": "http://localhost:80" by"Url": "http://*:80" and you will be able now access to your application by http://your_local_machine_ip:80 for example http://192.168.1.4:80
If you want to run on a specific port 60535 while developing locally but want to run app on port 80 in stage/prod environment servers, this does it.
Add to environmentVariables section in launchSettings.json
"ASPNETCORE_DEVELOPER_OVERRIDES": "Developer-Overrides",
and then modify Program.cs to
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel(options =>
{
var devOverride = Environment.GetEnvironmentVariable("ASPNETCORE_DEVELOPER_OVERRIDES");
if (!string.IsNullOrWhiteSpace(devOverride))
{
options.ListenLocalhost(60535);
}
else
{
options.ListenAnyIP(80);
}
})
.UseStartup<Startup>()
.UseNLog();
});
Maybe it's because I am not using Core yet. My project didn't have a LaunchSettings.json file but that did prompt me to look in the project properties. I found it under the Web tab and simply changed the project url:
I had a similar issue with a Kubernetes deployment after upgrading to .NET 6. The solution was simply to add the following environment variable to the deployment:
- name: Kestrel__Endpoints__Http__Url
value: http://0.0.0.0:80
This will work anywhere else where you can use an environment variable
Core 6.0 -->
Without any JSON setting changes we do some thing like this..
I also commented some code bcoz I don't have certificate. we can run it any port.
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
// serverOptions.Listen(System.Net.IPAddress.Loopback, 5003);
serverOptions.Listen(System.Net.IPAddress.Loopback, 8086, listenOptions =>
{
listenOptions.UseHttps();
//listenOptions.UseHttps("testCert.pfx", "testPassword");
});
});
I created my project using Visual Studio 2022, so in Project/Properties/launchSettings.json there are two parts for this topic:
1- for lunching in IISExpress :
"iisSettings": {
..
"iisExpress": {
"applicationUrl": "http://localhost:31520",
"sslPort": 44346
}
},
2- for lunching through IDE:
"profiles": {
"MaxTemplate.API": {
...
"applicationUrl": "https://localhost:7141;http://localhost:5141",
...
}
},
For example you can change the port 7141 to 5050 and run the project again.
In asp.net core 6
app.Run("https://*:25565");
or in my case for deploying on heroku
app.Run("https://*:"+Environment.GetEnvironmentVariable("PORT"));
Don't have enough rep to add this as a comment, but I want to add that the WebHost.UseUrls() in .net core 6 can be set using a combination of IPAddress and IPEndPoint in file Program.cs
if (!builder.Environment.IsDevelopment()) // app in release
{
// listen to any ip on port 80 for http
IPEndPoint ipEndPointHttp = new IPEndPoint(IPAddress.Any, 80),
// listen to any ip on port 443 for https
ipEndPointHttps = new IPEndPoint(IPAddress.Any, 443);
builder.WebHost.UseUrls($"http://{ipEndPointHttp}",
$"https://{ipEndPointHttps}");
// enforce ssl when in release
builder.Services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(3); // a commonly used value is one year.
});
// redirect to specific https port
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = (int)HttpStatusCode.PermanentRedirect;
options.HttpsPort = ipEndPointHttps.Port;
});
}
else // app in debug
{
// listen to localhost on port 8081 for http
IPEndPoint ipEndPointHttp = new IPEndPoint(IPAddress.Loopback, 8081),
// listen to localhost on port 5001 for https
ipEndPointHttps = new IPEndPoint(IPAddress.Loopback, 5001);
builder.WebHost.UseUrls($"http://{ipEndPointHttp}",
$"https://{ipEndPointHttps}");
// redirect to specific https port
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = (int)HttpStatusCode.TemporaryRedirect;
options.HttpsPort = ipEndPointHttps.Port;
});
}
... // rest of configuration
app.UseHttpsRedirection(); // set redirection to https if url is in http
....
Also note that using these values new IPEndPoint(IPAddress.Any, 80), *:80, ::80 are all equivalent, but I prefer IPEndPoint since it is more verbose
If a custom ip address (ex: 192.168.1.200) is needed other than IPAddress.Any or IPAddress.Loopback, a new address can be set using IPAddress.Parse("192.168.1.200")

User.IsInRole is always false when using IIS Express / Kestrel in ASP.Net 5 with Windows Authentication

I have an ASP.Net 5 application using version 1.0.0-rc1-update1 with Windows Authentication. I've implemented a custom policy in my Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
// ... other configuration code
var viewCharts = new AuthorizationPolicyBuilder()
.AddRequirements(new ViewChartsRequirement())
.Build();
collection.AddAuthorization(opts =>
{
opts.AddPolicy(Policy.ViewCharts, viewCharts);
});
collection.AddTransient<IAuthorizationHandler, ViewChartsHandler>();
// ... other configuration code
}
The ViewChartsHandler's Handle method is as follows:
protected override void Handle(
AuthorizationContext context,
T requirement)
{
var identities = _securityRepo.GetIdentitiesForPolicy(_policy);
// this returns a result when using a web listener, but
// never finds a match when using IIS Express
var matchingIdentity = identities.FirstOrDefault(role => context.User.IsInRole(role));
if (!string.IsNullOrWhiteSpace(matchingIdentity))
{
context.Succeed(requirement);
}
}
When using a web listener as shown in this answer, the code above works. However, when using IIS Express it never finds a matchingIdentity.
Things to note:
My IIS Express is configured to use Windows Authentication, and deny Anonymous Authentication. The bug related to IIS Express and this was fixed in RC1.
The username from Windows is always resolving correctly.
In the Handle code above, context.User is an instance of System.Security.Principal.WindowsPrincipal when using a web listener, but when using IIS Express it is a System.Security.Claims.ClaimsPrincipal.
I have forwardWindowsAuthToken="true" set in my web.config.
I think this is a role provider problem, but I am at a loss as to how to correct it.
I'm using the following code to successfully check for role membership on RC1, however note that it does not resolve group names (probably due to the problems referred to by #blowdart), I have to supply the group names as SIDs:
// Set up authorisation policies from the configured AD group lists.
// NOTE: Currently this only works with SIDs if hosting using Kestrel
// behind IIS, not friendly group names.
var viewerGroups = Configuration.GetSection("Groups:Viewer").Value.Split(',');
var adminGroups = Configuration.GetSection("Groups:Admin").Value.Split(',');
services.AddAuthorization(auth =>
{
auth.AddPolicy("viewer", policy =>
{
policy.RequireRole(viewerGroups);
});
auth.AddPolicy("admin", policy =>
{
policy.RequireRole(adminGroups);
});
});
I don't know if this will help you, but I thought I'd offer it up in case!
Did you add the IISPlatformHandler middleware?
app.UseIISPlatformHandler();
This needs to be ran before app.UseMvc(), app.UseStaticFiles() or any other authentication middleware.
It turns out that User.IsInRole does not function correctly in RC1. (See #blowdart's comments.) This will be fixed in RC2.
The original code will work so long as the line below returns the SIDs for each AD group, as opposed to the friendly names.
// This line must return SIDs instead of friendly names
var identities = _securityRepo.GetIdentitiesForPolicy(_policy);
Update
This was fixed in RC2. The original code works!

Categories