Skip to content

Commit d03b67f

Browse files
committed
Initial commit
0 parents  commit d03b67f

File tree

12 files changed

+175
-0
lines changed

12 files changed

+175
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin/**
2+
obj/**

.idea/.idea.WindowsServiceDotNETCore.dir/.idea/.gitignore

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/.idea.WindowsServiceDotNETCore.dir/.idea/encodings.xml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/.idea.WindowsServiceDotNETCore.dir/.idea/indexLayout.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/.idea.WindowsServiceDotNETCore.dir/.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

JokeService.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
namespace WindowsServiceDotNETCore;
2+
3+
public sealed class JokeService
4+
{
5+
public string GetJoke()
6+
{
7+
Joke joke = _jokes.ElementAt(
8+
Random.Shared.Next(_jokes.Count));
9+
10+
return $"{joke.Setup}{Environment.NewLine}{joke.Punchline}";
11+
}
12+
13+
// Programming jokes borrowed from:
14+
// https://github.com/eklavyadev/karljoke/blob/main/source/jokes.json
15+
private readonly HashSet<Joke> _jokes = new()
16+
{
17+
new Joke("What's the best thing about a Boolean?", "Even if you're wrong, you're only off by a bit."),
18+
new Joke("What's the object-oriented way to become wealthy?", "Inheritance"),
19+
new Joke("Why did the programmer quit their job?", "Because they didn't get arrays."),
20+
new Joke("Why do programmers always mix up Halloween and Christmas?", "Because Oct 31 == Dec 25"),
21+
new Joke("How many programmers does it take to change a lightbulb?", "None that's a hardware problem"),
22+
new Joke("If you put a million monkeys at a million keyboards, one of them will eventually write a Java program", "the rest of them will write Perl"),
23+
new Joke("['hip', 'hip']", "(hip hip array)"),
24+
new Joke("To understand what recursion is...", "You must first understand what recursion is"),
25+
new Joke("There are 10 types of people in this world...", "Those who understand binary and those who don't"),
26+
new Joke("Which song would an exception sing?", "Can't catch me - Avicii"),
27+
new Joke("Why do Java programmers wear glasses?", "Because they don't C#"),
28+
new Joke("How do you check if a webpage is HTML5?", "Try it out on Internet Explorer"),
29+
new Joke("A user interface is like a joke.", "If you have to explain it then it is not that good."),
30+
new Joke("I was gonna tell you a joke about UDP...", "...but you might not get it."),
31+
new Joke("The punchline often arrives before the set-up.", "Do you know the problem with UDP jokes?"),
32+
new Joke("Why do C# and Java developers keep breaking their keyboards?", "Because they use a strongly typed language."),
33+
new Joke("Knock-knock.", "A race condition. Who is there?"),
34+
new Joke("What's the best part about TCP jokes?", "I get to keep telling them until you get them."),
35+
new Joke("A programmer puts two glasses on their bedside table before going to sleep.", "A full one, in case they gets thirsty, and an empty one, in case they don’t."),
36+
new Joke("There are 10 kinds of people in this world.", "Those who understand binary, those who don't, and those who weren't expecting a base 3 joke."),
37+
new Joke("What did the router say to the doctor?", "It hurts when IP."),
38+
new Joke("An IPv6 packet is walking out of the house.", "He goes nowhere."),
39+
new Joke("3 SQL statements walk into a NoSQL bar. Soon, they walk out", "They couldn't find a table.")
40+
};
41+
}
42+
43+
readonly record struct Joke(string Setup, string Punchline);

Program.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using WindowsServiceDotNETCore;
2+
using Microsoft.Extensions.Logging.Configuration;
3+
using Microsoft.Extensions.Logging.EventLog;
4+
5+
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
6+
builder.Services.AddWindowsService(options =>
7+
{
8+
options.ServiceName = ".NET Joke Service";
9+
});
10+
11+
LoggerProviderOptions.RegisterProviderOptions<
12+
EventLogSettings, EventLogLoggerProvider>(builder.Services);
13+
14+
builder.Services.AddSingleton<JokeService>();
15+
builder.Services.AddHostedService<WindowsBackgroundService>();
16+
17+
IHost host = builder.Build();
18+
host.Run();

Properties/launchSettings.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"$schema": "http://json.schemastore.org/launchsettings.json",
3+
"profiles": {
4+
"WindowsServiceDotNETCore": {
5+
"commandName": "Project",
6+
"dotnetRunMessages": true,
7+
"environmentVariables": {
8+
"DOTNET_ENVIRONMENT": "Development"
9+
}
10+
}
11+
}
12+
}

WindowsServiceDotNETCore.csproj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Worker">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<UserSecretsId>dotnet-WindowsServiceDotNETCore-081a241b-3c72-4faa-abbc-e558ba56cbbd</UserSecretsId>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
12+
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.7" />
13+
</ItemGroup>
14+
</Project>

Worker.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
namespace WindowsServiceDotNETCore;
2+
3+
public sealed class WindowsBackgroundService(
4+
JokeService jokeService,
5+
ILogger<WindowsBackgroundService> logger) : BackgroundService
6+
{
7+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
8+
{
9+
try
10+
{
11+
while (!stoppingToken.IsCancellationRequested)
12+
{
13+
string joke = jokeService.GetJoke();
14+
logger.LogWarning("{Joke}", joke);
15+
16+
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
17+
}
18+
}
19+
catch (OperationCanceledException)
20+
{
21+
// When the stopping token is canceled, for example, a call made from services.msc,
22+
// we shouldn't exit with a non-zero exit code. In other words, this is expected...
23+
}
24+
catch (Exception ex)
25+
{
26+
logger.LogError(ex, "{Message}", ex.Message);
27+
28+
// Terminates this process and returns an exit code to the operating system.
29+
// This is required to avoid the 'BackgroundServiceExceptionBehavior', which
30+
// performs one of two scenarios:
31+
// 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
32+
// 2. When set to "StopHost": will cleanly stop the host, and log errors.
33+
//
34+
// In order for the Windows Service Management system to leverage configured
35+
// recovery options, we need to terminate the process with a non-zero exit code.
36+
Environment.Exit(1);
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)