You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不重启主程序更新DLL?附Updater类实现及相关问询

Answers to Your Updater Class Questions

Let's tackle your two questions and address your server dependency concern clearly, with practical code adjustments:


1. Can we check the DLL before it's used?

Absolutely—this is actually the optimal time to run your version check. By doing this before the DLL is loaded into the application domain, you avoid file lock issues that happen once the CLR has the DLL in use.

How to implement it:

Move your updater logic to the very start of your application, before any code that references types from the target DLL executes. For example, in your Program.Main method:

static void Main(string[] args)
{
    const string LOCAL_DLL_PATH = @"C:\MyApp\MyFeature.dll";
    const string SERVER_DLL_PATH = @"\\Server\AppUpdates\MyFeature.dll";

    // Run update check FIRST—before loading the DLL
    Updater updater = new Updater(LOCAL_DLL_PATH, SERVER_DLL_PATH);
    if (updater.IsAvailableNewerVersion)
    {
        updater.Update();
        // If you're using static references, you'll still need a restart here
        // But we'll cover how to skip that in the next section
    }

    // Now proceed to initialize your app and use the DLL
    StartMainApplication();
}

This ensures the DLL hasn't been locked yet, making the File.Copy operation in Update() far more reliable.


2. How to update the DLL without restarting the main program?

The core problem here is that once the CLR loads a DLL into an AppDomain, it locks the file and can't unload the assembly directly. To get around this, you need to use dynamic loading with isolated execution contexts (AppDomains for .NET Framework, or AssemblyLoadContext for .NET Core/.NET 5+).

Step-by-Step Solution:

a. Decouple with an Interface

First, create a shared assembly (like MyApp.Interfaces.dll) that only contains the interface for your DLL's functionality. Your main app references this interface assembly, not the actual DLL—this eliminates direct runtime dependency.

// In MyApp.Interfaces.dll
public interface IFeatureService : MarshalByRefObject // Required for cross-AppDomain calls (Framework only)
{
    void ExecuteFeature();
    string GetVersion();
}

b. Implement the Interface in Your DLL

Both your local and server-side DLLs implement this interface:

// In MyFeature.dll
public class FeatureService : IFeatureService
{
    public void ExecuteFeature()
    {
        MessageBox.Show("Running feature from DLL!");
    }

    public string GetVersion()
    {
        return Assembly.GetExecutingAssembly().Version.ToString();
    }
}

c. Use Isolated Contexts for Loading

For .NET Framework: Use AppDomains

Create a loader class that manages a separate AppDomain for the DLL—this lets you unload the domain to release the file lock when updating:

public class FeatureLoader : IDisposable
{
    private AppDomain _featureDomain;
    private IFeatureService _featureInstance;

    public IFeatureService LoadFeature(string dllPath)
    {
        var domainSetup = new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(dllPath) };
        _featureDomain = AppDomain.CreateDomain("FeatureDomain", null, domainSetup);

        // Load DLL and create instance
        _featureInstance = (IFeatureService)_featureDomain.CreateInstanceFromAndUnwrap(
            dllPath,
            "MyFeature.FeatureService" // Full type name of your implementation
        );

        return _featureInstance;
    }

    public void UnloadFeature()
    {
        if (_featureDomain != null)
        {
            AppDomain.Unload(_featureDomain);
            _featureDomain = null;
            _featureInstance = null;
        }
    }

    public void Dispose() => UnloadFeature();
}
For .NET Core/.NET 5+: Use AssemblyLoadContext

This is the modern alternative to AppDomains, designed specifically for dynamic assembly loading/unloading:

public class FeatureLoadContext : AssemblyLoadContext
{
    public FeatureLoadContext() : base(isCollectible: true) { }

    protected override Assembly Load(AssemblyName assemblyName)
    {
        // Load dependencies here if needed, or return null to use the default context
        return null;
    }
}

d. Integrate with Your Updater

Now you can update and reload the DLL without restarting:

static void Main(string[] args)
{
    const string LOCAL_DLL_PATH = @"C:\MyApp\MyFeature.dll";
    const string SERVER_DLL_PATH = @"\\Server\AppUpdates\MyFeature.dll";

    while (true) // Example loop for periodic checks
    {
        // Check for updates
        Updater updater = new Updater(LOCAL_DLL_PATH, SERVER_DLL_PATH);
        if (updater.IsAvailableNewerVersion)
        {
            // Unload existing DLL to release file lock
            using (var loader = new FeatureLoader()) // Use FeatureLoadContext for .NET Core
            {
                loader.UnloadFeature();
            }

            // Update the DLL safely
            updater.Update();
            MessageBox.Show("DLL updated! Reloading feature...");
        }

        // Load and use the updated DLL
        using (var loader = new FeatureLoader())
        {
            var feature = loader.LoadFeature(LOCAL_DLL_PATH);
            MessageBox.Show($"Loaded DLL version: {feature.GetVersion()}");
            feature.ExecuteFeature();
        }

        // Wait before next check (adjust timing as needed)
        Thread.Sleep(60000);
    }
}

Addressing Your Server Dependency Concern

Using the dynamic loading approach above means you never need to directly reference the server-side DLL. You only download the latest version locally once, then use the local copy for runtime execution. The server is only contacted for version checks and updates, not for ongoing runtime dependency—keeping your app functional offline after the latest DLL is downloaded.


内容的提问来源于stack exchange,提问作者HelloWorld

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:45:34