c#-4.0 - 在不同线程上使用应用程序域 self 更新应用程序

标签 c#-4.0 task appdomain restart

我一直在努力让 Windows 服务在有新版本时自动重启应用程序。我的代码在下面,它确实有效。我的问题是:这里某处有很大的禁忌吗?我不熟悉在单独的线程上创建应用程序域,我想知道是否有更优雅的方法来完成此操作。我还担心我在处理这件事上可能有很大的盲点。任何建议表示赞赏。

有两个常规部分:运行的 Windows 服务,在不同的进程中启动我的应用程序,然后轮询以检测该应用程序的新版本何时可用。第二部分是启动、更新、重启的实际应用。

首先,当服务启动时,它会调用 LoadApp() 以便应用程序开始运行。

private void LoadApp()
    {
    // ** appDomainSetup here **

    this._appDomain = AppDomain.CreateDomain("MyUpdatedApp", AppDomain.CurrentDomain.Evidence, appDomainSetup);

    this._tokenSource = new CancellationTokenSource();

    Task.Factory.StartNew(() =>
    {
        try
        {
            this._appDomain.ExecuteAssembly(assembly);
        }
        catch (AppDomainUnloadedException ex)
        {
            Debug.WriteLine(ex.ToString());
        }
    }, _tokenSource.Token);
}

然后,每隔 10 秒,计时器调用此方法:

private void Process(object stateInfo)
{
    if (!Monitor.TryEnter(_locker)) { return; }

    try
    {
        // Check for new binaries. If new, copy the files and restart the app domain.            
        if (!NewAppVersionReady()) { return; }
        DeleteFiles();
        CopyFiles();
        RestartAppDomain();
    }
    finally
    {
        Monitor.Exit(_locker);
    }
}

RestartAppDomain() 看起来像这样。请注意,当我在此方法的第二行卸载应用程序域时出现异常。 (我通过捕获异常并基本上忽略它来解决这个问题。)

private void RestartAppDomain()
{
    this._tokenSource.Cancel();
    AppDomain.Unload(this._appDomain);
    LoadApp();
}

编辑:我后来发现 AppDomain.Unload() 行是不必要的。没有它,该服务仍会使用新版本更新应用程序,然后启动新版本的应用程序。我最关心的是在 token 源上调用 Cancel()。我希望应用能够正常关闭,而不是强制关闭。

最佳答案

通过反复试验和学习,我似乎已经确定了一个不错的解决方案。我想我会把它贴在这里以防它对其他人有帮助。

首先,我在一个单独的项目中创建了一个接口(interface),因此 self 更新的应用程序不必引用实际在其自己的应用程序域中运行的应用程序。使用此接口(interface),以便 self 更新的应用程序可以调用其他应用程序上的启动和停止。

public interface IStartStop
{
    void Start();
    void Stop();
}

在单独域中运行的应用程序中,我让类从 MarshalByRefObject 派生,并实现 IStartStop。

public class PrestoTaskRunnerController : MarshalByRefObject, IStartStop, IDisposable

这允许我从我的 self 更新应用程序启动和停止这个应用程序:

this._appDomain = AppDomain.CreateDomain(this._appName, AppDomain.CurrentDomain.Evidence, appDomainSetup);
this._startStopControllerToRun = (IStartStop)this._appDomain.CreateInstanceFromAndUnwrap(assemblyName, this._fullyQualifiedClassName);
this._startStopControllerToRun.Start();

停止它是这样完成的:

this._startStopControllerToRun.Stop();
AppDomain.Unload(this._appDomain);

还有一些细节,但这是一般概念,而且似乎运作良好。

关于c#-4.0 - 在不同线程上使用应用程序域 self 更新应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8538659/

相关文章:

c# - 类型推断推断的是类的范围,而不是方法,尽管它们是相同的?

c# - 我可以在现有方法中发出 CIL 吗?

c# - 改进任务代码以实现异步等待

c# - Task.WhenAll 未完成

.net - 如何使用 Reflection.Emit 注入(inject)文字表达式?

C#通过反射设置对象DateTime属性值

C#、MVVM、任务和 UI 线程

.NET 应用程序域和 ASP.NET

c# - 跨AppDomains时无法将对象类型转换为目标类型

.net - 即时修改 IL 代码