I'm trying to run my webapi under http on localhost so in the program.cs, I have
if (!app.Environment.IsDevelopment())
{
app.UseHttpsRedirection();
}
else
{
app.UseSwagger();
app.UseSwaggerUI();
}
but when I run the api, it still redirects to https and if I try to use http it says localhost cannot load any data. I'm also definitely in development as the swagger ui is displayed.
Is there something else I need to do to run the api under http?
Appsettings:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"DbConnection": "From user secrets"
},
"AllowedHosts": "*"
}
Add the listening end points in manually.
.UseKestrel(options =>
{
// HTTP 8088
options.ListenLocalhost(8088);
}
also, .UseUrls("http://*:8088") may work
Turns out it was my launchSettings.json:
"API": {
"commandName": "Project",
"dotnetRunMessages": false,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:7188", <-- this line was set to https, changing it to http fixed the issue
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
Related
In older versions of ASP.Net core you had the startup.cs file where you would do a lot of the work including reading and setting the application environment then based on that you could read different version of the appsettings.json file. In the new ASP.Net Core 7 they got rid of Startup.cs and greatly streamlined the program.cs files. Now I can't figure out how to read the environment and then pass Entity Framework 7 my connection string. Looking around all the answers I find don't apply to version 7 or tell you to undo all the work in 7 by remaking the entire Startup.cs file. How are we supposed to inject the connection string based off the environment in .Net 7?
I do have the code to read from the base appsettings.json file and that works, there is also a section to read the environment but it get setup AFTER the DbContext injection. Here is my program.cs file and I am just lost on what needs to be updated. I looked at the microsoft docs but did not see anything applying to environements and injection of the string.
var builder = WebApplication.CreateBuilder(args);
//Add Services (builder.Services.AddScoped<IService, Service>();
builder.Services.AddScoped<INavigationHelper, NavigationHelper>();
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
builder.Services.AddRazorPages().AddMicrosoftIdentityUI();
builder.Services.AddDbContext<SiteDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("Database")));
var app = builder.Build();
if (!app.Environment.IsDevelopment()) { app.UseHsts(); }
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.Run();
appsettings.json:
{
"AzureAd":
{
"Instance": "https://login.microsoftonline.com/",
"Domain": "",
"TenantId": "",
"ClientId": "",
"CallbackPath": "",
"ClientSecret": "Client secret from app-registration. Check user secrets/azure portal.",
"ClientCertificates":
[
]
},
"Logging":
{
"LogLevel":
{
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings":
{
"Database": ""
}
}
appsettings.development.json
{
"Logging":
{
"LogLevel":
{
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
},
"ConnectionStrings":
{
"Database": ""
}
}
}
builder.Configuration.GetConnectionString("Database")
will use the appropriate appsettings.json file based on the chosen environment. If you look in Properties folder in your project and examine the launchsettings.json file you should see something like this:
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:30787",
"sslPort": 44345
}
},
"profiles": {
"Cosmos.Application.Server": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:7138;http://localhost:5138",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
In the above, this means that the ASPNETCORE_ENVIRONMENT is set to Development and this will determine which appsettings file is used in your program.cs when calling:
builder.Configuration ...
We can read configs from environments like below. Keys within latest added file will get the priority when reading the values.
For example if "Default" connection string was present in both appsettings.json and appsettings.Development.json, then the value in latter file will be the resulting value.
using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
.Build();
var defaultConnectionString = config.GetConnectionString("Default");
Console.WriteLine($"Default ConnectionString: {defaultConnectionString}");
In order to educate myself about web technologies, I am building a small project with the following setup:
An ASP.NET 6 server that provides gRPC services and a REST API
A .NET 6 WPF client application as Desktop gRPC client
A .NET 6 MAUI app as Mobile gRPC client
A React website that "talks" to the server with REST
I have had experience with gRPC, backend development and Desktop clients, so creating a simple server and the WPF client was no problem. Creating a simple .NET MAUI app was something new, but I managed to get it running. So these three applications talk to each other using gRPC and it works smoothly.
As for the React website, I first used an ASP.NET WebAPI sample project from a tutorial website and it worked fine. However, I wanted to integrate the REST API into my existing server that so far only provided gRPC services. My issue is, that I can't make them (server and React website) talk.
My server
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
}
}
launchSettings.json
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:18460",
"sslPort": 44326
}
},
"profiles": {
"Gather.Server": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:7081;http://localhost:5081",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": false,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Program.cs
public static IHostBuilder CreateHostBuilder(string[] args)
{
// This retrieves the proper IP address and port numbers that are used below.
var configuration = ServiceFactory.Instance.GetConfiguration();
return Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(options =>
{
// http://192.168.1.20:5000
options.Listen(configuration.IPAddress, configuration.HttpPort);
// https://192.168.1.20:5005
options.Listen(configuration.IPAddress, configuration.HttpsPort, configure => configure.UseHttps());
});
webBuilder.UseStartup<Startup>();
});
}
Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc(options =>
{
options.MaxReceiveMessageSize = 16 * 1024 * 1024;
options.MaxSendMessageSize = 16 * 1024 * 1024;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<AuthenticationService>();
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
endpoints.MapGet("/weatherforecast", () =>
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast(DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)]))
.ToArray();
});
});
}
}
My Program.cs is pretty simple, I only set the URLs for HTTP and HTTPS. In my Setup.cs, I set the message sizes, add my gRPC service used by the Desktop and Mobile clients and I added the sample REST GET from the tutorial I used for self-education.
My React client
I basically have an un-edited project that you get when you add a new "Standalone JavaScript React Project" in Visual Studio 2022. The only thing I have changed is the URL in the setupProxy.js which looks as follows.
setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
const context = [
"/weatherforecast",
];
module.exports = function (app) {
const appProxy = createProxyMiddleware(context, {
target: 'https://192.168.1.20:5005',
secure: false,
changeOrigin: true,
logLevel: 'debug'
});
app.use(appProxy);
};
Error when using HTTPS
When I use the code as above, I see the following errors when starting my React website.
Error when using HTTP
When I change the URL in setupProxy.js to my HTTP address (http://192.168.1.20:5000), I don't get an error in my server console output, but I get an error in my Node console from the website.
I am very new to React / Node / REST and my problem might be trivial for you, but any help is greatly appreciated. I think that once I have my basic setting going, I can learn more about these topics step by step.
I found the solution. The configuration of my React app was totally fine, but the issue was on my ASP.NET side. Because I use gRPC, my HTTPS connection was HTTP/2 only, but the incoming GET request from my React app was using HTTP 1. When I configured my endpoints to HTTP1 and 2, but gRPC and REST API work.
I need to implement the HSTS header security in the ASP.Net Core 6.0 WEB API application.
Below is my Program.cs
var builder = WebApplication.CreateBuilder(args);
...
// Https redirection
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = (int)HttpStatusCode.TemporaryRedirect;
options.HttpsPort = 7075;
});
// HSTS Security Headers
builder.Services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(365);
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseCustomExceptionHandler();
app.MapControllers();
app.Run();
and below is the launchSettings.json
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:17240",
"sslPort": 0
}
},
"profiles": {
"EFCoreRelationshipsTutorial": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5075;https://localhost:7075",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
The application launches on the URL - http://localhost:5075/swagger/index.html however, I was expecting it to be redirected to https://localhost:7075/swagger/index.html automatically.
Also, I was expecting the Strict Transport Security Header in the response like
however, it is not present in the response header.
What am I missing? How do I implement the HSTS in asp.net core 6.0?
.AddHsts() excludes localhost which is why you're not seeing it working on your dev machine; and why it is only recommended to be used in production.
From the asp.net docs HTTP Strict Transport Security Protocol (HSTS):
UseHsts isn't recommended in development because the HSTS settings are
highly cacheable by browsers. By default, UseHsts excludes the local
loopback address.
For production environments that are implementing HTTPS for the first
time, set the initial HstsOptions.MaxAge to a small value using one of
the TimeSpan methods. Set the value from hours to no more than a
single day in case you need to revert the HTTPS infrastructure to
HTTP. After you're confident in the sustainability of the HTTPS
configuration, increase the HSTS max-age value; a commonly used value
is one year.
And then a snippet of code:
using System.Net;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(60);
options.ExcludedHosts.Add("example.com");
options.ExcludedHosts.Add("www.example.com");
});
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = (int)HttpStatusCode.TemporaryRedirect;
options.HttpsPort = 5001;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
The rest of the article explains the configuration options and behavior in more detail.
Edit: Testing UseHsts Locally
Just did a bit of experimenting and was able to get the Strict-Transport-Security header added to a Postman request by creating an entry in my Windows host file and updating my launchSettings.json.
Edit your hosts file; example on SuperUser.
File: C:\Windows\System32\drivers\etc\hosts
Add something along the lines of:
127.0.0.1 myweb.local
Save the file (you may need to open your editor in admin mode). And with the settings you posted, modify the host names from local host to the site name defined in the hosts file, i.e., myweb.local
"profiles": {
"EFCoreRelationshipsTutorial": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://myweb.local:5075;https://myweb.local:7075",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
Granted, my environment only has https enabled, but the header was present after creating the entry in the hosts file and updating my launch settings to use the host name I mapped back to 127.0.0.1.
I have two API's. One of them is a Gateway (Ocelot + .Net 6) and the other one is a normal .Net 6 API, which I'm gonna call Backoffice. On both of them I have a controller with and endpoint 'api/health' that indicates if the API is running and describes the environment. When I call the endpoints of each API, both API's are working.
The endpoints are:
http://localhost:5039/api/health
http://localhost:5105/api/health
However, when I call the Gateway endpoint that points to the Backoffice API, it returns an 404.
The Gatewayt that redirects to the Backoffice API is:
http://localhost:5039/backoffice/api/health
But it returns 404. I can't really understand why. I have the ocelot.json configured and added in the Program.cs file.
And even worse, I can't seem to find any documentation on .Net 6 implementation. .Net 6 now has only a Program.cs and doesn't have a Startup.cs so it confuses a little bit and can't seem to find an example online.
ocelot.Development.json
{
"Routes": [
//Backoffice API
{
"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5105
}
],
"UpstreamPathTemplate": "/backoffice/{everything}",
"UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ],
"Key": "user-transactions"
}
],
"GlobalConfiguration": {
"RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration",
"BaseUrl": "http://localhost:5039"
}
}
launchSettings.json
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:5039",
"sslPort": 0
}
},
"profiles": {
"Dimatur.APIGateway": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5039",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5039",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Program.cs
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
// Add services to the container.
builder.Services.AddControllers();
IConfiguration configuration = builder.Configuration.AddJsonFile($"ocelot.{env}.json", true, true).Build();
builder.Services.AddOcelot(configuration);
// 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.UseAuthorization();
app.MapControllers();
app.Run();
app.UseOcelot().Wait();
I tried to edit the launchSettings.json on both API's, but never managed to succeed. Also, tried to use version 17.0.0 but it didn't work either (I'm using 18.0.0).
I have added:
IConfiguration configuration = builder.Configuration.AddJsonFile($"ocelot.{env}.json", true, true).Build();
builder.Services.AddOcelot(configuration);
And at the end of the file:
app.UseOcelot().Wait();
What I'm expecting is, when I call http://localhost:5039/backoffice/api/health, it should return a JSON. The same one the returns in http://localhost:5105/api/health. But I can't seem to debug what's happening and don't know what to do anymore. When I call the API's directly, everything is working.
put the app.UseOcelot().Wait(); just above the app.UseAuthorization(); and try.
I am trying to run the ASP.NET Core angular template on a kestrel server. It works flawlessly on ASP.NET, but when I change in the launchsettings in Visual Studio from IIS Express to my project name, it opens a command window where I can see the log and everything, but the browser returns a 404 error. This is what my launchsettings look like:
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:59994/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Sankini": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Production": {
"commandName": "IISExpress"
}
}
}
What can I do to make sure it works?
You will want the IISExpress server to serve your Angular App.
The NameOfEnvironmentWhenAppRuns is the name you assign the run button. Like so.
So to answer your question the following will work.
"Sankini": {
"commandName": "IISExpress",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}