Skip to main content

GeneralUpdate.Extension — Execution Flow Deep Dive

Target Audience: Developers who need to understand Extension's internal management engine

After reading you will understand:

  • GeneralExtensionHost's DI injection architecture and legacy compatibility mode
  • The complete nine-stage execution chain of UpdateExtensionAsync
  • DependencyResolver's topological sorting and circular dependency detection
  • Version compatibility checking and platform matching decision logic
  • InstallExtensionAsync's backup → cleanup → extract → atomic write flow
  • Zip Slip path traversal protection implementation details
  • Extension Catalog's atomic write and crash-safe design
  • DownloadQueueManager's concurrency control
  • IExtensionLifecycleHooks' 8 event injection points

Table of Contents​

  1. Architecture Overview
  2. Entry: GeneralExtensionHost's Dual Constructor Design
  3. ExtensionHostBuilder: DI Builder Pattern
  4. UpdateExtensionAsync: One-Click Update Complete Flow
  5. Dependency Resolution: DependencyResolver Deep Dive
  6. Compatibility Checks: Version + Platform Dual Validation
  7. Download: DownloadQueueManager Concurrency Control
  8. Install: InstallExtensionAsync Security Guarantees
  9. Catalog: Atomic Writes & Crash Safety
  10. Lifecycle Hooks: 8 Event Injection Points
  11. Key Code Path Index

1. Architecture Overview​

1.1 Six-Layer Service Architecture​

Extension uses a DI + Builder pattern design where all services are replaceable:

┌──────────────────────────────────────────────────────────────┐
│ GeneralExtensionHost (Orchestration Layer) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ IExtension │ │ IExtension │ │ IVersion │ │
│ │ HttpClient │ │ Catalog │ │ Compatibility │ │
│ │ Server API │ │ Local │ │ Checker │ │
│ │ communication │ │ manifest │ │ Version check │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ IDownload │ │ IDependency │ │ IPlatformMatcher │ │
│ │ QueueManager │ │ Resolver │ │ Platform match │ │
│ │ Concurrency │ │ Topo sort │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ IExtensionLifecycleHooks (Optional) │ │
│ │ Before/After Install, Activate, Deactivate, Uninstall │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘

1.2 Core Design Principles​

PrincipleDescription
Full DI ReplaceabilityEvery service has an interface, injected via constructor, testable
Builder PatternExtensionHostBuilder provides fluent config API with ConfigureServices
Legacy CompatibilityParameterless constructor auto-creates defaults, old code unchanged
Atomic WritesCatalog manifest.json writes to .tmp then renames, crash-safe
Zip Slip ProtectionSafeExtractZipAsync validates each entry's destination path
Recursive Dependency InstallMissing dependencies auto-trigger recursive UpdateExtensionAsync

2. Entry: GeneralExtensionHost's Dual Constructor Design​

public GeneralExtensionHost(
ExtensionHostOptions options,
IExtensionHttpClient httpClient,
IExtensionCatalog catalog,
IVersionCompatibilityChecker compatibilityChecker,
IDownloadQueueManager downloadQueue,
IDependencyResolver dependencyResolver,
IPlatformMatcher platformMatcher,
IExtensionLifecycleHooks? lifecycleHooks = null,
IExtensionMetadataMapper? metadataMapper = null)

Legacy Constructor (Backward Compatible)​

public GeneralExtensionHost(ExtensionHostOptions options)
{
// Auto-creates default implementations
_httpClient = new ExtensionHttpClient(options.ServerUrl, ...);
ExtensionCatalog = new ExtensionCatalog(options.CatalogPath ?? options.ExtensionsDirectory);
_compatibilityChecker = new VersionCompatibilityChecker();
_downloadQueue = new DownloadQueueManager();
_dependencyResolver = new DependencyResolver(ExtensionCatalog);
_platformMatcher = new PlatformMatcher();
}

3. ExtensionHostBuilder: DI Builder Pattern​

var host = new ExtensionHostBuilder()
.ConfigureOptions(options => {
options.HostVersion = "2.0.0";
options.ExtensionsDirectory = "./extensions";
options.ServerUrl = "https://api.example.com";
})
.ConfigureServices(services => {
services.AddSingleton<IExtensionHttpClient, CustomHttpClient>();
services.AddSingleton<IExtensionLifecycleHooks, MyLifecycleHooks>();
})
.Build();

4. UpdateExtensionAsync: One-Click Update Complete Flow​

This is Extension's core method, chaining: query → compatibility → platform → dependency recursion → download → hash verify → safe install → catalog update → event notification.

Nine Stages Summary​

StageOperationFailure Behavior
①Notify Queued—
②Query ServerThrow
③Version CompatibilityThrow
④Platform MatchThrow
⑤Dependency ResolutionRecursive install
⑥DownloadThrow
⑦SHA256 VerifyDelete file, throw
⑧Safe InstallRollback on failure
⑨Catalog UpdateAtomic write

5. Dependency Resolution: DependencyResolver Deep Dive​

Topological Sort​

public List<string> GetTransitiveDependencies(List<string> directDependencies)
{
// 1. Build dependency graph (adjacency list)
// 2. Kahn's algorithm for topological sort
// 3. Detect circular dependencies (A → B → A)
// 4. Return install order (dependencies first)
}

Dependency Install Decision Tree​

sortedDeps = DependencyResolver.GetTransitiveDependencies(deps)
missingDeps = sortedDeps.Where(d => Catalog.GetInstalledExtensionById(d) == null)

foreach dep in sortedDeps:
if dep is missing:
await UpdateExtensionAsync(dep) // Recursive install

6. Compatibility Checks: Version + Platform Dual Validation​

Version Compatibility (SemVer 2.0)​

ConditionResult
HostVersion < MinHostVersion❌ Host too old
HostVersion > MaxHostVersion❌ Host too new
MinHostVersion ≤ HostVersion ≤ MaxHostVersion✅ Compatible

Platform Matching (Flag Enum)​

[Flags]
public enum TargetPlatform
{
Windows = 1, Linux = 2, macOS = 4, Android = 8, iOS = 16
}

PlatformMatcher uses bitwise AND: (metadata.SupportedPlatforms & currentPlatform) != 0.


7. Download: DownloadQueueManager Concurrency Control​

Uses SemaphoreSlim(3) for max 3 concurrent downloads. Dispatches actual download via DownloadHandler delegate → _httpClient.DownloadExtensionAsync().


8. Install: InstallExtensionAsync Security Guarantees​

Install Flow​

  1. Validate file exists and is .zip
  2. Parse extension name from filename
  3. OnBeforeInstallAsync hook (can cancel)
  4. Backup existing version to .backup/{name}_{timestamp}
  5. Remove old directory
  6. SafeExtractZipAsync (Zip Slip protected)
  7. On success: delete backup; On failure: restore from backup
  8. OnAfterInstallAsync hook

Zip Slip Protection​

var fullDestDir = Path.GetFullPath(destinationDir);
foreach (var entry in archive.Entries)
{
var destinationPath = Path.GetFullPath(Path.Combine(fullDestDir, entry.FullName));
if (!destinationPath.StartsWith(fullDestDir + Path.DirectorySeparatorChar)
&& destinationPath != fullDestDir)
{
continue; // Skip malicious entries attempting path traversal
}
entry.ExtractToFile(destinationPath, overwrite: true);
}

9. Catalog: Atomic Writes & Crash Safety​

// Write temp file first, then atomic rename
var tempPath = manifestPath + ".tmp";
File.WriteAllText(tempPath, json);
File.Move(tempPath, manifestPath, overwrite: true);

Why safe: If crash occurs during WriteAllText(tempPath) → manifest.json untouched. If during File.Move → filesystem guarantees rename atomicity.


10. Lifecycle Hooks: 8 Event Injection Points​

public interface IExtensionLifecycleHooks
{
Task<bool> OnBeforeInstallAsync(ExtensionMetadata metadata, string packagePath);
Task OnAfterInstallAsync(ExtensionMetadata metadata);
Task OnBeforeActivateAsync(string extensionId, CancellationToken ct);
Task OnAfterActivateAsync(string extensionId, CancellationToken ct);
Task OnBeforeDeactivateAsync(string extensionId, CancellationToken ct);
Task OnAfterDeactivateAsync(string extensionId, CancellationToken ct);
Task<bool> OnBeforeUninstallAsync(ExtensionMetadata metadata, CancellationToken ct);
Task OnAfterUninstallAsync(string extensionId, CancellationToken ct);
}

Return value semantics: OnBeforeInstallAsync and OnBeforeUninstallAsync returning false cancels the operation. All After hooks are notification-only.


11. Key Code Path Index​

ComponentFileKey Methods
Extension HostCore/GeneralExtensionHost.csUpdateExtensionAsync() / InstallExtensionAsync() / SafeExtractZipAsync()
BuilderCore/ExtensionHostBuilder.csConfigureOptions() / ConfigureServices() / Build()
Lifecycle HooksCore/IExtensionLifecycleHooks.cs8 hook methods
CatalogCatalog/ExtensionCatalog.csAddOrUpdateInstalledExtension() / LoadInstalledExtensions()
Download QueueDownload/DownloadQueueManager.csSemaphoreSlim concurrency
Dependency ResolverDependencies/DependencyResolver.csGetTransitiveDependencies()
Platform MatcherCompatibility/PlatformMatcher.csIsCurrentPlatformSupported()
Version CheckerCompatibility/VersionCompatibilityChecker.csIsCompatible()
HTTP ClientCommunication/ExtensionHttpClient.csQueryExtensionsAsync() / DownloadExtensionAsync()