惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
V
V2EX
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
罗磊的独立博客
小众软件
小众软件
Vercel News
Vercel News
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
J
Java Code Geeks
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
B
Blog
美团技术团队
量子位

博客园 - 洪虎

Windows环境下安装Python 建立批命令快速修改本机IP地址 网络经典命令 - 洪虎 - 博客园 “指定域的名称或安全标识SID与该域的信任信息不一致”的解决方法 建立主DNS区域和辅助DNS区域的最佳实践 无人职守安装 XP 电脑黑客基本技术和入侵的关键字以及电脑攻防应用 建立一个可修改Windows域用户密码的web页面 修复SQL2000中损坏的表 将Excel转换为CSV的VBA代码 - 洪虎 - 博客园 用命令检查电脑是否被安装木马 DateTime.ToString 方法 - 洪虎 - 博客园 在C#中自定义异常 - 洪虎 - 博客园 使用DataDynamics.ActiveReports 创建子报表 错误的SQL脚本,错误消息 4104 - 洪虎 - 博客园 适配器模式 如何在 Reporting Services 开发基于用户权限的报表呢? 委托模式 接口模型
使用反射检查程序集,实现自动更新
洪虎 · 2006-10-04 · via 博客园 - 洪虎

使用反射检查程序集,实现自动更新

在.Net下要让程序实现自动维护程序集的版本并且实现自动更新到最新版本的功能,可以使用反射机制。它提供了检查程序集的方法,通过 System.Reflection 中的 Assembly 类我们可以加载程序集,然后检查它的版本号,以此判断是否需要下载或更新。这里我写了一个示例来实现这个功能。但最后发现一旦加载了程序集就占用了需要更新的程序集文件,导致文件替换失败。为了解决这个问题,我参考了

Flier's SkyAssembly.UnloadWayfarer's Prattle通过应用程序域AppDomain加载和卸载程序集。下面就是我的代码,由于时间仓促,估计有些异常还没有处理到。请大家指教。

  1using System;
  2using System.IO;
  3using System.Reflection;
  4using System.Collections.Generic;
  5using System.Text;
  6
  7namespace 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