How to Build and Operate Windows Services ── From Choosing Between Task Scheduler and Services to Turning a BackgroundService into a Windows Service
· Go Komura · Windows Service, Windows, .NET, C#, BackgroundService, Generic Host, Background Processing, Operations, Decision Table, Technical Consulting
“A Task Scheduler job running every 5 minutes just can’t keep up anymore.” “We want a monitoring daemon running at all times, waiting on data from a device.” “When a file lands in a folder, we need it processed within a few seconds.” Keep taking on consulting work around scheduled execution, and requirements inevitably grow into this conversation.
On this blog, we’ve been writing a continuing series on automation: Automating Business Processes with Power Automate and Designing Reliable, Safe Task Scheduler Operations. Chapter 8 of the Task Scheduler article drew a line: once you need minute-level polling or constant monitoring, you’ve crossed into resident-process territory. But how do you actually build a Windows service, and how do you get it running reliably in production? Leave that question vague and just “turn it into a service for now,” and you end up with services that can’t be stopped, services that silently die with nobody noticing, and services running as LocalSystem doing anything they please.
This article organizes, in the order you’d actually decide them in practice: a decision table for whether a background process should become a Windows service, the minimum knowledge needed of how services work (the SCM, start types, Session 0), an implementation using the .NET 8 Worker Service template, registration and recovery options via sc.exe, choosing a service account, and safe shutdown handling.
1. The Short Version
- The axis for deciding is simple. If it’s periodic work at intervals of a few minutes or more, Task Scheduler is enough. Once the requirements include constant listening (sockets, named pipes, FileSystemWatcher), second-level response, or automatic recovery from a crash, you need a Windows service.
- Since Windows Vista, services run in Session 0 and cannot interact directly with the user (cannot show a UI). If a UI is required, split the service and the UI app into separate processes and design them to talk over inter-process communication.1
- For .NET, the official route is the Worker Service template plus
Microsoft.Extensions.Hosting.WindowsServices’sAddWindowsService(orUseWindowsServicefor theIHostBuilderfamily).2 It can be run directly as a console app, which makes development and debugging dramatically easier than traditional service development. - From .NET 6 onward, an unhandled exception inside
BackgroundServicestops the host by default (BackgroundServiceExceptionBehavior.StopHost). But since this counts as a “normal stop,” it does not trigger the SCM’s recovery-driven restart. For a failure you want to trigger a restart, bring the process down with a non-zero exit code.32 - Don’t default to LocalSystem for the service account out of inertia. Since
sc.exe createdefaults to LocalSystem4, it starts running with maximum privilege unless you deliberately choose otherwise. For purely local work, LocalService or a virtual account is the right call; for anything touching a domain share or database, a gMSA is the go-to.5 - Design the recovery options (
sc.exe failure) and the shutdown handling (HostOptions.ShutdownTimeout, defaulting to 30 seconds6) at registration time. A “service that doesn’t respond to stop requests” is one of the most hated things in operations.
2. When Should Something Become a Service? — a Decision Table for Task Scheduler, Services, and Resident Apps
When a requirement that sounds like it needs to be “always running” comes up, there are three options: Task Scheduler, a Windows service, or a “resident app registered at startup” (the kind that lives in the notification area). Here’s how they compare.
| Aspect | Task Scheduler | Windows Service | Resident App (Registered at Startup) |
|---|---|---|---|
| Start timing | Triggered by time or event, each run | Resident from OS boot (before logon) | From user logon onward |
| Logon required? | Can run without logon (non-interactive) | Not required | Required (disappears on logoff) |
| UI | Cannot show one (in a non-interactive configuration) | Cannot show one (Session 0) | Can show one (notification area, dialogs) |
| Continuous or periodic | Periodic (best suited to hourly-to-daily intervals) | Continuous | Continuous (but within the user session) |
| Privileges | Run-as account specified per task | Service account (Chapter 6) | Logged-on user’s privileges |
| Monitoring & recovery | History + your own notifications | SCM recovery options (automatic restart) | None (build it yourself) |
| Deployment effort | Register via XML / PowerShell | sc.exe / installer | Register via Run key, etc. |
Here’s the axis for deciding.
- If it’s periodic work — a few times a day up to hourly — that carries no state between runs, use Task Scheduler. Turning this into a service and rolling your own timer management is overkill; the operational design covered in the Task Scheduler article is far cheaper.
- If constant, always-on listening is the essence of the job — waiting on requests over TCP or a named pipe, watching a folder with FileSystemWatcher, draining a queue sequentially, reacting within seconds — that’s a Windows service. If you find yourself chopping the work into a “task every 5 minutes” and polling in slices, that’s a sign you’re reimplementing a resident process poorly.
- If the UI is the whole point — operation from the notification area, popups to the user — that’s a resident app. But it only runs while someone is logged on, so it doesn’t work for server-like use cases. If “background processing must run constantly, but a UI is also needed,” split it into two processes — a service and a UI app — as described in the next chapter.
One more decision factor that’s easy to overlook is recovery. A Task Scheduler job that fails just sits there until its next scheduled run, but for a service, the SCM takes care of automatic restarts (Chapter 5). A requirement like “if it goes down overnight, it should recover on its own by morning” is, by itself, a reason to make something a service.
3. The Minimum You Need to Know About How Services Work — the SCM, Start Types, and Session 0
3.1 The SCM and Start Types
The party running the show for Windows services is the Service Control Manager (SCM). It manages the registry of services, brokers start and stop requests, and carries out recovery actions on failure. A service process has to be built to talk to the SCM according to its protocol, but .NET’s libraries handle that part for us (Chapter 4), leaving four things for us to actually design: the start type, the service account, recovery, and shutdown.
There are four choices for the start type (startup type).4
| Start type | Behavior | Where it’s used |
|---|---|---|
| Automatic (auto) | Starts at OS boot | The baseline for an always-on service |
| Automatic (Delayed Start) (delayed-auto) | Starts a little after other automatic services | The default choice for a business service — avoids congestion right after boot and dependencies that aren’t up yet |
| Manual (demand) | Starts only on request | Helper services started by other apps |
| Disabled (disabled) | Cannot start | Decommissioning / locking down |
Make delayed start the default for business services. Right after OS boot, the network, the database, and other services aren’t all up yet, so starting as fast as possible with “Automatic” tends to fail on the first connection attempt. The stable two-layer approach is to buy some time with delayed start, and then absorb any remaining connection failures with retries inside ExecuteAsync, covered below.
There’s one more thing worth knowing: the start timeout. The SCM won’t wait forever for a service to report that it has finished starting. Exceed the default timeout (ServicesPipeTimeout, 30 seconds) and events 7000/7011 get logged, and the start is treated as a failure.7 In other words, don’t do heavy initialization — retrying a database connection, building a large cache — inside the “start” step. The iron rule is: finish starting immediately, and do the heavy lifting in the main loop (ExecuteAsync).
3.2 Session 0 Isolation — a Service Cannot Show a UI
Since Windows Vista, services run in an isolated session called Session 0, and cannot interact with the user directly.1 Calling MessageBox.Show or showing a form from inside a service produces nothing on the screen of a logged-on user. Worse, it becomes a classic hang: the process sits forever waiting for an OK button that no one can click. When porting older code into a service, always check that no message box intended as an error display has been left behind.
When a UI is required, the right answer is to split the work into a service (Session 0) and a UI app (user session) as separate processes, and have them talk over inter-process communication (IPC). This is the design Microsoft itself recommends — using an IPC mechanism such as a named pipe, with the UI side reporting results back to the service.1 Which IPC mechanism to choose is covered in the companion article published the same day, A Decision Table for Inter-Process Communication. Putting the UI app on Generic Host as well lets both processes share the same approach to DI, logging, and configuration (see Why Use the .NET Generic Host and BackgroundService in Desktop Apps).
4. How to Build One in .NET — the Worker Service Template and AddWindowsService
4.1 The Template and Program.cs
Service development in .NET starts with the Worker Service template. It ships with the SDK, so dotnet new worker scaffolds the project; add the Microsoft.Extensions.Hosting.WindowsServices package and call AddWindowsService, and it’s ready to run as a Windows service.2 The Generic Host mechanism underlying this is covered in What Is the .NET Generic Host?.
using App.MonitorService;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// Wire up the lifetime that talks to the SCM when started as a Windows service.
// When started as a console app, it just keeps running with the normal ConsoleLifetime
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "KsMonitor";
});
builder.Services.AddSingleton<MeasurementQueue>();
builder.Services.AddHostedService<MonitorWorker>();
IHost host = builder.Build();
host.Run();
For an older-style project using Host.CreateDefaultBuilder, call the IHostBuilder extension UseWindowsService() instead. It plays the same role.
There’s one trap here that’s the same shape as the “Start in (optional)” problem from the Task Scheduler article: when started as a service, the current directory is C:\Windows\System32. If you’re loading appsettings.json and similar files assuming a relative path, you get “it works from the console, but the service can’t find its settings.” Resolve configuration files relative to the executable, or, as the official tutorial recommends, pass --contentRoot in the binpath at registration time to make the content root explicit.2
4.2 ExecuteAsync — Designing Around stoppingToken and Exceptions
The main logic goes in ExecuteAsync, overridden from BackgroundService. What you need to decide here really comes down to two things: how to respond to a stop request, and how to handle exceptions.
namespace App.MonitorService;
public sealed class MonitorWorker(
MeasurementQueue queue,
ILogger<MonitorWorker> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
// Dequeue one item and process it. Always pass the token to the wait as well
var item = await queue.DequeueAsync(stoppingToken);
await ProcessAsync(item, stoppingToken);
}
catch (Exception ex) when (ex is IOException or TimeoutException)
{
// A failure we can recover from: log it, then retry after a delay
logger.LogError(ex, "Processing failed. Retrying in 30 seconds.");
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
}
}
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
// A stop request from the SCM. This is the normal flow, so do nothing.
// The `when` clause narrows this to cancellation caused by stoppingToken specifically,
// so that a cancellation thrown by an internal timeout or similar isn't mistaken
// for a "normal stop" — which would leave the worker quietly stopped
// while the host keeps running
}
catch (Exception ex)
{
// An unexpected failure: with the default StopHost behavior, the host stops
// "normally," so the SCM's recovery option (automatic restart) never fires.
// Exit with a non-zero code instead, to tell the SCM this actually failed
logger.LogCritical(ex, "Unrecoverable error; shutting down the service.");
Environment.Exit(1);
}
}
private Task ProcessAsync(Measurement item, CancellationToken token)
=> throw new NotImplementedException();
}
- Pass
stoppingTokento every wait.Task.Delay, I/O, queue waits — all of them. Even one long wait that ignores the token becomes fertile ground for a “service that doesn’t respond to stop requests” (Chapter 7). - Separate recoverable failures from unrecoverable ones. Catch network drops and transient timeouts inside the loop, log them, and retry. A
catch (Exception)that just swallows the error andcontinues only produces a service that quietly spins its wheels. How to decide which bucket a given failure falls into is covered in A Decision Table for Whether to Exit or Continue on an Unexpected Exception. - Know the default behavior for an unhandled exception. Before .NET 6, an exception leaking out of
ExecuteAsyncvanished into the void, and the service became a “zombie” — apparently running, but doing nothing. From .NET 6 onward, the default isBackgroundServiceExceptionBehavior.StopHost: the exception is logged, and then the host stops.3 But that stop is a “normal stop,” so it won’t be restarted even if you’ve configured recovery options. For failures you want the recovery option to bring back, exit explicitly and abnormally withEnvironment.Exit(1), as in the code above — that’s the approach laid out in the official tutorial.2
4.3 It Still Runs as a Console App — the Biggest Reason Development Got Easier
AddWindowsService only switches to the service lifetime when it’s actually launched as a Windows service. That means the same exe runs as an ordinary console app under Visual Studio’s F5 or dotnet run. Breakpoints still work, and pressing Ctrl+C lets you verify the entire flow locally, from the stop request through to StopAsync.
That said, working from the console doesn’t guarantee it’ll work as a service. Three things — the difference in service account (Chapter 6), Session 0, and the current directory — genuinely need to be verified as a service on real hardware. Almost every case of “it works from the console but not as a service” traces back to one of these three.
5. Registration and Operations — sc.exe, Recovery Options, and Event Logging
5.1 Registering with sc.exe create
Publish the exe (dotnet publish — a single-file publish is the easiest to work with), then register it with the SCM using sc.exe create. Run this from an administrative PowerShell.
sc.exe create "KsMonitor" binpath= "C:\Services\KsMonitor\KsMonitor.exe" start= delayed-auto obj= "NT AUTHORITY\LocalService" displayname= "KS Measurement Data Ingest Service"
sc.exe description "KsMonitor" "Resident service that ingests measurement data and registers it in the database (owner: IT Systems Department)"
A classic trap first: binpath= and start= require a space after the equals sign. This is sc.exe’s own idiosyncratic syntax — everything up to the equals sign is the option name, and a space between it and the value is mandatory (omit it and the command fails).4 Also, if you omit obj=, the default is LocalSystem.4 Register without thinking about it and the service starts running with maximum privilege, so make the choice from Chapter 6 at registration time.
Setting description matters more than it looks. Leaving behind information that lets someone who opens services.msc years from now judge “what this service is, whether it’s safe to stop, and who to ask” eliminates a lot of future investigation cost. To remove it, stop the service first, then run sc.exe delete "KsMonitor".2
If you’re deploying to multiple machines, or updates (file replacements) happen regularly, move early to an installer (MSI, WiX’s ServiceInstall, etc.) that handles registration, updates, and removal as a set, rather than doing it by hand with sc.exe. A manual registration runbook will always, eventually, produce a machine where someone skipped a step.
5.2 Recovery Options — Let the SCM Handle “Restart on Crash”
One of the big benefits of turning something into a service is the SCM’s built-in recovery options. You can declaratively configure what happens when the process terminates abnormally.2
sc.exe failure "KsMonitor" reset= 86400 actions= restart/60000/restart/60000/restart/300000
This example means: “restart after 60 seconds on the 1st and 2nd failures, restart after 5 minutes from the 3rd failure onward, and reset the failure counter after 24 hours.” You can configure the same thing through the GUI (services.msc → Properties → the Recovery tab). Reach for this standard feature before building your own “watchdog task” or monitoring script.
Two cautions. First, as in the previous chapter, this only fires if the process exits non-zero; a normal stop via StopHost is not covered by recovery. Second, if the service is guaranteed to crash right after startup — a misconfiguration, an unreachable database — you get a restart loop. That’s exactly why the interval from the 3rd failure onward should be longer, and why you should first make sure “why it crashed” is captured in the event log (next section).
5.3 Combining Event Log and File Log
On Windows, Host.CreateApplicationBuilder automatically adds the EventLog logger provider. And by default, only Warning and above reach the event log.2 It’s easy to get confused and think “all my Information logs disappeared once I made this a service” — they haven’t disappeared, they’re just caught by the event log’s default filter. If you want operational events like start and stop recorded too, set the EventLog provider’s level explicitly in appsettings.json.
{
"Logging": {
"EventLog": {
"SourceName": "KsMonitor",
"LogLevel": {
"Default": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
}
One caution: an event source can’t be written to unless it’s registered beforehand, and registering it requires administrative privileges. Omitting SourceName doesn’t get you out of this either — by default, AddWindowsService uses the application name as the source name2, so either way you start from an “unregistered source.” A minimum-privilege account like LocalService can’t create a source at runtime, and when creation fails, operation begins with nothing at all written to the event log. Get the registration done on the installer side (or in an administrator-privileged setup step). This is the same point made in Chapter 6 of the Task Scheduler article: “separate CreateEventSource out into the setup step.”
The rule of thumb for the division of labor: the event log carries only what an operator needs to see (start, stop, failure, recovery), and detailed processing traces go to your own file log. The minimum requirements for maintaining your own file log (rotation, behavior on write failure) are covered in The Minimum Requirements for a Custom Logger, and designing to leave evidence behind when the whole process goes down is covered in Designing Windows Apps to Leave Logs and Dumps When They Crash. In a setup where recovery options trigger an automatic restart, whatever got recorded at the moment of the crash is the only clue you’ll have.
6. The Service Account — Don’t Default to LocalSystem Out of Inertia
A service runs in the security context of the account you specify; at startup, the SCM logs on as that account and attaches its token to the process.8 This is the service-world version of the “who does this run as” discussion from Chapter 3 of the Task Scheduler article. Here are the options.
| Account | Privileges | Network identity | Password management | Where it’s used |
|---|---|---|---|---|
| LocalSystem | Extremely powerful (OS-equivalent) | Computer account | Not needed | Avoid as a rule of thumb — note this is the sc.exe create default |
| LocalService | Minimal | Anonymous (can’t access shares) | Not needed | First choice for processing that’s entirely local |
| NetworkService | Minimal | Computer account | Not needed | Lightweight processing that touches domain resources |
| Virtual account (NT SERVICE\service-name) | Only what you grant it | Computer account | Not needed | Can be granted an ACL per service. Minimum privilege for local resources |
| gMSA | Only what you grant it | The gMSA itself | Managed automatically by the DC | The go-to for a service that touches a share or database in a domain |
There are three decision points.
- Don’t choose LocalSystem just because “it works.” A vulnerability in the service translates directly into taking over the entire machine. For whether administrator-equivalent privilege is genuinely necessary, the breakdown in When Do You Actually Need Administrator Privileges on Windows? applies as-is. In most cases, what’s actually needed is something like “write access to a specific folder,” and granting a folder ACL to a virtual account (
NT SERVICE\KsMonitor) covers that. A virtual account needs neither creation nor password management.5 - The network share trap. LocalService is anonymous on the network, so access to
\\server\sharefails. NetworkService, virtual accounts, and LocalSystem all go out on the network as the computer account (DOMAIN\machine-name$)5, so the share needs both share-level and NTFS permissions granted to the computer account. “I granted the user permission, but only the service can’t read it” is almost always this. Decide who you go out on the network as first, then configure the share side. - If you run it under an ordinary user account, budget for password operations too. A dedicated account needs the “Log on as a service” right, and once its password expires, the logon fails and the service can’t start.8 This is the service-world version of “the task silently dies after a password change.” In a domain environment, the right answer is to make the whole problem disappear with a gMSA, whose password the domain manages automatically (the same conclusion as Section 3.2 of the Task Scheduler article).
7. Safe Shutdown — ShutdownTimeout and In-Flight Work
Let’s walk through the shutdown flow. When services.msc, sc.exe stop, or an OS shutdown makes the SCM issue a stop request, .NET’s service lifetime translates that into stopping the host (StopApplication); stoppingToken is canceled, ExecuteAsync returns, and each service’s StopAsync is called. How long the host waits for this whole shutdown sequence is HostOptions.ShutdownTimeout, and the default is 30 seconds.69 If it doesn’t finish in time, shutdown is forced through without waiting for cleanup to complete.
If 30 seconds isn’t enough to finish writing out one in-flight item, work backward from the time you actually need and extend it.
builder.Services.Configure<HostOptions>(options =>
{
// Work backward from the maximum time needed to finish writing out in-flight work
options.ShutdownTimeout = TimeSpan.FromSeconds(90);
});
With that in place, shutdown handling comes down to three design points.
- Decide, as a sequence, what to do after a stop request. Stop accepting new work → finish in-flight processing (or interrupt it at a safe boundary and record it in a form that can be resumed) → clean up connections and temp files. Without deciding this order in advance, you get one of two extremes: dropping everything the instant you see the token, or trying to finish everything and running out of time.
- Don’t build a “service that doesn’t respond to stop requests.” Even one long loop or wait that ignores the token turns into a service stuck forever showing “Stopping” in the SCM. This is the bug operations teams hate most: it blocks Windows Update restarts, and forces a manual kill every time a server has a planned shutdown. As in Chapter 4, check the token at every processing boundary, and pass a
CancellationTokeninto any long I/O operation. Since Ctrl+C exercises this exact stop flow when running from the console, we’d recommend adding “how many seconds after Ctrl+C does it finish” to your pre-release test checklist. - Prioritize a design that survives being killed over how polished the shutdown handling is. A power loss or a forced termination happens no matter how carefully you build shutdown handling. Transactions, atomic file writes, rerunnable units of work — a design where “even if it dies mid-way, consistency is restored on the next startup” is the real substance; graceful shutdown handling is ultimately just good manners.
8. Summary
The decision is simple. Periodic processing goes to Task Scheduler; if you need constant listening, second-level response, or automatic recovery, use a Windows service; if the UI is the whole point, use a resident app. Once you’ve decided to make it a service, the current standard route is the .NET Worker Service template with AddWindowsService: “develop as a console app, ship as a service.”
There are four things to design at registration time: the start type (delayed start for a business service), the service account (avoid LocalSystem — use a virtual account or gMSA), recovery options (sc.exe failure paired with Environment.Exit(1)), and shutdown (ShutdownTimeout and cleaning up in-flight work). Get these four things right, along with writing ExecuteAsync to respect stoppingToken, and a Windows service stops being “something especially hard to build.” Conversely, a service that started running without these four decisions made will come back years later with a triple curse: it can’t be stopped, nobody notices when it goes down, and it’s running with too much privilege to touch safely. Fixing up an existing service is also fastest to start by auditing these same four points.
Related Articles
- When Task Scheduler Tasks Don’t Run or Exit with 0x1 — Isolating the Cause and Designing for Reliable Operation
- What Is the .NET Generic Host?
- A Decision Table for Inter-Process Communication
- Designing Windows Apps to Leave Logs and Dumps When They Crash
Related Consulting Areas
KomuraSoft LLC handles consulting on design reviews for resident/background processing (including the decision of whether to migrate off Task Scheduler), and on investigating and rebuilding Windows services that “don’t respond to stop requests” or “go down without anyone noticing.”
References
-
Microsoft Learn, Interactive Services. Since Windows Vista, services cannot interact with the user directly, run in Session 0, and — when a UI is needed — the recommended design is a separate GUI app process that communicates with the service over IPC. ↩ ↩2 ↩3
-
Microsoft Learn, Create Windows Service using BackgroundService. The official tutorial on turning a Worker Service into a Windows service — covers
AddWindowsService, the EventLog provider’s default level of Warning, registering/recovering/removing viasc.exe, and that recovery options require a non-zero exit code. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 -
Microsoft Learn, .NET 6 breaking change: Exception handling in hosting. From .NET 6 onward, an unhandled exception in
BackgroundService.ExecuteAsyncis logged and, by default, stops the host (BackgroundServiceExceptionBehavior.StopHost). ↩ ↩2 -
Microsoft Learn, sc.exe create. The specification for
start=(auto / demand / delayed-auto, etc.) andobj=(default LocalSystem), and the requirement for a space after each option’s equals sign (omitting it causes the command to fail). ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Service Accounts in Windows Server. Covers virtual accounts (
NT SERVICE\service-name) accessing the network with computer-account credentials without any password management, and gMSA passwords being automatically managed on the domain side. ↩ ↩2 ↩3 -
Microsoft Learn, .NET Generic Host. Covers the host’s shutdown flow and the configurable shutdown timeout (default 30 seconds) it waits on during stop. ↩ ↩2
-
Microsoft Learn, A service does not start, and events 7000 and 7011 are logged. The SCM waits only as long as
ServicesPipeTimeoutfor a service to start, logging events 7000/7011 if that’s exceeded, plus the steps for raising the default timeout. ↩ -
Microsoft Learn, Service User Accounts. Covers services running in the security context of a specified account, the SCM logging on at start, a service failing to start once its password has expired, and the special LocalService / NetworkService / LocalSystem accounts. ↩ ↩2
-
Microsoft Learn, HostOptions.ShutdownTimeout Property. The definition of the property controlling the default timeout for
StopAsync. ↩
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Date, Time, and Timezones in Business Apps — From DateTime Pitfalls to the UTC-Storage Principle and Test Design
Timestamps drift by nine hours after a server migration; only the overseas office's dates roll back to the previous day — we trace date/t...
Choosing Windows Inter-Process Communication ── A Decision Table for Named Pipes / TCP / gRPC / Shared Memory / COM
How do you choose the right way for Windows applications to talk to each other? This article organizes named pipes, local TCP, gRPC, shar...
Using SQLite from C# in Business Apps — WAL Mode, Exclusive Locking, Corruption Countermeasures, and When to Reach for EF Core
A practical rundown of embedding SQLite into a business Windows app with Microsoft.Data.Sqlite: connection strings and pooling, how WAL m...
How to Choose Where a Windows App Stores Local Data — A Decision Table for SQLite / JSON / Registry / Access
Where — and in what format — should a Windows desktop app store its data? This article organizes the choice between AppData and ProgramDa...
How to Think About Windows Session Isolation — Session 0, RDP, and Running Multiple Users Concurrently
This article untangles the concept of a Windows "session," a topic that consistently confuses Windows app developers. It covers why Sessi...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Generic Host & App Architecture
Topic page for Generic Host, BackgroundService, DI, configuration, logging, and app lifetime design.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Author Profile
Profile page for the article author.
Go Komura
Representative of KomuraSoft LLC
Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.
Public links