Minimal Hosting Model: Exited from Program.Main with exit code = '0' - asp.net-core

After migrating an ASP.NET Core 6 app from the legacy Program/Startup to use the new minimal hosting model, I am receiving a non-descript set of errors.
Error Messages
I have explicitly enabled UseDeveloperExceptionPage() to be safe, but all I am receiving in the browser is the generic:
HTTP Error 500.30 - ASP.NET Core app failed to start
In the Event Viewer, Event 1011 gets logged:
Application '/LM/W3SVC/2/ROOT' with physical root 'C:\Code' has exited from Program.Main with exit code = '0'. Please check the stderr logs for more information.
Followed by Event 1007:
Application '/LM/W3SVC/2/ROOT' with physical root 'C:\Code' failed to load coreclr.
Exception message:
CLR worker thread exited prematurely
No further information is available in the debug console when running either IIS Express or Kestrel. I am, however, able to see other startup processes from my Program being logged, so know they're loading correctly.
Code
This is a simplified version of my Program file, with custom components removed:
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ViewComponents;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Should be implicit in Debug mode, but explicitly including to be safe
app.UseDeveloperExceptionPage();
app.UseStaticFiles();
app.UseRouting();
app.MapControllers();
Previous Threads
As these are really general errors, there are quite a few previous threads available related to this issue—but none that seem applicable to this case. (Many have to do with the ASP.NET Core Hosting Bundle, which I am not using.)
Question
Are there common causes for this issue? Alternatively, are there other approaches for debugging this scenario?

The error messages aren't terribly intuitive, but this error essentially means that the application ran, and then immediately exited. A common cause of this is when you neglect to add the Run() command at the end of the Program:
app.Run();
Background
This is easy to miss if you're focused on migrating your ConfigureServices() and Configure() methods from your Startup class. While most of your previous configuration code likely lives in that class, the Run() method is one of a few pieces that needs to be migrated from your legacy Program class. You might recognize it from your legacy Main() method; e.g.,
public static void Main(string[] args) => CreateHostBuilder(args).Build().Run();
In the new ASP.NET Core 6 minimal hosting model, this gets translated to:
var builder = WebApplication.CreateBuilder(args);
// Configuration from Startup.ConfigureService()
var app = builder.Build();
// Configuration from Startup.Configure()
app.Run();
When it exits from Program.Main() with exit code 0, that's telling you that your Program ran correctly—and, thus, seeing logging for your configuration code—but then it stopped without ever actually launching your web application.
Simple fix once you know to look for it.

Related

How to restart Kestrel Hosted in Windows Service?

I want to restart Kestrel (asp.net core 3.1) via an authorized http request.
Kestrel is contained in a Windows service configured to restart itself automatically upon failure.
As far as i know the simplest way is to return an exit code different from 0, windows will do all the rest.
In light of that, the code I wrote is actually simple:
public MaintenanceController(IHostApplicationLifetime hostLifetime)
{
this.HostLifetime = hostLifetime ?? throw new ArgumentNullException(nameof(hostLifetime));
}
[HttpPost]
[Route("service/restart")]
[Authorize("AdminOnly")]
public ActionResult RestartService()
{
Program.IsRestart = true; //see below
this.HostLifetime.StopApplication();
//this does not work!
if (HostLifetime is WindowsServiceLifetime lifetime)
{
lifetime.ExitCode = 1;
}
//neither this!
Environment.ExitCode = 1;
return Ok();
}
The only way to make windows restarts the service is just actually call
Environment.Exit(1);
without HostLifetime.StopApplication();
But the issue with Environment.Exit called alone is it causes a non graceful shutdown, something I want absolutely to avoid.
Another approach I tried, to force an exit code different from 0, which did not work, was to put in Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime)
{
[...]
applicationLifetime.ApplicationStopped.Register(() =>
{
//this can be set in the controller
if (Program.IsRestart)
{
Environment.Exit(1);
}
});
}
but, when called after ApplicationStopped, Environment.Exit(1) does apparently nothing, in fact even inside event viewer there is no trace of the services' shutdown with error, so windows does nothing.
UPDATE
Going back to classic, I changed the Main entry point to return an int and returned 1.
Still windows does not restart the service nor a failure entry is written to event viewer. It looks like is always stopped gracefully
Everything is working like it should. You may want to consider writing a wrapper batch file or watcher process.
Your watcher would wait for the process to exit, and if a flag file (e.g. .staydown) is present, it would exit gracefully. If the file doesn't exist, it would then restart the process.
In your RestartService method, use Environment.Exit(0) which would be a graceful shutdown, but since the .staydown file doesn't exist, your watcher would then restart the server. Your watcher would only stop running if the .staydown file exists and then the server is stopped, or the Windows Service itself is stopped.
When your app starts up, be sure to delete .staydown if present.
If you have node installed, you might be able to use a utility like forever in place of the watcher batch file.
You need to check the 'Enable actions for stops with errors' on the service, or run 'sc failureflag "My Service" 1'
More info here: https://blog.stephencleary.com/2020/06/servicebase-gotcha-recovery-actions.html
(this is a very strange behaviour on Windows part I think, honouring exit codes should be default!)

Weird exception when trying to use Dependency Injection in an Azure Function

Given a File->New->Azure Functions v2 App, I'm trying to get a reference to either an ILoggerFactory or an ILogger<T>.
I'm doing this in the StartUp.cs class which is ran on the function app start.
Given the following code a weird exception is thrown:
var serviceProvider = builder.Services.BuildServiceProvider();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
with the following exception:
A host error has occurred
[27/02/2019 8:21:22 AM] Microsoft.Extensions.DependencyInjection: Unable to resolve service for type 'Microsoft.Azure.WebJobs.Script.IFileLoggingStatusManager' while attempting to activate 'Microsoft.Azure.WebJobs.Script.Diagnostics.HostFileLoggerProvider'.
Value cannot be null.
Parameter name: provider
What is going on?
The full test repo/code can be found here on GitHub.
It seems that some infrastructure (e.g. IFileLoggingStatusManager) necessary for HostFileLoggerProvider is not set up yet at the time you are creating the dependency injection container and attempt to resolve the logger in the StartUp class. I think you should delay logging until after the application has fully started.
If you look at the startup code of WebJobs you'll see that the logger gets added first, after that the external startup gets executed and finally the required logging services gets added. Which is the wrong order for your case.
I've been looking for a solution for a while then I end up creating another service container for the startup class, but it'll need to register the required services to this container.
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var services = builder.Services;
IConfiguration configuration = services.BuildServiceProvider().GetService<IConfiguration>();
var tempServiceContainer = new ServiceCollection()
.AddScoped(_ => configuration);
tempServiceContainer.AddSingleton<IYourService, YourService>();
}
}
Or maybe you could try using lazy Dependency Injection, but I haven't test it yet on the cloud server.
service.AddSingleton<IYourService, YourService>();
service.AddSingleton(provider => new Lazy<IYourService>(provider.GetService<IYourService>));
var yourService = serviceProvider.GetService<Lazy<IYourService>>();
This doesn't work, at least not yet. (link)
The services getting registered at startup are not fully ready to be used inside the Configure method itself. Read the section 'Caveats' here:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection
"The startup class is meant for only setup and registration. Avoid
using services registered at startup during the startup process. For
instance, don't try to log a message in a logger that is being
registered during startup. This point of the registration process is
too early for your services to be available for use. After the
Configure method is run, the Functions runtime continues to register
additional dependencies, which can affect how your services operate."

Topshelf Windows Service times out Error 7000 7009

I have a windows service programmed in vb.NET, using Topshelf as Service Host.
Once in a while the service doesn't start. On the event log, the SCM writes errors 7000 and 7009 (service did not respond in a timely fashion). I know this is a common issue, but I (think) I have tried everything with no result.
The service only relies in WMI, and has no time-consuming operations.
I read this question (Error 1053: the service did not respond to the start or control request in a timely fashion), but none of the answers worked for me.
I Tried:
Set topshelf's start timeout.
Request additional time in the first line of "OnStart" method.
Set a periodic timer wich request additional time to the SCM.
Remove TopShelf and make the service with the Visual Studio Service Template.
Move the initialization code and "OnStart" code to a new thread to return inmediately.
Build in RELEASE mode.
Set GeneratePublisherEvidence = false in the app.config file (per application).
Unchecked "Check for publisher’s certificate revocation" in the internet settings (per machine).
Deleted all Alternate Streams (in case some dll was marked as web and blocked).
Removed any "Debug code"
Increased Window's general service timeout to 120000ms.
Also:
The service doesn't try to communicate with the user's desktop in any way.
The UAC is disabled.
The Service Runs on LOCAL SYSTEM ACCOUNT.
I believe that the code of the service itself is not the problem because:
It has been on production for over two years.
Usually the service starts fine.
There is no exception logged in the Event Log.
The "On Error" options for the service dosn't get called (since the service doesn't actually fails, just doesn't respond to the SCM)
I've commented out almost everything on it, pursuing this error! ;-)
Any help is welcome since i'm completely out of ideas, and i've been strugling with this for over 15 days...
For me the 7009 error was produced by my NET core app because I was using this construct:
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
and appsettings.json file obviously couldn't be found in C:\WINDOWS\system32.. anyway, changing it to Path.Combine(AppContext.BaseDirectory, "appsettings.json") solved the issue.
More general help - for Topshelf you can add custom exception handling where I finally found some meaningfull error info, unlike event viewer:
HostFactory.Run(x => {
...
x.OnException(e =>
{
using (var fs = new StreamWriter(#"C:\log.txt"))
{
fs.WriteLine(e.ToString());
}
});
});
I've hit the 7000 and 7009 issue, which fails straight away (even though the error message says A timeout was reached (30000 milliseconds)) because of misconfiguration between TopShelf and what the service gets installed as.
The bottom line - what you pass in HostConfigurator.SetServiceName(name) needs to match exactly the SERVICE_NAME of the Windows service which gets installed.
If they don't match it'll fail straight away and you get the two event log messages.
I had this start happening to a service after Windows Creator's Edition update installed. Basically it made the whole computer slower, which is what I think triggered the problem. Even one of the Windows services had a timeout issue.
What I learned online is that the constructor for the service needs to be fast, but OnStart has more leeway with the SCM. My service had a C# wrapper and it included an InitializeComponent() that was called in the constructor. I moved that call to OnStart and the problem went away.

An asynchronous operation cannot be started at this time in .net 4.5

I am trying to call an async method from a WCF service, within a project that targets .net 4.5 and am getting the annoying "An asynchronous operation cannot be started at this time" error.
When i create another copy of my app that targets .net 4.0 it works. No error message.
What can that be? Any ideas on how i can fix this?
The async calls are made using Something.DoAsync() and OnCompleted event pattern.
UPDATE:
The exact error is:
"An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>."
My code look something like this:
m_Service.LoginCompleted += m_Service_LoginCompleted;
try
{
m_Service.LoginAsync(ToByteMesIn(loPar), key.Id);
}
catch (Exception exc)
{
SendNotification(exc.Message);
}
The error happens when the Login4Aynch method is called.
Showing the exception.
Please bear in mind this only happens when my project is compiled targeting .NET .4.5, the code works fine when targeting .NET 4.0
The m_service is a WCF service : "net.tcp://some.domain.com/something:"
MORE INFO:
This is run as a web app, and the WCF server targets .NET 4.5

Configuring Ninject for a console application and leveraging the existing repository for my MVC application

I have a MVC 3 solution configured with Ninject using a repository pattern. Some of my bindings include:
kernel.Bind<IDatabaseFactory>().To<DatabaseFactory>().InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind<IMyRepository>().To<MyRepository>().InRequestScope();
kernel.Bind<IMyService>().To<MyService>().InRequestScope();
kernel.Bind<ILogging>().To<Logging>().InSingletonScope();
I also added a console application to my solution and I want to leverage the same repository and services. My Ninject configuration for the console application looks like:
kernel.Bind<IDatabaseFactory>().To<DatabaseFactory>().InSingletonScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope();
kernel.Bind<IMyRepository>().To<MyRepository>().InSingletonScope();
kernel.Bind<IMyService>().To<MyService>().InSingletonScope();
kernel.Bind<ILogging>().To<Logging>().InSingletonScope();
My console code looks like:
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new IoCMapper());
var service = kernel.Get<IMyService>();
var logger = kernel.Get<ILogging>();
... do some processing here
}
This works just fine but I want t be sure that I am configuring Ninject correctly for a console application. Is it correct to use InSingletonScope() for all my bindings in my console application? Should I be configuring it differently?
Do you want one and only one instance of each of your repository services for the whole application? If so, then use InSingletonScope.
Is your console application multithreaded? If this is the case and you want a new instance of your services for each thread then you will use InThreadScope.
If you want a new instance of the service(s) each time they are called for, set it to InTransientScope.
You also have the option of defining your own scope using InScope. Bob Cravens gives a good overview of each of these here http://blog.bobcravens.com/2010/03/ninject-life-cycle-management-or-scoping/