Marcin Jahn | Dev Notebook
  • Home
  • Programming
  • Technologies
  • Projects
  • About
  • Home
  • Programming
  • Technologies
  • Projects
  • About
  • An icon of the Core section Core
    • Programs Execution
    • Stack and Heap
    • Asynchronous Programming
      • Overview
      • Event Queues
      • Fibers
      • Stackless Coroutines
  • An icon of the .NET section .NET
    • HTTPClient
    • Async
      • How Async Works
      • TAP Tips
    • Equality
    • Comparisons
    • Enumerables
    • Unit Tests
    • Generic Host
    • Logging
    • Configuration
    • Records
    • Nullability
    • Garbage Collector
    • IL and Allocations
    • gRPC
    • Source Generators
    • Platform Invoke
    • ASP.NET Core
      • Overview
      • Middleware
      • Razor Pages
      • Routing in Razor Pages
      • Web APIs
      • Filters
      • Identity
      • Validation
      • Tips
    • Entity Framework Core
      • Overview
      • Testing
      • Tips
  • An icon of the Angular section Angular
    • Overview
    • Components
    • Directives
    • Services and DI
    • Routing
    • Observables (RxJS)
    • Forms
    • Pipes
    • HTTP
    • Modules
    • NgRx
    • Angular Universal
    • Tips
    • Standalone Components
  • An icon of the JavaScript section JavaScript
    • OOP
    • JavaScript - The Weird Parts
    • JS Functions
    • ES Modules
    • Node.js
    • Axios Tips
    • TypeScript
      • TypeScript Environment Setup
      • TypeScript Tips
    • React
      • React Routing
      • MobX
    • Advanced Vue.js Features
  • An icon of the Rust section Rust
    • Overview
    • Cargo
    • Basics
    • Ownership
    • Structures
    • Enums
    • Organization
    • Collections
    • Error Handling
    • Generics
    • Traits
    • Lifetimes
    • Closures
    • Raw Pointers
    • Smart Pointers
    • Concurrency
    • Testing
    • Tips
  • An icon of the C/C++ section C/C++
    • Compilation
    • Structures
    • OOP in C
    • Pointers
    • Strings
    • Dynamic Memory
    • argc and argv Visualization
  • An icon of the GTK section GTK
    • Overview
    • GObject
    • GJS
  • An icon of the CSS section CSS
    • Responsive Design
    • CSS Tips
    • CSS Pixel
  • An icon of the Unity section Unity
    • Unity
  • An icon of the Functional Programming section Functional Programming
    • Fundamentals of Functional Programming
    • .NET Functional Features
    • Signatures
    • Function Composition
    • Error Handling
    • Partial Application
    • Modularity
    • Category Theory
      • Overview
      • Monoid
      • Other Magmas
      • Functors
  • An icon of the Algorithms section Algorithms
    • Big O Notation
    • Array
    • Linked List
    • Queue
    • Hash Table and Set
    • Tree
    • Sorting
    • Searching
  • An icon of the Architecture section Architecture
    • What is architecture?
    • Domain-Driven Design
    • ASP.NET Core Projects
  • An icon of the Core section Core
    • Programs Execution
    • Stack and Heap
    • Asynchronous Programming
      • Overview
      • Event Queues
      • Fibers
      • Stackless Coroutines
  • An icon of the .NET section .NET
    • HTTPClient
    • Async
      • How Async Works
      • TAP Tips
    • Equality
    • Comparisons
    • Enumerables
    • Unit Tests
    • Generic Host
    • Logging
    • Configuration
    • Records
    • Nullability
    • Garbage Collector
    • IL and Allocations
    • gRPC
    • Source Generators
    • Platform Invoke
    • ASP.NET Core
      • Overview
      • Middleware
      • Razor Pages
      • Routing in Razor Pages
      • Web APIs
      • Filters
      • Identity
      • Validation
      • Tips
    • Entity Framework Core
      • Overview
      • Testing
      • Tips
  • An icon of the Angular section Angular
    • Overview
    • Components
    • Directives
    • Services and DI
    • Routing
    • Observables (RxJS)
    • Forms
    • Pipes
    • HTTP
    • Modules
    • NgRx
    • Angular Universal
    • Tips
    • Standalone Components
  • An icon of the JavaScript section JavaScript
    • OOP
    • JavaScript - The Weird Parts
    • JS Functions
    • ES Modules
    • Node.js
    • Axios Tips
    • TypeScript
      • TypeScript Environment Setup
      • TypeScript Tips
    • React
      • React Routing
      • MobX
    • Advanced Vue.js Features
  • An icon of the Rust section Rust
    • Overview
    • Cargo
    • Basics
    • Ownership
    • Structures
    • Enums
    • Organization
    • Collections
    • Error Handling
    • Generics
    • Traits
    • Lifetimes
    • Closures
    • Raw Pointers
    • Smart Pointers
    • Concurrency
    • Testing
    • Tips
  • An icon of the C/C++ section C/C++
    • Compilation
    • Structures
    • OOP in C
    • Pointers
    • Strings
    • Dynamic Memory
    • argc and argv Visualization
  • An icon of the GTK section GTK
    • Overview
    • GObject
    • GJS
  • An icon of the CSS section CSS
    • Responsive Design
    • CSS Tips
    • CSS Pixel
  • An icon of the Unity section Unity
    • Unity
  • An icon of the Functional Programming section Functional Programming
    • Fundamentals of Functional Programming
    • .NET Functional Features
    • Signatures
    • Function Composition
    • Error Handling
    • Partial Application
    • Modularity
    • Category Theory
      • Overview
      • Monoid
      • Other Magmas
      • Functors
  • An icon of the Algorithms section Algorithms
    • Big O Notation
    • Array
    • Linked List
    • Queue
    • Hash Table and Set
    • Tree
    • Sorting
    • Searching
  • An icon of the Architecture section Architecture
    • What is architecture?
    • Domain-Driven Design
    • ASP.NET Core Projects

Generic Host

Console apps or ASP.NET Core background tasks can use IHostedService to run. Such apps are also perfect to run in:

  • containers
  • system services (e.g. via systemd)

Kestrel

Kestrel itself uses IHostedService to run!

IHostedService

StartAsync

The StartAsync method of the IHostedService interface is async, but it’s run inline during startup. If the hosted service is a long-running one, it should return a Task immediately and schedule the work on a separate thread. Using await is also not recommended.

BackgroundService

The BackgroundService is a convenient base class. It’s designed to be used with long-running tasks. It has just one method to override - ExecuteAsync(). We can freely use await and never-ending loops (although we should be checking CancellationToken).

HttpClient and other non-singleton services

If our IHostedService implementation is long-lived we shouldn’t inject HTTP services there (e.g. typed HttpClients). HttpClient should be short-lived. We could either use IServiceProvider to get new typed client in some interval (service locator - not ideal) or use IHttpClientFactory.

Singleton

In general, IHosterServices are singletons. If we need to use some service that is not a singleton from within, we shouldn’t inject them directly. Instead, we need to use some factory or IServiceProvider (to create scope for example) to create the service repeatedly (usually the hosted service will run in some loop with a delay).

Terminating the app

The hosted service can terminate the app when finished the execution. An instance of IHostApplicationLifetime needs to be injected and used:

_logger?.LogInformation("Terminating Application");
_applicationLifetime.StopApplication();

Worker Service

Worker Service is a console app without the ASP.NET Core stuff.

We can easily create a Worker Service project with dotnet new worker. It creates a simple Worker class that inherits from BackgroundService and Program.cs that sets up IHost.

To get access to IHttpCLientFactory we need to add the Microsoft.Extensions.Http NuGet package.

Systemd

To turn an app into a systemd service, we’d install the Microsoft.Extensions.Hosting.Systemd package. Then we’d call the UseSystemd() method on IHostBuilder.

Runing as a Windows service is similar, but different package/method combo is used.

ASP.NET Core

ASP.NET Core apps can be installed as services as well.

Quartz.NET

Quartz.NET is a scheduler library that enable some more advanced features of background services, like:

  • CRON
  • running multiple instances of it, with options to control concurrency (similar to RedLock)

It acts as a

Manual Creation

We can also create the boilerplate manually.

Imports

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Threading.Tasks;

Creating an IHostBuilder

Simple:

private static IHostBuilder GetHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton(hostContext.Configuration.GetSection("AppConfiguration").Get<AppConfiguration>());
services.AddHostedService<InfluxCompleteSetupService>();
});
}

With configuration:

private static IHostBuilder GetHostBuilder()
{
var builder = new HostBuilder()
.ConfigureAppConfiguration((hostBuilderContext, configBuilder) =>
{
configBuilder.AddJsonFile("appsettings.json", optional: true);
configBuilder.AddEnvironmentVariables();
})
.ConfigureServices((hostBuilderContext, services) =>
{
services.AddAllServices(hostBuilderContext.Configuration.GetSection("AppConfiguration").Get<AppConfiguration>());
})
.ConfigureLogging((hostBuilderContext, loggingBuilder) =>
{
loggingBuilder.AddConfiguration(hostBuilderContext.Configuration.GetSection("Logging"));
loggingBuilder.AddConsole();
});
return builder;
}

Running the application

static async Task Main(string[] args)
{
try
{
var builder = GetHostBuilder(args);
await builder.RunConsoleAsync(options => options.SuppressStatusMessages = true);
}
catch (Exception e)
{
Console.WriteLine("Program run into an exception");
Console.WriteLine(e.Message);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}

.NET 6:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
try {
using var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((_, services) =>
services
.AddSingleton<InputReader>()
.AddSingleton<BmiCalculator>()
.AddHostedService<App>())
.Build();
await host.RunAsync();
}
catch (Exception e)
{
Console.WriteLine("Program run into an exception");
Console.WriteLine(e.Message);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
←  Unit Tests
Logging  →
© 2023 Marcin Jahn | Dev Notebook | All Rights Reserved. | Built with Astro.