I am trying to run a .NET Core 1.0.0 console application inside a docker container.
When I run dotnet run
command from inside the Demo folder on my machin
One more "dirty way" is to start your program in screen using:
screen -dmS yourprogramm
You should run your container in Interactive mode (with the -i
option), but please note that the background processes will be closed immediately when you run the container, so make sure your script is run in the foreground or it simply won't work.
You can use:
Thread.Sleep(Timeout.Infinite);
See this answer:
Is Thread.Sleep(Timeout.Infinite); more efficient than while(true){}?
The only way I could get Docker/Linux to keep my .NET Core application alive was to spoof ASP.NET into hosting it for me... This is such an ugly hack!!
Doing it this way will run in Docker using the docker run -d
option, so you don't have to have a live connection to keep the STDIN stream alive.
I created a .NET Core console application (not an ASP.NET app) and my Program class looks like this:
public class Program
{
public static ManualResetEventSlim Done = new ManualResetEventSlim(false);
public static void Main(string[] args)
{
//This is unbelievably complex because .NET Core Console.ReadLine() does not block in a docker container...!
var host = new WebHostBuilder().UseStartup(typeof(Startup)).Build();
using (CancellationTokenSource cts = new CancellationTokenSource())
{
Action shutdown = () =>
{
if (!cts.IsCancellationRequested)
{
Console.WriteLine("Application is shutting down...");
cts.Cancel();
}
Done.Wait();
};
Console.CancelKeyPress += (sender, eventArgs) =>
{
shutdown();
// Don't terminate the process immediately, wait for the Main thread to exit gracefully.
eventArgs.Cancel = true;
};
host.Run(cts.Token);
Done.Set();
}
}
}
The Startup class:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IServer, ConsoleAppRunner>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
}
}
The ConsoleAppRunner class:
public class ConsoleAppRunner : IServer
{
/// <summary>A collection of HTTP features of the server.</summary>
public IFeatureCollection Features { get; }
public ConsoleAppRunner(ILoggerFactory loggerFactory)
{
Features = new FeatureCollection();
}
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
}
/// <summary>Start the server with an application.</summary>
/// <param name="application">An instance of <see cref="T:Microsoft.AspNetCore.Hosting.Server.IHttpApplication`1" />.</param>
/// <typeparam name="TContext">The context associated with the application.</typeparam>
public void Start<TContext>(IHttpApplication<TContext> application)
{
//Actual program code starts here...
Console.WriteLine("Demo app running...");
Program.Done.Wait(); // <-- Keeps the program running - The Done property is a ManualResetEventSlim instance which gets set if someone terminates the program.
}
}
The only nice thing about it is that you get to use DI in your application (if you want to) - so in my use case, I am using the ILoggingFactory to handle my logging.
Edit 30th Oct 2018
This post still seems to be popular - I'd like to just point out to anyone reading my old post that it is now pretty ancient. I was basing it on .NET Core 1.1 (which was new at the time). It is likely that if you are using a newer version of.NET Core (2.0 / 2.1 or greater) that there is probably a much better way of solving this problem now. Please take time to look at some of the other posts on this thread which may not be as highly ranked as this one, but may be newer and more up-to-date.
For those that what to run your .net 4.x console app in linux docker without having to specified -i
and want to run it in the background, the best solution is mono.posix
package, which does exactly what we are looking for, listen to linux signals.
this also applys to WebApi2
with Owin
projects, or basically any console app
for most of us running containers in the background using console.read
or ManualResetEventSlim
or AutoResetEvent
wont worked because of detached mode by docker.
The best solution is installing Install-Package Mono.Posix
here's an example:
using System;
using Microsoft.Owin.Hosting;
using Mono.Unix;
using Mono.Unix.Native;
public class Program
{
public static void Main(string[] args)
{
string baseAddress = "http://localhost:9000/";
// Start OWIN host
using (WebApp.Start<Startup>(url: baseAddress))
{
Console.ReadLine();
}
if (IsRunningOnMono())
{
var terminationSignals = GetUnixTerminationSignals();
UnixSignal.WaitAny(terminationSignals);
}
else
{
Console.ReadLine();
}
host.Stop();
}
public static bool IsRunningOnMono()
{
return Type.GetType("Mono.Runtime") != null;
}
public static UnixSignal[] GetUnixTerminationSignals()
{
return new[]
{
new UnixSignal(Signum.SIGINT),
new UnixSignal(Signum.SIGTERM),
new UnixSignal(Signum.SIGQUIT),
new UnixSignal(Signum.SIGHUP)
};
}
}
full source blog post: https://dusted.codes/running-nancyfx-in-a-docker-container-a-beginners-guide-to-build-and-run-dotnet-applications-in-docker
Using Console.ReadLine
instead seems to work.
C#:
do
{
Console.WriteLine($"Type: quit<Enter> to end {Process.GetCurrentProcess().ProcessName}");
}
while (!Console.ReadLine().Trim().Equals("quit",StringComparison.OrdinalIgnoreCase));
F#:
while not (Console.ReadLine().Trim().Equals("quit",StringComparison.OrdinalIgnoreCase)) do
printfn "Type: quit<Enter> to end"