Skip to main content

πŸš€ GeneralUpdate Integration Guide

Helps developers integrate GeneralUpdate auto-update into any .NET application. Start from scratch β€” no prior knowledge of GeneralUpdate internals required.


First: Why do you need two programs?​

GeneralUpdate uses a dual-process architecture. Understanding this is key to everything else:

Your App.exe (Client β€” main application)
β”‚
β”œβ”€β”€ Normally: runs your business logic
β”‚
β”œβ”€β”€ When an update is found:
β”‚ 1. Downloads the update package
β”‚ 2. Writes download info to an IPC file (temporary file)
β”‚ 3. Launches the "upgrade program" (UpgradeApp.exe)
β”‚ 4. Exits itself (Windows won't let a program overwrite itself)
β”‚
β–Ό
UpgradeApp.exe (Upgrade β€” update installer)
β”‚
β”œβ”€β”€ Reads the IPC file
β”œβ”€β”€ Extracts/replaces files (main program has exited, files are free)
β”œβ”€β”€ Launches the main program
└── Exits itself

IPC file (Inter-Process Communication) = a temporary file. The Client writes update info into it; the Upgrade reads it to perform the actual update.

manifest.json = a manifest file that tells GeneralUpdate what your main program is called and where the upgrade program lives.

The reason is simple: Windows doesn't allow a running program to overwrite its own .exe, so a separate "helper" process is needed to do the file replacement.


What you'll need​

1. Your .NET project (WPF / WinForms / Avalonia / MAUI / Console β€” any works)
2. .NET SDK (8.0+)
3. A backend service (optional β€” you can use OSS object storage instead)

Install NuGet​

dotnet add package GeneralUpdate.Core --version 10.5.0-beta.7

If you need the crash daemon (Bowl), add one more package: dotnet add package GeneralUpdate.Bowl --version 10.5.0-beta.7
Differential update is built into Core β€” no need for a separate GeneralUpdate.Differential package.


Minimum setup: 3 lines to get it running​

This is the simplest integration, suitable for console apps or just verifying functionality:

using GeneralUpdate.Core;
using GeneralUpdate.Core.Configuration;

var config = new UpdateRequest
{
UpdateUrl = "https://your-server.com/api", // Server API endpoint
AppSecretKey = "your-secret-key", // Secret key (β‰₯ 16 chars)
MainAppName = "MyApp.exe", // Your main program filename
ClientVersion = "1.0.0.0", // Current version
ProductId = "my-product-001", // Your product ID
InstallPath = "." // Install directory (. = current dir)
};

await new GeneralUpdateBootstrap().SetConfig(config).LaunchAsync();

These 6 fields are required β€” missing any will cause an error:

FieldWhat to putWhy it's needed
UpdateUrlServer API URLThe program queries this for new versions
AppSecretKeyYour chosen keyUsed for IPC encrypted communication; must match between Client & Upgrade
MainAppName"MyApp.exe"Tells the Upgrade which exe to launch after updating
ClientVersion"1.0.0.0"Server uses this to decide which versions to send
ProductId"my-app-001"Differentiates products (if you have multiple apps)
InstallPath"."Where to extract update packages

Full setup: with event listeners​

If you want to see download progress, handle errors, or add logging, attach event listeners:

using GeneralUpdate.Core;
using GeneralUpdate.Core.Configuration;
using GeneralUpdate.Core.Download;

var config = new UpdateRequest
{
UpdateUrl = "https://your-server.com/Upgrade/Verification",
AppSecretKey = "your-secret-key",
MainAppName = "MyApp.exe",
ClientVersion = "1.0.0.0",
ProductId = "my-product-001",
InstallPath = AppDomain.CurrentDomain.BaseDirectory, // Use this in production
};

await new GeneralUpdateBootstrap()
.SetConfig(config)
.AddListenerUpdateInfo((_, e) =>
{
// Fires when update info is available
Console.WriteLine($"Found {e.Info?.Body?.Count ?? 0} versions");
})
.AddListenerMultiDownloadStatistics((_, e) =>
{
// Download progress (bind to your progress bar)
Console.WriteLine($"Progress: {e.ProgressPercentage}% | Speed: {e.Speed}");
})
.AddListenerMultiDownloadCompleted((_, e) =>
{
Console.WriteLine($"Version {e.Version} downloaded");
})
.AddListenerMultiDownloadError((_, e) =>
{
Console.WriteLine($"Download failed: {e.Exception?.Message}");
})
.AddListenerMultiAllDownloadCompleted((_, e) =>
{
Console.WriteLine("All downloads complete, starting update");
})
.AddListenerException((_, e) =>
{
Console.WriteLine($"Error: {e.Message}");
})
.AddListenerProgress((_, e) =>
{
// v10.5.0-beta.7 new β€” the 7th event
})
.LaunchAsync();

You usually only need 3 events: MultiDownloadStatistics (progress bar), MultiDownloadError (download failed), Exception (errors). Add others as needed.


UpdateRequest full reference​

Beyond the 6 required fields, these optional settings are available:

var config = new UpdateRequest
{
// === Required ===
UpdateUrl = "...", AppSecretKey = "...", MainAppName = "...",
ClientVersion = "1.0.0.0", ProductId = "...", InstallPath = ".",

// === Optional: Authentication ===
AuthScheme = AuthScheme.Hmac, // Hmac / Bearer / ApiKey / Basic
Token = "your-token",
BasicUsername = "user",
BasicPassword = "pass",

// === Optional: Files to exclude during backup ===
Files = new List<string> { "*.log", "*.tmp" },
Formats = new List<string> { ".pdb" },
Directories = new List<string> { "logs", "cache" },
};

You can also use the builder pattern (same result, more fluent syntax):

var config = UpdateRequestBuilder.Create()
.SetUpdateUrl("https://your-server.com/api")
.SetAppSecretKey("your-secret-key")
.SetMainAppName("MyApp.exe")
.SetClientVersion("1.0.0.0")
.SetProductId("my-product-001")
.SetInstallPath(".")
.Build();

Or use zero-config mode (auto-discovers from manifest.json):

await new GeneralUpdateBootstrap()
.SetSource(
updateUrl: "https://your-server.com/api",
appSecretKey: "your-secret-key")
.AddListenerUpdateInfo(...)
.LaunchAsync();

4 update scenarios (based on server response)​

GeneralUpdate auto-selects its action based on what the server returns:

ScenarioWhat happens
NoneNo update β†’ launch main program
UpgradeOnlyUpdate upgrade app only β†’ extract and overwrite
MainOnlyUpdate main app only β†’ download β†’ IPC β†’ Upgrade replaces files
BothUpdate both

Upgrade process configuration​

The Upgrade (installer) doesn't need configuration β€” it reads from the IPC file automatically:

using GeneralUpdate.Core;

await new GeneralUpdateBootstrap()
.AddListenerException((_, e) =>
Console.WriteLine($"Error: {e.Message}"))
.LaunchAsync();

Your project needs two separate projects: one Client (main app) and one Upgrade (installer).


Deployment checklist​

Your publish directory should look like:

publish/
β”œβ”€β”€ MyApp.exe ← Your main program
β”œβ”€β”€ generalupdate.manifest.json ← Update manifest
└── update/
└── UpgradeApp.exe ← Upgrade program (must exist from v1.0!)

The most common first-time mistake is forgetting to include UpgradeApp.exe, which makes updates impossible to execute.


App type reference​

AppType distinguishes the two processes:

ValueEnumWho uses it
1AppType.ClientMain program (your business code)
2AppType.UpgradeUpgrade program (UpgradeApp.exe)
3AppType.OssClientOSS main program
4AppType.OssUpgradeOSS upgrade program

Common beginner mistakes​

#MistakeConsequenceCorrect approach
1Client and Upgrade use different NuGet versionsMethod not found at runtimeBoth projects use the exact same version
2Forgot to include UpgradeApp.exeUpdate detected but can't executeInclude it in update/ from the first release
3IPC encoding not set to UTF-8Garbled text on Linux/macOSSet Encoding.UTF8
4Version not in 4-part format (e.g. 1.0)Version comparison breaksAlways use 1.0.0.0 format
5manifest.json exe name doesn't matchCan't find main program after updateMatch the actual filename exactly

Next steps​