Updater Application Block实践

2024-02-21 08:08

本文主要是介绍Updater Application Block实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Step #1 Install the Application Blocks 安装自动更新组件

Download the Updater Application Block from Microsoft.

Step #2 Add the Code and References to Your Project: 添加代码和引用到工程

Add the following projects to the solution containing your Winforms project :

把以下工程添加到你的解决方案

Microsoft.ApplicationBlocks.ApplicationUpdater
Microsoft.ApplicationBlocks.ApplicationUpdater.Interfaces
Microsoft.ApplicationBlocks.ExceptionManagement
Microsoft.ApplicationBlocks.ExceptionManagement.Interfaces

They should be located in the following folder, if you've accepted the defaults 默认的安装位置在

C:/Program Files/Microsoft Application Blocks for .NET/Updater/Code/CS/Microsoft.ApplicationBlocks.Updater

Reference the following projects from within your Winforms Project 在工程中添加引用

Microsoft.ApplicationBlocks.ApplicationUpdater
Microsoft.ApplicationBlocks.ApplicationUpdater.Interfaces
Microsoft.ApplicationBlocks.ExceptionManagement

Add the following namespaces to your form's .cs file.

using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Xml;

using Microsoft.ApplicationBlocks.ApplicationUpdater; 工程要引用其中的类

Then add the application updater code located here to your code. You'll need to call InitializeAutoUpdate() from your MainForm's Initialize method.把以下代码添加到工程首页。

Step #3 Create your Application's Deployment Directory Structure and Configure AppStart.exe 创建发布目录并配置配置文件

Create a folder for your client installation. For example purposes, we'll use the following directory: 创建客户端安装目录,如:

C:/Program Files/YourApp/1.0.0.0/

Now copy the AppStart.exe and AppStart.exe.config into the root directory like so: 把以下两个文件拷贝到安装的根目录(C:/Program Files/YourApp)

C:/Program Files/YourApp/AppStart.exe
C:/Program Files/YourApp/AppStart.exe.config

Note: You can find these two files in the “C:/Program Files/Microsoft Application Blocks for .NET/Updater/Code/CS/Microsoft.ApplicationBlocks.Updater/AppStart/bin/Debug“ directory.

Step #4 Modify the AppStart.exe.config File 修改配置文件AppStart.exe.config

Appstart.exe.config将负责启动你的程序。

Modify this config file to match the current version like so: 按照你程序的当前版本配置此文件:


<appStart>
<ClientApplicationInfo>
<appFolderName>C:/Program Files/YourApp/1.0.0.0</appFolderName>
<appExeName>YourAppName.exe</appExeName>
<installedVersion>1.0.0.0</installedVersion>
<lastUpdated>2004-06-10T15:33:17.3745836-04:00</lastUpdated>
</ClientApplicationInfo>
</appStart>



Step #5: Create Your Public and Private Keys 创建公匙和私匙

Run the ManifestUtility "C:/Program Files/Microsoft Application Blocks for .NET/Updater/Code/CS/Microsoft.ApplicationBlocks.Updater/ManifestUtility/bin/Debug/ManifestUtility.exe"

Choose “File..Generate Keys” You will be prompted to save the following keys: PublicKey.xml and PrivateKey.xml You'll be using these keys in the next steps.

From what I can tell it's best to create these keys once, because you'll need to reference these RSA public and private keys in a couple of places. You'll want to keep your keys in a safe place, because you'll need them when pushing new updates.

此工具生成成对的公匙和私匙。

Step #6 Create Your IIS Virtual Directory

Create a directory on your WebServer to house your updates. You will end up with two things in this directory

1) a ServerManifest.xml file which will contain the latest version information, and

2) your new application directory. Within this directory, create a directory to house your new application version. So, for our example, we'll create the directories, C:/Inetpub/AppUpdates and C:/Inetpub/AppUpdates/1.0.0.1

Use IIS Manager to create a virtual directory pointing to this physical directory. Remember your URL, as you will need it in an upcoming step. You will have to enable directory browsing for this virtual directory.

创建IIS的虚拟目录,在此存放你的新程序版本,例如:

C:/Inetpub/AppUpdates 包括你新版本程序的信息的配置文件将放在此目录

C:/Inetpub/AppUpdates/1.0.0.1 新版本的程序放在此目录

Step #7. Configure Your Version 1.0.0.0 App.config File 配置你程序的配置文件(你的程序名.config即完整程序名加.config例如:App01.exe.config 程序将默认寻找与其同名的.config配置文件,{DLL没有此项功能})

Here, we'll need to add a few things. First, we need to add a configSections element to define our appUpdater section:


<configSections>
<section name="appUpdater" type="Microsoft.ApplicationBlocks.ApplicationUpdater.UpdaterSectionHandler,Microsoft.ApplicationBlocks.ApplicationUpdater" />
</configSections>

Next we need to add the Version key to our appsettings key, we're first going to set our local versoin to 1.0.0.0, so that we can test the auto-update to version 1.0.0.1

<appSettings>
<add key="VERSION" value="1.0.0.0" /> 注意版本号一定要与程序的设定的版本号匹配
</appSettings>

Finally, add the appUpdater section to your config file. I've put brackets where you need to edit the values. You can just copy the <RSAKeyValue> element from the PublicKey.xml file that you created in the previous step. 把刚才生成的公匙填到配置文件的相应位置,(以下[]中)。

<appUpdater>
<UpdaterConfiguration>
<polling type="Seconds" value="120" />
<logListener logPath="C:/Program Files/YourApp/UpdaterLog.txt" />
<downloader type="Microsoft.ApplicationBlocks.ApplicationUpdater.Downloaders.BITSDownloader"
assembly="Microsoft.ApplicationBlocks.ApplicationUpdater,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/>
<validator type="Microsoft.ApplicationBlocks.ApplicationUpdater.Validators.RSAValidator" assembly="Microsoft.ApplicationBlocks.ApplicationUpdater,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null">
<key>
<RSAKeyValue>
<Modulus>[YOUR MODULUS KEY]</Modulus>
<Exponent>[YOUR EXPONENET]</Exponent>
</RSAKeyValue>
</key>
</validator>
<application name="[YOUR APP NAME]" useValidation="true"> 此处是你程序的名称,如App01,无需后缀
<client>
<baseDir>C:/Program Files/YourApp</baseDir>
<xmlFile>C:/Program Files/YourApp/AppStart.exe.config</xmlFile>
<tempDir>C:/Program Files/YourApp/temp</tempDir>
</client>
<server>
<xmlFile>http://[YOUR URL]/ServerManifest.xml</xmlFile>
<xmlFileDest>C:/Program Files/YourApp/ServerManifest.xml</xmlFileDest>
<maxWaitXmlFile>60000</maxWaitXmlFile>
</server>
</application>
</UpdaterConfiguration>
</appUpdater>

Step #8 Deploy Version 1.0.0.0 发布版本1.0.0.0


Version your app. You do this by setting the version attribute of your app's AssemblyInfo.cs file. 修改你程序的版本号(在AssemblyInfo.cs中)

[assembly: AssemblyVersion("1.0.0.0")]

Build the Application and copy version 1.0.0.0 to your program file's 1.0.0.0 directory. “C:/Program Files/YourApp/1.0.0.0“将版本1.0.0.0拷贝到你的客户端安装目录(注意,在版本号下1.0.0.0)

At this point, you should be able to run AppStart.exe. The update process should fail, since we haven't deployed the ServerManifest XML file which tells our app that there's a new version available. You can inspect the log files that should be created in your C:/Program Files/YourApp/ directory.

Step #9 Buld Version 1.0.0.1 创建新版本1.0.0.1

将新版本拷贝到你的发布目录,在step #6创建的C:/Inetpub/AppUpdates/1.0.0.1下

注意同时拷贝到发布目录的还应该有:配置文件 App01.exe.config

因为可能找不到微软的组件,以下几个文件也一同拷贝,(否则升级时可能会报错system.io.filenotfoundException的错误,找不到相应的文件)

Microsoft.ApplicationBlocks.ApplicationUpdater.dll
Microsoft.ApplicationBlocks.ApplicationUpdater.Interfaces.dll
Microsoft.ApplicationBlocks.ExceptionManagement.dll
Microsoft.ApplicationBlocks.ExceptionManagement.Interfaces.dll

注意以上文件都在版本号的目录下,C:/Inetpub/AppUpdates/1.0.0.1

Step #10 Create Your Server Manifest File 生成服务端的升级说明文件

This should be the last step. Any changes you make to the .config files from this point on will require repeating this step. To do this:

Launch the ManifestUtility program again. 再次用工具 ManifestUtility (step #5中的工具)
Choose the 1.0.0.1 directory from the “Update files folder“ chooser. 选择新版本程序的目录(注意是带版本号的目录)
Enter the URL of the update location. 新版本的HTTP的址(注意带版本号的目录)
Enter version 1.0.0.1 新的程序版本号
Open your PrivateKey.xml file created earlier. Key处添加你刚才生成的私匙
Choose the validator class 选择校验类为RSA的“Microsoft.ApplicationBlocks.ApplicationUpdater.Validators.RSAValidator”
Click CreateManifest, and save the ServerManifest.xml file to your virtual server directory. 生成新版本说明文件,存放在虚拟目录下(注意是不带版本号的,C:/Inetpub/AppUpdates/)
生成的ServerManifest.xml文件中说明了要升级的文件的内容,1.0.0.1下的内容都将下载。

step 2 的代码
#region Auto-Update Stuff

private ApplicationUpdateManager _updater = null;
private Thread _updaterThread = null;
private const int UPDATERTHREAD_JOIN_TIMEOUT = 3 * 1000;

private delegate void MarshalEventDelegate( object sender, UpdaterActionEventArgs e );

private void InitializeAutoUpdate()
{
// hook ProcessExit for a chance to clean up when closed peremptorily
AppDomain.CurrentDomain.ProcessExit +=new EventHandler(CurrentDomain_ProcessExit);

// make an Updater for use in-process with us
_updater = new ApplicationUpdateManager();

// hook Updater events
_updater.DownloadStarted +=new UpdaterActionEventHandler( OnUpdaterDownloadStarted );
_updater.FilesValidated +=new UpdaterActionEventHandler( OnUpdaterFilesValidated );
_updater.UpdateAvailable +=new UpdaterActionEventHandler( OnUpdaterUpdateAvailable );
_updater.DownloadCompleted +=new UpdaterActionEventHandler(OnUpdaterDownloadCompleted);

// start the updater on a separate thread so that our UI remains responsive
_updaterThread = new Thread( new ThreadStart( _updater.StartUpdater ) );
_updaterThread.Start();

// get version from config, set caption correctly
string version = System.Configuration.ConfigurationSettings.AppSettings["version"];
this.Text = this.Text + String.Format(" v. {0}", version);
}

private void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
StopUpdater();
}


private void StopUpdater()
{
// tell updater to stop
_updater.StopUpdater();
if( null != _updaterThread )
{
// join the updater thread with a suitable timeout
bool isThreadJoined = _updaterThread.Join( UPDATERTHREAD_JOIN_TIMEOUT );
// check if we joined, if we didn't interrupt the thread
if( !isThreadJoined )
{
_updaterThread.Interrupt();
}
_updaterThread = null;
}
}

/// <summary>
/// This handler gets fired by the Windows UI thread that is the main STA thread for THIS FORM. It takes the same
/// arguments as the event handler below it--sender, e--and acts on them using the main thread NOT the eventing thread
/// </summary>
/// <param name="sender">marshalled reference to the original event's sender argument</param>
/// <param name="e">marshalled reference to the original event's args</param>
private void OnUpdaterDownloadStartedHandler( object sender, UpdaterActionEventArgs e )
{
Debug.WriteLine("Thread: " + Thread.CurrentThread.GetHashCode().ToString());

Debug.WriteLine(String.Format( " DownloadStarted for application '{0}'", e.ApplicationName ));
}


/// <summary>
/// Event handler for Updater event. This event is fired by the originating thread from "inside" the Updater. While it is
/// possible for this same thread to act on our UI, it is NOT a good thing to do--UI is not threadsafe.
/// Therefore here we marshal from the Eventing thread (belongs to Updater) to our window thread using the synchronous Invoke
/// mechanism.
/// </summary>
/// <param name="sender">event sender in this case ApplicationUpdaterManager</param>
/// <param name="e">the UpdaterActionEventArgs packaged by Updater, which gives us access to update information</param>
private void OnUpdaterDownloadStarted( object sender, UpdaterActionEventArgs e )
{
// using the synchronous "Invoke". This marshals from the eventing thread--which comes from the Updater and should not
// be allowed to enter and "touch" the UI's window thread
// so we use Invoke which allows us to block the Updater thread at will while only allowing window thread to update UI
Debug.WriteLine( String.Format( "[OnUpdaterDownloadStarted]Thread: {0}", Thread.CurrentThread.GetHashCode().ToString()) );
this.Invoke(
new MarshalEventDelegate( this.OnUpdaterDownloadStartedHandler ),
new object[] { sender, e } );
}


/// <summary>
/// This handler gets fired by the Windows UI thread that is the main STA thread for THIS FORM. It takes the same
/// arguments as the event handler below it--sender, e--and acts on them using the main thread NOT the eventing thread
/// </summary>
/// <param name="sender">marshalled reference to the original event's sender argument</param>
/// <param name="e">marshalled reference to the original event's args</param>
private void OnUpdaterFilesValidatedHandler( object sender, UpdaterActionEventArgs e )
{
Debug.WriteLine(String.Format("FilesValidated successfully for application '{0}' ", e.ApplicationName));

// ask user to use new app
DialogResult dialog = MessageBox.Show(
"Would you like to stop this application and open the new version?", "Open New Version?", MessageBoxButtons.YesNo );
if( DialogResult.Yes == dialog )
{
StartNewVersion( e.ServerInformation );
}
}

/// <summary>
/// Event handler for Updater event. This event is fired by the originating thread from "inside" the Updater. While it is
/// possible for this same thread to act on our UI, it is NOT a good thing to do--UI is not threadsafe.
/// Therefore here we marshal from the Eventing thread (belongs to Updater) to our window thread using the synchronous Invoke
/// mechanism.
/// </summary>
/// <param name="sender">event sender in this case ApplicationUpdaterManager</param>
/// <param name="e">the UpdaterActionEventArgs packaged by Updater, which gives us access to update information</param>
private void OnUpdaterFilesValidated( object sender, UpdaterActionEventArgs e )
{
// using the asynchronous "BeginInvoke".
// we don't need/want to block here
this.BeginInvoke(
new MarshalEventDelegate( this.OnUpdaterFilesValidatedHandler ),
new object[] { sender, e } );
}

/// <summary>
/// This handler gets fired by the Windows UI thread that is the main STA thread for THIS FORM. It takes the same
/// arguments as the event handler below it--sender, e--and acts on them using the main thread NOT the eventing thread
/// </summary>
/// <param name="sender">marshalled reference to the original event's sender argument</param>
/// <param name="e">marshalled reference to the original event's args</param>
private void OnUpdaterUpdateAvailableHandler( object sender, UpdaterActionEventArgs e )
{
Debug.WriteLine("Thread: " + Thread.CurrentThread.GetHashCode().ToString());

string message = String.Format(
"Update available: The new version on the server is {0} and current version is {1} would you like to upgrade?",
e.ServerInformation.AvailableVersion,
System.Configuration.ConfigurationSettings.AppSettings["version"] ) ;

// for update available we actually WANT to block the downloading thread so we can refuse an update
// and reset until next polling cycle;
// NOTE that we don't block the thread _in the UI_, we have it blocked at the marshalling dispatcher "OnUpdaterUpdateAvailable"
DialogResult dialog = MessageBox.Show( message, "Update Available", MessageBoxButtons.YesNo );

if( DialogResult.No == dialog )
{
// if no, stop the updater for this app
_updater.StopUpdater( e.ApplicationName );
Debug.WriteLine("Update Cancelled.");
}
else
{
Debug.WriteLine("Update in progress.");
}
}

/// <summary>
/// Event handler for Updater event. This event is fired by the originating thread from "inside" the Updater. While it is
/// possible for this same thread to act on our UI, it is NOT a good thing to do--UI is not threadsafe.
/// Therefore here we marshal from the Eventing thread (belongs to Updater) to our window thread using the synchronous Invoke
/// mechanism.
/// </summary>
/// <param name="sender">event sender in this case ApplicationUpdaterManager</param>
/// <param name="e">the UpdaterActionEventArgs packaged by Updater, which gives us access to update information</param>
private void OnUpdaterUpdateAvailable( object sender, UpdaterActionEventArgs e )
{
// using the synchronous "Invoke". This marshals from the eventing thread--which comes from the Updater and should not
// be allowed to enter and "touch" the UI's window thread
// so we use Invoke which allows us to block the Updater thread at will while only allowing window thread to update UI
this.Invoke(
new MarshalEventDelegate( this.OnUpdaterUpdateAvailableHandler ),
new object[] { sender, e } );
}


/// <summary>
/// This handler gets fired by the Windows UI thread that is the main STA thread for THIS FORM. It takes the same
/// arguments as the event handler below it--sender, e--and acts on them using the main thread NOT the eventing thread
/// </summary>
/// <param name="sender">marshalled reference to the original event's sender argument</param>
/// <param name="e">marshalled reference to the original event's args</param>
private void OnUpdaterDownloadCompletedHandler( object sender, UpdaterActionEventArgs e )
{
Debug.WriteLine("Download Completed.");

}

/// <summary>
/// Event handler for Updater event. This event is fired by the originating thread from "inside" the Updater. While it is
/// possible for this same thread to act on our UI, it is NOT a good thing to do--UI is not threadsafe.
/// Therefore here we marshal from the Eventing thread (belongs to Updater) to our window thread using the synchronous Invoke
/// mechanism.
/// </summary>
/// <param name="sender">event sender in this case ApplicationUpdaterManager</param>
/// <param name="e">the UpdaterActionEventArgs packaged by Updater, which gives us access to update information</param>
private void OnUpdaterDownloadCompleted( object sender, UpdaterActionEventArgs e )
{
// using the synchronous "Invoke". This marshals from the eventing thread--which comes from the Updater and should not
// be allowed to enter and "touch" the UI's window thread
// so we use Invoke which allows us to block the Updater thread at will while only allowing window thread to update UI
this.Invoke(
new MarshalEventDelegate( this.OnUpdaterDownloadCompletedHandler ),
new object[] { sender, e } );
}


private void StartNewVersion( ServerApplicationInfo server )
{
XmlDocument doc = new XmlDocument();

// load config file to get base dir
doc.Load( AppDomain.CurrentDomain.SetupInformation.ConfigurationFile );

// get the base dir
string baseDir = doc.SelectSingleNode("configuration/appUpdater/UpdaterConfiguration/application/client/baseDir").InnerText;
string newDir = Path.Combine( baseDir, "AppStart.exe" );

ProcessStartInfo process = new ProcessStartInfo( newDir );
process.WorkingDirectory = Path.Combine( newDir , server.AvailableVersion );

// launch new version (actually, launch AppStart.exe which HAS pointer to new version )
Process.Start( process );

// tell updater to stop
CurrentDomain_ProcessExit( null, null );
// leave this app
Environment.Exit( 0 );
}

这篇关于Updater Application Block实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/731095

相关文章

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

MySQL 中 ROW_NUMBER() 函数最佳实践

《MySQL中ROW_NUMBER()函数最佳实践》MySQL中ROW_NUMBER()函数,作为窗口函数为每行分配唯一连续序号,区别于RANK()和DENSE_RANK(),特别适合分页、去重... 目录mysql 中 ROW_NUMBER() 函数详解一、基础语法二、核心特点三、典型应用场景1. 数据分

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

MySQL 用户创建与授权最佳实践

《MySQL用户创建与授权最佳实践》在MySQL中,用户管理和权限控制是数据库安全的重要组成部分,下面详细介绍如何在MySQL中创建用户并授予适当的权限,感兴趣的朋友跟随小编一起看看吧... 目录mysql 用户创建与授权详解一、MySQL用户管理基础1. 用户账户组成2. 查看现有用户二、创建用户1. 基

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

MySQL MCP 服务器安装配置最佳实践

《MySQLMCP服务器安装配置最佳实践》本文介绍MySQLMCP服务器的安装配置方法,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下... 目录mysql MCP 服务器安装配置指南简介功能特点安装方法数据库配置使用MCP Inspector进行调试开发指

SQLite3命令行工具最佳实践指南

《SQLite3命令行工具最佳实践指南》SQLite3是轻量级嵌入式数据库,无需服务器支持,具备ACID事务与跨平台特性,适用于小型项目和学习,sqlite3.exe作为命令行工具,支持SQL执行、数... 目录1. SQLite3简介和特点2. sqlite3.exe使用概述2.1 sqlite3.exe