asp.net core: IApplicationLifetime.ApplicationStopping isn't triggered - c#

I saw a few articles about IApplicationLifetime and the way I can trigger execution when application starts and stops but I probably miss something because it is just not triggered.
Here is my workaround:
I opened a project template Container Application for kubernetes, asp.net core 2.2
Program.cs looks as it was created:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Kubernetes1
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}
Startup.cs looks as following:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Kubernetes1
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
appLifetime.ApplicationStopping.Register(() => Console.WriteLine("ApplicationStopping called"));
appLifetime.ApplicationStopped.Register(() => Console.WriteLine("ApplicationStopped called"));
app.Run(async (context) =>
{
Console.WriteLine("AAA");
});
}
}
}
All I wanted to do here is running the app in cmd, then stop it and see 2 lines printed in console:
ApplicationStopping called
ApplicationStopped called
I didn't manage to make it happen.
Any ideas?

in a different cmd window I type: Get-Process -Name *dotnet* | Stop-Process
Stop-Process will kill the process, skipping any graceful shutdown behavior an application might have.
When the IApplicationLifetime talks about the application stopping, then it refers to the application being gracefully shut down. There are a few ways to trigger this, depending on how the application is starting:
When the application is running in the console: CTRL + C. For example when running through dotnet run or running the compiled executable directly.
When the application is running in IIS: Stopping the website or the application pool.
When the application is running as a Windows Service: Stopping the service.

Related

'WebHost' is inaccessible due to its protection level

I am trying to follow Microsoft's Ocelot API Gateway tutorial (https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/implement-api-gateways-with-ocelot).
First I intialized a new empty ASP.NET Core web app:
dotnet new web
Then I installed the Ocelot dependencies (https://www.nuget.org/packages/Ocelot/):
dotnet add package Ocelot --version 17.0.0
Then I took the code from the tutorial:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using System.IO;
namespace MyApp
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
var builder = WebHost.CreateDefaultBuilder(args);
builder.ConfigureServices(s => s.AddSingleton(builder))
.ConfigureAppConfiguration(
ic => ic.AddJsonFile(Path.Combine("configuration",
"configuration.json")))
.UseStartup<Startup>();
var host = builder.Build();
return host;
}
}
}
But then it complains that the WebHost class, called in BuildWebHost method, "is inaccessible due to its protection level". According to Microsoft (https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.webhost), WebHost "provides convenience methods for creating instances of IWebHost and IWebHostBuilder with pre-configured defaults.", and looks like so:
public static class WebHost
...
Why does it complain that WebHost is inaccessible, when the class is in fact public? What am I missing here?
From the documentation, WebHost is in the namespace Microsoft.AspNetCore. But in your code, It hasn't the using to this namespace.
In Visual Studio, you can try Go to definition on WebHost to discover where the type come.
As sujested by #leiflundgren, as your code has the using Microsoft.AspNetCore.Hosting, then the compiler thinks you want use Microsoft.AspNetCore.Hosting.WebHost.
https://github.com/dotnet/aspnetcore/blob/main/src/Hosting/Hosting/src/Internal/WebHost.cs
namespace Microsoft.AspNetCore.Hosting;
internal sealed partial class WebHost : IWebHost, IAsyncDisposable
{
....
}
But this class has the scope internal, then it isn't exposed and can be used by your code. Hence the following error :
WebHost is inaccessible due to its protection level.

Localhost Page Cannot be Found

I am running Visual Studio 2019 which uses IIS Express for Web applications. It was running fine up till suddenly a website I was working on (ASP.NET Core) crashed and gave an error. I went and fixed the error and now all I get is https://localhost:44314 can not be reached (see image 1 below). I have all the routing in the code and even reverted my code to the last working version with still no luck. I have even reinstalled Visual Studio and iisexperess. You can see my startup code below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Website
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}

Authorize signalr core hub using identiyserver4

I am using visual studio 2019 preview Angular / .net core API backend template with individual authorization.
I believe within this template, identityserver4 is being used.
Within the API there is a signalr core hub which I am trying to authorize. I have the Authorize attribute on the hub. I am also specifying the token in the angular signalr client URL query string.
Despite the above, the authorize attribute has no effect, I am able to access the hub with or without the token.
JS / angular client
ngOnInit() {
console.log(this.authService.getAccessToken().toPromise())
this._hubConnection = new signalR.HubConnectionBuilder()
//.withUrl('/handoverhub', {accessTokenFactory: () => this.token})
.withUrl('/handoverhub', { accessTokenFactory: () => {
return this.authService.getAccessToken().toPromise();
} })
.configureLogging(signalR.LogLevel.Information)
.build();
ASPNETCore code
Hub using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using HomecareShared.Models;
using HomecareShared.Models.DTOs;
using HomecareShared.Models.Handover;
using HomecareShared.Models.Notify;
using HomecareShared.Models.SharedResources;
using HomecareHandover.Repo;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.VisualBasic.ApplicationServices;
namespace HomecareHandover.Hubs {
[Authorize]
public class HandoverHub : Hub
Some snippets of startup
app.UseAuthentication();
app.UseAuthorization();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<HandoverHub>("/handoverhub"); //For handover
endpoints.MapHub<TaskHub>("/taskhub"); //For task
});
app.UseIdentityServer();
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddSignalR();
No error messages. I am able to get straight into the hub no problem.
I have had a similar problem but with AzureSignalR. I overcome the issue by implementing the code below. You also should call UseIdentityServer before UseEndpoints;
app.UseAuthentication();
app.UseAuthorization();
app.UseAzureSignalR(routes =>
{
routes.MapHub<ChatHub>("/hubs/chat");
routes.MapHub<NotificationHub>("/hubs/notifications");
});
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapHealthChecks("/healthz", new HealthCheckOptions() { });
});
By the way, another example about Hub authorization yet again in AzureSignalR and pure JWT but I put here so you may take a peek
https://github.com/ilkerkaran/MySignalRPlayGround/blob/master/SignalRServer.API/Startup.cs
FIXED!!!!
Turns out it was ordering in Startup.cs file.
I first implemented ilkerkaran's suggestion about calling identityserver before UseEndpoints. Then after 4 more hours, I moved app.UseAuthorization() below app.UseIdentityServer and that fixed it.
Hopefully, this helps someone else.

How to define initial url on web api project?

I created a project on Visual Studio Code on Mac and wanted to set my default page. I wrote the code on the "Startup.cs", but it's not working.
When I run the project and open the browser it shows that is not finding the controller.
Follow the Startup.cs code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace ProblemsV4
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
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)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Problem}/{action=Index}");
});
}
}
}
You should create a MVC project to be able to define the initial URL.
Your problem is because you're creating a Web API project instead of a MVC project,
because it's an API, doesn't make sense to have a default initial url, like MVC project (because of the views),
You could follow this tutorial to create a MVC application and set the default controller:
https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app-xplat/
If you mean the page that should open when you click run:
Right click on your project -> properties -> Debug -> Launch browser

ASP.NET 5 MVC6 - How to include the standard HTTP error views (404, 502, etc..)

I created a new empty Project in Visual Studio 2015 - Update 1 with ASP.NET 5, MVC6 and AngularJS. I want to see the standard error pages when there are errors like 404, 502 etc like shown in the example below.
How can I include those error messages?
At this time I can only look in my browser console and see the 404 errors.
The routing will be client side with the angular ui-router module (if this information is needed here).
Here you can see my startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Diagnostics;
using Microsoft.AspNet.Diagnostics.Entity;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Chronicus
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
/*
// auto generated code
app.UseIISPlatformHandler();
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
*/
app.UseIISPlatformHandler();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseMvc();
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}

Categories