使用反射检查程序集,实现自动更新
使用反射检查程序集,实现自动更新
在.Net下要让程序实现自动维护程序集的版本并且实现自动更新到最新版本的功能,可以使用反射机制。它提供了检查程序集的方法,通过 System.Reflection 中的 Assembly 类我们可以加载程序集,然后检查它的版本号,以此判断是否需要下载或更新。这里我写了一个示例来实现这个功能。但最后发现一旦加载了程序集就占用了需要更新的程序集文件,导致文件替换失败。为了解决这个问题,我参考了Flier's Sky的Assembly.Unload和Wayfarer's Prattle的通过应用程序域AppDomain加载和卸载程序集。下面就是我的代码,由于时间仓促,估计有些异常还没有处理到。请大家指教。
在.Net下要让程序实现自动维护程序集的版本并且实现自动更新到最新版本的功能,可以使用反射机制。它提供了检查程序集的方法,通过 System.Reflection 中的 Assembly 类我们可以加载程序集,然后检查它的版本号,以此判断是否需要下载或更新。这里我写了一个示例来实现这个功能。但最后发现一旦加载了程序集就占用了需要更新的程序集文件,导致文件替换失败。为了解决这个问题,我参考了Flier's Sky的Assembly.Unload和Wayfarer's Prattle的通过应用程序域AppDomain加载和卸载程序集。下面就是我的代码,由于时间仓促,估计有些异常还没有处理到。请大家指教。
1
using System;
2
using System.IO;
3
using System.Reflection;
4
using System.Collections.Generic;
5
using System.Text;
6![]()
7
namespace Update
8
{
9
// 序列化这个用来传递参数的类
10
public class AssembliyInf : MarshalByRefObject
11
{
12
public string AssemblyName = "";
13
public string AssemblyFileFullPath = "";
14
public string Version = "";
15
public string Revision = "";
16
public string Major = "";
17
public string Minor = "";
18
}
19![]()
20
// 由于是远程调用的方式,所以这个类也需要序列化
21
public class AssemblyLoader : MarshalByRefObject, IDisposable
22
{
23
public AssembliyInf GetAssemblyInf(string fileFullName)
24
{
25
AssembliyInf assemblyInf = new AssembliyInf();
26![]()
27
try
28
{
29
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(fileFullName);
30![]()
31
assemblyInf.AssemblyName = ((AssemblyName)assembly.GetName()).Name;
32
assemblyInf.AssemblyFileFullPath = assembly.Location;
33
assemblyInf.Version = ((AssemblyName)assembly.GetName()).Version.ToString();
34
assemblyInf.Revision = ((AssemblyName)assembly.GetName()).Version.Revision.ToString();
35
assemblyInf.Major = ((AssemblyName)assembly.GetName()).Version.Major.ToString();
36
assemblyInf.Minor = ((AssemblyName)assembly.GetName()).Version.Minor.ToString();
37![]()
38
assembly = null; // 释放引用
39![]()
40
// 手工调用框架的垃圾收集器
41
System.GC.Collect();
42
System.GC.WaitForPendingFinalizers();
43
System.GC.Collect(0);
44
}
45
catch (Exception)
46
{
47
}
48
return assemblyInf;
49
}
50![]()
51
public void Dispose()
52
{
53
}
54
}
55![]()
56![]()
57![]()
58
class Program
59
{
60
static void Main(string[] args)
61
{
62
Console.WriteLine();
63
string sourceFile, distinationFile;
64![]()
65
sourceFile = @"D:\MyApp\Update\myApp.exe"; // 假定准备更新的程序集已经下载到本地
66
distinationFile = @"D:\MyApp\myApp.exe"; // 这是要维护的目标程序集,发现新版本后就需要替换
67![]()
68
// 显示准备更新的程序集信息
69
AssembliyInf assemblyNew = GetAssemblyInf(sourceFile);
70
ShowAssembly(assemblyNew);
71![]()
72
// 显示当前使用的程序集信息
73
AssembliyInf assemblyCurrent = GetAssemblyInf(distinationFile);
74
ShowAssembly(assemblyCurrent);
75![]()
76
// 比较两个程序集
77
if (Compare(assemblyNew, assemblyCurrent))
78
{
79
Console.WriteLine("需要更新当前程序集!");
80
// 开始更新
81
Update(assemblyNew, assemblyCurrent);
82
}
83
else
84
Console.WriteLine("不需要更新当前程序集!");
85![]()
86
Console.ReadKey();
87
}
88![]()
89
// 用新的程序集替换现有的
90
static void Update(AssembliyInf assemblyNew, AssembliyInf assemblyCurrent)
91
{
92
string sourceFile, distinationFile;
93![]()
94
sourceFile = assemblyNew.AssemblyFileFullPath;
95
distinationFile = assemblyCurrent.AssemblyFileFullPath;
96![]()
97
// 替换文件
98
File.Copy(sourceFile, distinationFile, true);
99![]()
100
}
101![]()
102
// 显示程序集相关信息
103
static void ShowAssembly(AssembliyInf assembly)
104
{
105
Console.WriteLine("Assembly Name: " + assembly.AssemblyName );
106
Console.WriteLine("Assembly Version.Current: " + assembly.Version);
107
Console.WriteLine("Assembly Version.Revision: " + assembly.Revision);
108
Console.WriteLine("Assembly Version.Major: " + assembly.Major);
109
Console.WriteLine("Assembly Version.Minor: " + assembly.Minor);
110
Console.WriteLine("Assembly FullName: " + assembly.AssemblyFileFullPath);
111
Console.WriteLine();
112
}
113![]()
114
// 比较两个程序集判断是否需要更新
115
static bool Compare(AssembliyInf assemblyNew, AssembliyInf assemblyCurrent)
116
{
117
if ((assemblyNew.AssemblyName == assemblyCurrent.AssemblyName)
118
&& (int.Parse(assemblyNew.Revision) > int.Parse(assemblyCurrent.Revision)))
119
return true;
120
else
121
return false;
122
}
123![]()
124
// 获取程序集的信息
125
static AssembliyInf GetAssemblyInf(string fileFullName)
126
{
127
AssembliyInf assemblyInf = new AssembliyInf();
128![]()
129
string dllName = typeof(Program).Assembly.Location;
130
AppDomain domain = null;
131
AppDomainSetup setup = new AppDomainSetup();
132
setup.ShadowCopyFiles = "true";
133
domain = AppDomain.CreateDomain(dllName, null, setup);
134
AssemblyLoader al = (AssemblyLoader)domain.CreateInstanceFromAndUnwrap(dllName, "Update.AssemblyLoader");
135
AssembliyInf tmpAssemblyInf = al.GetAssemblyInf(fileFullName);
136
137
// 由于使用了序列化导致传回的对象不能传出这个方法,所以要转换一下
138
assemblyInf.AssemblyName = tmpAssemblyInf.AssemblyName;
139
// 又因为是使用了子程序域的方法,实际执行加载的子程序域是一个临时文件。返回值是一个临时文件。
140
//assemblyInf.AssemblyFileFullPath = tmpAssemblyInf.AssemblyFileFullPath;
141
assemblyInf.AssemblyFileFullPath = fileFullName;
142
assemblyInf.Version = tmpAssemblyInf.Version;
143
assemblyInf.Major = tmpAssemblyInf.Major;
144
assemblyInf.Minor = tmpAssemblyInf.Minor;
145
assemblyInf.Revision = tmpAssemblyInf.Revision;
146![]()
147
AppDomain.Unload(domain);
148![]()
149
return assemblyInf;
150
}
151
}
152![]()
153
}
154![]()
using System;2
using System.IO;3
using System.Reflection;4
using System.Collections.Generic;5
using System.Text;6

7
namespace Update8
{9
// 序列化这个用来传递参数的类10
public class AssembliyInf : MarshalByRefObject11
{12
public string AssemblyName = "";13
public string AssemblyFileFullPath = "";14
public string Version = "";15
public string Revision = "";16
public string Major = "";17
public string Minor = "";18
}19

20
// 由于是远程调用的方式,所以这个类也需要序列化21
public class AssemblyLoader : MarshalByRefObject, IDisposable22
{23
public AssembliyInf GetAssemblyInf(string fileFullName)24
{25
AssembliyInf assemblyInf = new AssembliyInf();26

27
try28
{29
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(fileFullName);30

31
assemblyInf.AssemblyName = ((AssemblyName)assembly.GetName()).Name;32
assemblyInf.AssemblyFileFullPath = assembly.Location;33
assemblyInf.Version = ((AssemblyName)assembly.GetName()).Version.ToString();34
assemblyInf.Revision = ((AssemblyName)assembly.GetName()).Version.Revision.ToString();35
assemblyInf.Major = ((AssemblyName)assembly.GetName()).Version.Major.ToString();36
assemblyInf.Minor = ((AssemblyName)assembly.GetName()).Version.Minor.ToString();37

38
assembly = null; // 释放引用39

40
// 手工调用框架的垃圾收集器41
System.GC.Collect();42
System.GC.WaitForPendingFinalizers();43
System.GC.Collect(0);44
}45
catch (Exception)46
{47
}48
return assemblyInf;49
}50

51
public void Dispose()52
{53
}54
}55

56

57

58
class Program59
{60
static void Main(string[] args)61
{62
Console.WriteLine();63
string sourceFile, distinationFile;64

65
sourceFile = @"D:\MyApp\Update\myApp.exe"; // 假定准备更新的程序集已经下载到本地66
distinationFile = @"D:\MyApp\myApp.exe"; // 这是要维护的目标程序集,发现新版本后就需要替换67

68
// 显示准备更新的程序集信息69
AssembliyInf assemblyNew = GetAssemblyInf(sourceFile);70
ShowAssembly(assemblyNew);71

72
// 显示当前使用的程序集信息73
AssembliyInf assemblyCurrent = GetAssemblyInf(distinationFile);74
ShowAssembly(assemblyCurrent);75

76
// 比较两个程序集77
if (Compare(assemblyNew, assemblyCurrent))78
{79
Console.WriteLine("需要更新当前程序集!");80
// 开始更新81
Update(assemblyNew, assemblyCurrent);82
}83
else84
Console.WriteLine("不需要更新当前程序集!");85

86
Console.ReadKey();87
}88

89
// 用新的程序集替换现有的90
static void Update(AssembliyInf assemblyNew, AssembliyInf assemblyCurrent)91
{92
string sourceFile, distinationFile;93

94
sourceFile = assemblyNew.AssemblyFileFullPath;95
distinationFile = assemblyCurrent.AssemblyFileFullPath;96

97
// 替换文件98
File.Copy(sourceFile, distinationFile, true);99

100
}101

102
// 显示程序集相关信息103
static void ShowAssembly(AssembliyInf assembly)104
{105
Console.WriteLine("Assembly Name: " + assembly.AssemblyName );106
Console.WriteLine("Assembly Version.Current: " + assembly.Version);107
Console.WriteLine("Assembly Version.Revision: " + assembly.Revision);108
Console.WriteLine("Assembly Version.Major: " + assembly.Major);109
Console.WriteLine("Assembly Version.Minor: " + assembly.Minor);110
Console.WriteLine("Assembly FullName: " + assembly.AssemblyFileFullPath);111
Console.WriteLine();112
}113

114
// 比较两个程序集判断是否需要更新115
static bool Compare(AssembliyInf assemblyNew, AssembliyInf assemblyCurrent)116
{117
if ((assemblyNew.AssemblyName == assemblyCurrent.AssemblyName) 118
&& (int.Parse(assemblyNew.Revision) > int.Parse(assemblyCurrent.Revision)))119
return true;120
else121
return false;122
}123

124
// 获取程序集的信息125
static AssembliyInf GetAssemblyInf(string fileFullName)126
{127
AssembliyInf assemblyInf = new AssembliyInf(); 128

129
string dllName = typeof(Program).Assembly.Location;130
AppDomain domain = null;131
AppDomainSetup setup = new AppDomainSetup();132
setup.ShadowCopyFiles = "true";133
domain = AppDomain.CreateDomain(dllName, null, setup);134
AssemblyLoader al = (AssemblyLoader)domain.CreateInstanceFromAndUnwrap(dllName, "Update.AssemblyLoader");135
AssembliyInf tmpAssemblyInf = al.GetAssemblyInf(fileFullName);136
137
// 由于使用了序列化导致传回的对象不能传出这个方法,所以要转换一下138
assemblyInf.AssemblyName = tmpAssemblyInf.AssemblyName;139
// 又因为是使用了子程序域的方法,实际执行加载的子程序域是一个临时文件。返回值是一个临时文件。140
//assemblyInf.AssemblyFileFullPath = tmpAssemblyInf.AssemblyFileFullPath;141
assemblyInf.AssemblyFileFullPath = fileFullName;142
assemblyInf.Version = tmpAssemblyInf.Version;143
assemblyInf.Major = tmpAssemblyInf.Major;144
assemblyInf.Minor = tmpAssemblyInf.Minor;145
assemblyInf.Revision = tmpAssemblyInf.Revision;146

147
AppDomain.Unload(domain);148

149
return assemblyInf;150
}151
}152

153
}154




浙公网安备 33010602011771号