How to integrate Prometheus with .NET Core application? - c#

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

Related

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 implement an signalr CLIENT in c# System.Web.Http.ApiController

We have an application running different services (c#, .NET Core) LOCAL on a Windows PC.
I now need some kind of mechanism to inform all interested services if data changed in one service (some kind of observer pattern for microservices, or some kind of MQTT (pub/sub) mechanism of c# and .NET Core microservices locally running on a windows pc).
First I want to use Sockets but the Windows documentation says use Signalr instead.
So here is what I have so far:
public class Startup
{
public Startup()
{
// empty
}
public void ConfigureServices(IServiceCollection services)
{
// Add services.
//Test bidirectional communication (pub / sub Pattern over SignalR groups)
services.AddSignalR();
// Add the localization services to the services container.
services.AddLocalization(options => options.ResourcesPath = "Properties");
services.AddMvc()
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
// Use sessions
// The order of middleware is important.
// An InvalidOperationException exception will occur when UseSession is invoked after UseMvc.
app.UseSession();
//Test bidirectional communication (pub / sub Pattern over SignalR groups)
//The SignalR Hubs API enables you to call methods on connected clients from the server.
//In the server code, you define methods that are called by client. In the client code, you define methods that are called from the server.
app.UseSignalR(routes =>
{
routes.MapHub<SignalRHub>("/SignalRHub");
});
app.UseMvc(
routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
For the .NET CORE Service
But I now need a client for the c# System.Web.Http.ApiController and can not find an example.
Seems some are confused by our "beautiful" architecture ;-)
I hope the following picture makes it clearer:
So, if Application 1 changes data in Microservice 2, than Application 2 has to be informed.
And again, this is all running local on a Windows PC, no clouds are involved.
Probably missing something from your description.
SignalR is fine if there are clients to report relevant information to.
In your scenario, however, it would seem that the clients are the APIs themselves and this makes little sense to me.
Maybe there's a piece missing in the middle that does the work you're saying.
In any case, you may find relevant technical information about SignalR starting from the official website.
https://learn.microsoft.com/en-us/aspnet/core/signalr/dotnet-client?view=aspnetcore-3.1&tabs=visual-studio

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();

Can't get JWT based security in .NET Core 3.0 working

According to MSDN, I'm supposed to be able to use the following.
services.AddAuthentication()
.AddIdentityServerJwt();
This doesn't work because AddIdentityServerJwt seem not to be there. Also, I'm not sure if I want to go hand in hand with IdentityServer at this moment at all.
I haven't found any tutorials or blogs discussing security for an SPA based on backend in .NET Core 3.0 that wouldn't be a direct referrer to the link above (hence relying in the Identity Server). Probably because it such a cutting edge tech at the moment. The migration manual from 2.2 to 3.0 is not exhausting and I also suspect that it might be inaccurate.
In previous version, I'd declare a default scheme and configure the token validation in the Startup.cs file. However, now, it seems like all the cheese has been moved around in Core 3.
How should I configure the (simplest possible) security using JWT and (most preferably) avoiding Identity Server?
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
//app.UseRouting();
app.UseAuthentication();
//app.UseAuthorization();
//app.UseEndpoints(e => e.MapControllers());
}
This produces different variations of the following error in Swagger.
No authenticationScheme was specified, and there was no DefaultChallengeScheme found.
The missing part is that right after calling AddAuthentication, you also need to explicitly "optin" into JWT bearer:
public void ConfigureServices(IServiceCollection services)
{
...
services
.AddAuthentication()
.AddJwtBearer();
}
At the moment, that operation requires a manual installation of the extension methods as shown [here](Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 3.0.0-preview6.19307.2).
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 3.0.0-preview6.19307.2
The documentation for Core 3.0 covering the method, redirects at the moment to its counterpart for Core 2.2 and may be updated or removed at any time, due to the preview state.

SignalR Core not using Websockets in Azure App Service

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.

Categories