How to use HTTP/2 from a React website for communication? - c#

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.

Related

.net 6 use http on localhost api

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"
}
}

How to Implement HSTS header in ASP.Net Core 6.0?

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.

.Net 6 Ocelot 18.0.0 returns Error 404 when navigating to an URL of the gateway

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.

how can I Integrate Asp.Net Core WebApi With React.js?

I Have a Project With Asp.net Core WebApi and React.js that BackEnd and FrontEnd of it are Running StandAlone Fine When I Publish On IIS Server(frontEnd Use Internet for call BackEnd Apis)
But I Wanna Use Asp.NetCore With ReactApp Template In VisualStadio To Integrate Those
And FrontEnd Call Apis On LocalHost with Same Application.
VS template
I Have Some Problem With Call WebApis with ClientApp(FrontEnd) Locally.
How Can I Solve That ClientApp Call WebApis Locally?
that is my JSCode that handel Connecting with WebApis :
import axios from "axios"
import { BaseUrl } from "../utils/baseUrl"
const useRequest = ({ url, method, body }) => {
const doReq = async () => {
const token = localStorage.getItem("accessToken")
const res =await axios(`${BaseUrl}/${url}`, {
method: method,
headers: {
"Content-Type": "application/json" ,
"accept": "*/*",
'Authorization':`Bearer ${token}`
},
data : body
})
return res
}
return doReq
}
export default useRequest;
And Base Url :
export const BaseUrl = "http://localhost:44789"
My LunchSetting in BackEnd :
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:44789",
"sslPort": 44367
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Project2": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
you dont need baseUrl in js file as above ,
url is enough, and url must be your endPoint route you declared in startup.cs + Http function name you want to access.
Here is sample https://github.com/unpub777/PersonalPortal (I use this as template.)
I think you may to adjust something in your existing code following attached repo.

How should I resolve the following error message? (111)Connection refused: AH00957: HTTPS: attempt to connect to 127.0.0.1:5001 (127.0.0.1) failed

As mentioned I am receiving the following error message in my apache logs.
[Sat Jun 22 12:57:53.746190 2019] [proxy:error] [pid 10299:tid 140435221571328] (111)Connection refused: AH00957: HTTPS: attempt to connect to 127.0.0.1:5001 (127.0.0.1) failed
[Sat Jun 22 12:57:53.746228 2019] [proxy:error] [pid 10299:tid 140435221571328] AH00959: ap_proxy_connect_backend disabling worker for (127.0.0.1) for 60s
[Sat Jun 22 12:57:53.746233 2019] [proxy_http:error] [pid 10299:tid 140435221571328] [client myip:65168] AH01114: HTTP: failed to make connection to backend: 127.0.0.1
When deploying with code-pipline I see no error messages.
I have tried all of the following;
Restarting and rebuilding my application.
Adjusting the launchSettings.json file in my ASP project.
Adjusting the ports and enabling / disabling HTTPS redirect in my Program class.
Adjusting my vhsosts file in apache.
Here are some important files for you to browse;
launchSettings.json
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "https://localhost:44335",
"sslPort": 44335
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_My_Environment": "1",
"ASPNETCORE_DETAILEDERRORS": "1",
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"ProjectName": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
}
}
}
/etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:80>
ProxyPreserveHost On
ProxyPass "/" "http://127.0.0.1:5000/"
ProxyPassReverse "/" "http://127.0.0.1:5000/"
</VirtualHost>
/etc/apache2/sites-enabled/000-default-le-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
SSLEngine on
SSLProxyEngine on
ProxyPreserveHost On
ProxyPass "/" "https://127.0.0.1:5001/"
ProxyPassReverse "/" "https://127.0.0.1:5001/"
ServerName mydomain.com
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/mydomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mydomain.com/privkey.pem
</VirtualHost>
</IfModule>
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
var logger = _loggerFactory.CreateLogger<Startup>();
logger.LogInformation($"Environment: {_env.EnvironmentName}");
// Development service configuration
if (_env.IsDevelopment())
{
logger.LogInformation("Development environment");
services.Configure<ForwardedHeadersOptions>(options =>
{
options.KnownProxies.Add(IPAddress.Parse("127.0.0.1"));
});
services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
options.HttpsPort = 44335;
});
}
// Live Service Config
if (!_env.IsDevelopment())
{
services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
options.HttpsPort = 5001;
});
services.Configure<ForwardedHeadersOptions>(options =>
{
options.KnownProxies.Add(IPAddress.Parse("127.0.0.1"));
});
services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(60);
});
}
//lines removed for berevity.
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Dev Envoronments
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseHttpsRedirection();
}
if (env.IsProduction())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
}
app.UseHttpsRedirection();
//lines removed for berevity.
}
If you need any more information please let me know.
EDIT: Server: EC2 Ubuntu (Build via Code Star), Web service: Apache, Project Code: asp.net core 2.1, SSL Certificates: LetsEncrypt, Proxy: Not 100% sure.
Try the following code that enables HTTPD scripts and modules to connect to the network.
/usr/sbin/setsebool -P httpd_can_network_connect 1

Categories