SignalR Core not using Websockets in Azure App Service - c#

I'm working on a SignalR Core web app that uses the following stack:
ASP.NET Core 2.1 preview 2 (2.1.0-preview2-final)
SignalR Core 1.0 preview 2 (1.0.0-preview2-final)
Microsoft.AspNetCore.Cors (2.1.0-preview2-final)
Microsoft.AspNetCore.WebSockets (2.1.0-preview2-final)
The client is using SignalR NPM package (#aspnet/signalr).
The app is configured like so:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(
"CorsPolicy",
builder => builder
.AllowCredentials()
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
services.AddSignalR();
}
public void Configure(IApplicationBuilder app)
{
app.UseCors("CorsPolicy");
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseWebSockets();
app.UseSignalR(routes =>
{
routes.MapHub<ClientHub>("/hubs/notifications");
});
}
When running locally in http://localhost, the client connects using WS protocol. But when deployed in Azure App Service, it falls back to SSE.
The browser log shows:
WebSocket connection to 'wss://xxxxxx.azurewebsites.net/hubs/notifications?id=ZRniWKpMLMPIyLhS5RSyAg' failed: Error during WebSocket handshake: Unexpected response code: 503
Information: SSE connected to https://xxxxxx.azurewebsites.net/hubs/notifications?id=ig47oOdQzbasdgrlr0cHaw
The negotiate method seems to return support to Websockets:
{"connectionId":"ZRniWKpMLMPIyLhS5RSyAg",
"availableTransports":[
{"transport":"WebSockets","transferFormats":["Text","Binary"]},
{"transport":"ServerSentEvents","transferFormats":["Text"]},
{"transport":"LongPolling","transferFormats":["Text","Binary"]}]
}
Am I missing something? Or is WSS not yet supported?

To answer my own question, the failure in the Websocket connection was not a problem with ASP.NET Core or the stack, but due to the fact that Azure App Service needs to have Websockets enabled in the Application Settings:

2022 answer.
To enable Web Sockets on a modern console go to Home -> App Services -> your_app_name -> (Settings) Configuration -> General Settings and set Web sockets property to On.

Related

CefSharp CORS error on request to localhost: request client is not a secure context and the resource is in more-private address space local

I am building a web app with the following architecture:
remote server
CefSharp to render pages coming from the remote server
local server to communicate the app with a serial port
But when I make requests from the client to the local server I get some CORS errors
Access to fetch at 'http://localhost:3100/connection' from origin
'http://cloud.tissuelabs.com' has been blocked by CORS policy: The
request client is not a secure context and the resource is in
more-private address space local
so I added headers to the local server response
{
Access-Control-Allow-Origin: *,
Access-Control-Allow-Private-Network: true
}
it was working on firefox, but not on chrome nor on cefsharp. Then, I found this answer on stackoverflow (Chrome CORS error on request to localhost dev server from remote site) that suggested to disable chrome`s flag
chrome://flags/#block-insecure-private-network-requests
it worked on chrome, but I don`t know how to disable this flag on cefsharp. Does anyone know how to disable flags on cefsharp or any other workaround?
I disabled "BlockInsecurePrivateNetworkRequests" feature as suggested by #amaitland and it worked.
CefSettings settings = new CefSettings();
settings.CefCommandLineArgs.Add("disable-features", "BlockInsecurePrivateNetworkRequests");
CefSharp.Cef.Initialize(settings);
add to Startup.cs
public void ConfigureServices(IServiceCollection services)
{ services.AddControllersWithViews();
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
}
add in public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseCors(builder => builder.AllowAnyOrigin());
add to Controller.cs file
[EnableCors("MyPolicy")]

Windows authentication for SignalR service hosted in Kestrel (AspNet Core 5.0)

I have a SignalR (AspNet Core 5.0) hosted in a console app using Kestrel as the web host.
I want to access the user Identity of any request in a Hub implementation, when accessing the following the Identity values are NULL.
I've looked at the available documentation on MSDN and made the following changes, but not getting the Identity populated as I expected, also not finding any examples for AspNet Core 5.0 anywhere.
Any ideas what I am doing wrong?
public class ExampleHub : Hub
{
public Task Foo()
{
*// why is name NULL?*
var name = Context.User.Identity.Name;
return Task.Completed;
}
}
I have added the following line when configuring the services as StartUp:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNeogtiate();
services.AddSignalR(options => options.EnableDetailedErrors = true);
...
}
public void Configure(IApplicationBuuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints => endpoints.MapHub<ExampleHub>("/Example"); });
}
Managed to get this working by changing to HttpSys instead of Kestrel as the host. The Context.User.Identity is now populated as WindowsIdentity.
In this case using HttpSys is preferred - an internal (corporate) network hosted in a Windows Service instead of a web server (IIS). Note IIS also uses HttpSys internally.

How to integrate Prometheus with .NET Core application?

I am trying to integrate Prometheus for my C# .NET Core Console application. I am not developing an ASP.NET Core application. How do I send the metrics data to prometheus the way we usually do for ASP.NET Core application?
In ASP.NET Core application,
Open Startup.cs and update ConfigureServices and Configure to look something along the lines of:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<MetricReporter>();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Other middleware components omitted for brevity
// Make sure these calls are made before the call to UseEndPoints.
app.UseMetricServer();
app.UseMiddleware<ResponseMetricMiddleware>();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
How can I do this for a .NET Core console application?
You can use the Prometheus-net package which provides some useful features for integrating .Net and Prometheus.
Due to documentation you could start a kestrel-stand-alone server for console apps that do not have any accessible http endpoints.
in order to that ,you must have the .Web at the end of the Sdk attribute value in the project file.
after that you need to start the kestrel:
var metricServer = new KestrelMetricServer(port: 1234);
metricServer.Start();
Another way is to simply use the standalone Http-handlers as follows:
var metricServer = new MetricServer(port: 1234);
metricServer.Start();
The default configuration will publish metrics on the /metrics URL.
MetricServer.Start() may throw an access denied exception on Windows if your user does not have the right to open a web server on the specified port. You can use the netsh command to grant yourself the required permissions:
netsh http add urlacl url=http://+:1234/metrics user=DOMAIN\user

Angular app running localhost calling dotnet app on different port gets no-referrer-when-downgrade. Due to withCredentials?

I setup a new Angular app with Angular CLI and it runs on http://localhost:4200
I call webservices that I develop with dotnet core which runs on http://localhost:5000
I allowed CORS for the localhost setup. I am sure it worked in the past but now I get a
no-referrer-when-downgrade
error message in chrome.
It somehow has to do with withCredentials: true
If I put false then it works fine.
How can I pass credentials on http calls to a different port on the same localhost domain?
You might try to upgrade your .NET Core application to HTTPS.
The no-referrer-when-downgrade message indicates that the default referrer policy is in place as described here.
no-referrer-when-downgrade (default)
This is the default behavior if no policy is specified, or if the
provided value is invalid. The origin, path, and querystring of the
URL are sent as a referrer when the protocol security level stays the
same (HTTP→HTTP, HTTPS→HTTPS) or improves (HTTP→HTTPS), but isn't sent
to less secure destinations (HTTPS→HTTP).
Just for a test you might try to set the referrer policy for development environment to a different value (this code uses NWebsec.AspNetCore.Middleware):
if (env.IsDevelopment())
{
app.UseReferrerPolicy(opts => opts.UnsafeUrl());
}
It turned out it was no no-referrer-when-downgrade issue but a CORS issue.
I was missing the AllowCredentials() in the CORS policy
public void ConfigureServices(IServiceCollection services)
{
// add cors
services.AddCors(options =>
{
options.AddPolicy(name: "MyCorsPolicy",
builder => builder.SetIsOriginAllowed(s => s.Contains("localhost"))
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
}

ASP.NET Core AWS Serverless and CORS

I'm using Visual Studio to publish an ASP.NET Core 2.1 app to AWS Lambda (serverless). No matter what I've tried I cannot get CORS to work.
All I really want to do is add the header access-control-allow-origin globally to my web app.
Has anyone ever successfully added headers to an ASP.NET Core 2.1 Serverless app?
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// AddCors must be before AddMvc
services.AddCors();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// UseCors must be before UseMvc
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
// Also tried this
// app.UseCors(
// o => o.WithOrigins("http://example.com").AllowAnyMethod()
//);
app.UseMvc();
}
No CORS headers are added to my pages. I'm using Chrome dev tools to inspect my headers. I should see them on the homepage (for example) correct?
Any ideas? I'm dyin over here. Thanks!
EDIT
This application only uses API Gateway, Lambda and a few other services. It's great because I'm only charged when someone hits my app. There are no hourly charges. No EC2 or ELB which is amazing.
Also, I almost added this to my original post. The article #sturcotte06 references has a gotcha.
The API Gateway (automatically generated) uses the ANY method in a proxy integration. The above article says this...
Important
When applying the above instructions to the ANY method in a proxy integration, any applicable CORS headers will not be set. Instead, your backend must return the applicable CORS headers, such as Access-Control-Allow-Origin.
Ugh! So it's saying I must do this on the backend (Startup.cs right?) which is exactly what seems to get ignored when published.
For whatever reason app.UseCors does not work in my scenario. However, app.Use does...
app.Use((context, next) =>
{
context.Response.Headers["Access-Control-Allow-Origin"] = "https://example.com";
return next.Invoke();
});
app.UseMvc();

Categories