zoukankan      html  css  js  c++  java
  • C# WinForm通用自动更新器

    一、引言

    对于C/S架构来说,软件更新是一个很常用的功能,下面介绍一种非常实用的软件自动升级方案。

    二、示意图

    三、项目说明

    3.1、项目创建

    新建4个项目,如下所示:

    3.2、项目关系

    四、LinkTo.Toolkit

    LinkTo.Toolkit主要是一些Utility及Helper类文件,实现转换扩展、文件读写、进程处理等功能。

        /// <summary>
        /// 转换扩展类
        /// </summary>
        public static class ConvertExtension
        {
            public static string ToString2(this object obj)
            {
                if (obj == null)
                    return string.Empty;
                return obj.ToString();
            }
    
            public static DateTime? ToDateTime(this string str)
            {
                if (string.IsNullOrEmpty(str)) return null;
                if (DateTime.TryParse(str, out DateTime dateTime))
                {
                    return dateTime;
                }
                return null;
            }
    
            public static bool ToBoolean(this string str)
            {
                if (string.IsNullOrEmpty(str)) return false;
                return str.ToLower() == bool.TrueString.ToLower();
            }
    
            public static bool IsNullOrEmpty(this string str)
            {
                return string.IsNullOrEmpty(str);
            }
    
            public static int ToInt(this string str)
            {
                if (int.TryParse(str, out int intValue))
                {
                    return intValue;
                }
                return 0;
            }
    
            public static long ToLong(this string str)
            {
                if (long.TryParse(str, out long longValue))
                {
                    return longValue;
                }
                return 0;
            }
    
            public static decimal ToDecimal(this string str)
            {
                if (decimal.TryParse(str, out decimal decimalValue))
                {
                    return decimalValue;
                }
                return 0;
            }
    
            public static double ToDouble(this string str)
            {
                if (double.TryParse(str, out double doubleValue))
                {
                    return doubleValue;
                }
                return 0;
            }
    
            public static float ToFloat(this string str)
            {
                if (float.TryParse(str, out float floatValue))
                {
                    return floatValue;
                }
                return 0;
            }
    
            /// <summary>
            /// DataRow转换为实体类
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="dr"></param>
            /// <returns></returns>
            public static T ConvertToEntityByDataRow<T>(this DataRow dataRow) where T : new()
            {
                Type type = typeof(T);
                PropertyInfo[] properties = type.GetProperties();
                T t = new T();
                if (dataRow == null) return t;
                foreach (PropertyInfo property in properties)
                {
                    foreach (DataColumn column in dataRow.Table.Columns)
                    {
                        if (property.Name.Equals(column.ColumnName, StringComparison.OrdinalIgnoreCase))
                        {
                            object value = dataRow[column];
                            if (value != null && value != DBNull.Value)
                            {
                                if (value.GetType().Name != property.PropertyType.Name)
                                {
                                    if (property.PropertyType.IsEnum)
                                    {
                                        property.SetValue(t, Enum.Parse(property.PropertyType, value.ToString()), null);
                                    }
                                    else
                                    {
                                        try
                                        {
                                            value = Convert.ChangeType(value, (Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType));
                                            property.SetValue(t, value, null);
                                        }
                                        catch { }
                                    }
                                }
                                else
                                {
                                    property.SetValue(t, value, null);
                                }
                            }
                            else
                            {
                                property.SetValue(t, null, null);
                            }
                            break;
                        }
                    }
                }
                return t;
            }
    
            /// <summary>
            /// 通用简单实体类型互转
            /// </summary>
            public static T ConvertToEntity<T>(this object sourceEntity) where T : new()
            {
                T t = new T();
                Type sourceType = sourceEntity.GetType();
                if (sourceType.Equals(typeof(DataRow)))
                {
                    //DataRow类型
                    DataRow dataRow = sourceEntity as DataRow;
                    t = dataRow.ConvertToEntityByDataRow<T>();
                }
                else
                {
                    Type type = typeof(T);
                    PropertyInfo[] properties = type.GetProperties();
                    PropertyInfo[] sourceProperties = sourceType.GetProperties();
                    foreach (PropertyInfo property in properties)
                    {
                        foreach (var sourceProperty in sourceProperties)
                        {
                            if (sourceProperty.Name.Equals(property.Name, StringComparison.OrdinalIgnoreCase))
                            {
                                object value = sourceProperty.GetValue(sourceEntity, null);
                                if (value != null && value != DBNull.Value)
                                {
                                    if (sourceProperty.PropertyType.Name != property.PropertyType.Name)
                                    {
                                        if (property.PropertyType.IsEnum)
                                        {
                                            property.SetValue(t, Enum.Parse(property.PropertyType, value.ToString()), null);
                                        }
                                        else
                                        {
                                            try
                                            {
                                                value = Convert.ChangeType(value, (Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType));
                                                property.SetValue(t, value, null);
                                            }
                                            catch { }
                                        }
                                    }
                                    else
                                    {
                                        property.SetValue(t, value, null);
                                    }
                                }
                                else
                                {
                                    property.SetValue(t, null, null);
                                }
                                break;
                            }
                        }
                    }
                }
                return t;
            }
    
            /// <summary>
            /// 通用简单实体类型互转
            /// </summary>
            public static List<T> ConvertToEntityList<T>(this object list) where T : new()
            {
                List<T> t = new List<T>();
                if (list == null) return t;
                Type sourceObj = list.GetType();
                if (sourceObj.Equals(typeof(DataTable)))
                {
                    var dataTable = list as DataTable;
                    t = dataTable.Rows.Cast<DataRow>().Where(m => !(m.RowState == DataRowState.Deleted || m.RowState == DataRowState.Detached)).Select(m => m.ConvertToEntityByDataRow<T>()).ToList();
                }
                else if (list is IEnumerable)
                {
                    t = ((IList)list).Cast<object>().Select(m => m.ConvertToEntity<T>()).ToList();
                }
                return t;
            }
    
            /// <summary>
            /// 转换为DataTable,如果是集合没有数据行的时候会抛异常。
            /// </summary>
            /// <param name="list"></param>
            /// <returns></returns>
            public static DataTable ConvertToDataTable(this object list)
            {
                if (list == null) return null;
                DataTable dataTable = new DataTable();
                if (list is IEnumerable)
                {
                    var li = (IList)list;
                    //li[0]代表的是一个对象,list没有行时,会抛异常。
                    PropertyInfo[] properties = li[0].GetType().GetProperties();
                    dataTable.Columns.AddRange(properties.Where(m => !m.PropertyType.IsClass || !m.PropertyType.IsInterface).Select(m =>
                        new DataColumn(m.Name, Nullable.GetUnderlyingType(m.PropertyType) ?? m.PropertyType)).ToArray());
                    foreach (var item in li)
                    {
                        DataRow dataRow = dataTable.NewRow();
                        foreach (PropertyInfo property in properties.Where(m => m.PropertyType.GetProperty("Item") == null))    //过滤含有索引器的属性
                        {
                            object value = property.GetValue(item, null);
                            dataRow[property.Name] = value ?? DBNull.Value;
                        }
                        dataTable.Rows.Add(dataRow);
                    }
                }
                else
                {
                    PropertyInfo[] properties = list.GetType().GetProperties();
                    properties = properties.Where(m => m.PropertyType.GetProperty("Item") == null).ToArray();   //过滤含有索引器的属性
                    dataTable.Columns.AddRange(properties.Select(m => new DataColumn(m.Name, Nullable.GetUnderlyingType(m.PropertyType) ?? m.PropertyType)).ToArray());
                    DataRow dataRow = dataTable.NewRow();
                    foreach (PropertyInfo property in properties)
                    {
                        object value = property.GetValue(list, null);
                        dataRow[property.Name] = value ?? DBNull.Value;
                    }
                    dataTable.Rows.Add(dataRow);
                }
                return dataTable;
            }
    
            /// <summary>
            /// 实体类公共属性值复制
            /// </summary>
            /// <param name="entity"></param>
            /// <param name="target"></param>
            public static void CopyTo(this object entity, object target)
            {
                if (target == null) return;
                if (entity.GetType() != target.GetType())
                    return;
                PropertyInfo[] properties = target.GetType().GetProperties();
                foreach (PropertyInfo property in properties)
                {
                    if (property.PropertyType.GetProperty("Item") != null)
                        continue;
                    object value = property.GetValue(entity, null);
                    if (value != null)
                    {
                        if (value is ICloneable)
                        {
                            property.SetValue(target, (value as ICloneable).Clone(), null);
                        }
                        else
                        {
                            property.SetValue(target, value.Copy(), null);
                        }
                    }
                    else
                    {
                        property.SetValue(target, null, null);
                    }
                }
            }
    
            public static object Copy(this object obj)
            {
                if (obj == null) return null;
                object targetDeepCopyObj;
                Type targetType = obj.GetType();
                if (targetType.IsValueType == true)
                {
                    targetDeepCopyObj = obj;
                }
                else
                {
                    targetDeepCopyObj = Activator.CreateInstance(targetType);   //创建引用对象
                    MemberInfo[] memberCollection = obj.GetType().GetMembers();
    
                    foreach (MemberInfo member in memberCollection)
                    {
                        if (member.GetType().GetProperty("Item") != null)
                            continue;
                        if (member.MemberType == MemberTypes.Field)
                        {
                            FieldInfo field = (FieldInfo)member;
                            object fieldValue = field.GetValue(obj);
                            if (fieldValue is ICloneable)
                            {
                                field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone());
                            }
                            else
                            {
                                field.SetValue(targetDeepCopyObj, fieldValue.Copy());
                            }
                        }
                        else if (member.MemberType == MemberTypes.Property)
                        {
                            PropertyInfo property = (PropertyInfo)member;
                            MethodInfo method = property.GetSetMethod(false);
                            if (method != null)
                            {
                                object propertyValue = property.GetValue(obj, null);
                                if (propertyValue is ICloneable)
                                {
                                    property.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null);
                                }
                                else
                                {
                                    property.SetValue(targetDeepCopyObj, propertyValue.Copy(), null);
                                }
                            }
                        }
                    }
                }
                return targetDeepCopyObj;
            }
        }
    ConvertExtension.cs
        public class FileHelper
        {
            private readonly string strUpdateFilesPath;
    
            public FileHelper(string strDirector)
            {
                strUpdateFilesPath = strDirector;
            }
    
            //保存所有的文件信息
            private List<FileInfo> listFiles = new List<FileInfo>();
    
            public List<FileInfo> GetAllFilesInDirectory(string strDirector)
            {
                DirectoryInfo directory = new DirectoryInfo(strDirector);
                DirectoryInfo[] directoryArray = directory.GetDirectories();
                FileInfo[] fileInfoArray = directory.GetFiles();
                if (fileInfoArray.Length > 0) listFiles.AddRange(fileInfoArray);
    
                foreach (DirectoryInfo item in directoryArray)
                {
                    DirectoryInfo directoryA = new DirectoryInfo(item.FullName);
                    DirectoryInfo[] directoryArrayA = directoryA.GetDirectories();
                    GetAllFilesInDirectory(item.FullName);
                }
                return listFiles;
            }
    
            public string[] GetUpdateList(List<FileInfo> listFileInfo)
            {
                var fileArrary = listFileInfo.Cast<FileInfo>().Select(s => s.FullName.Replace(strUpdateFilesPath, "")).ToArray();
                return fileArrary;
            }
    
            /// <summary>
            /// 删除文件夹下的所有文件但不删除目录
            /// </summary>
            /// <param name="dirRoot"></param>
            public static void DeleteDirAllFile(string dirRoot)
            {
                DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(dirRoot));
                FileInfo[] files = directoryInfo.GetFiles("*.*", SearchOption.AllDirectories);
                foreach (FileInfo item in files)
                {
                    File.Delete(item.FullName);
                }
            }
        }
    FileHelper.cs
        public static class FileUtility
        {
            #region 读取文件
            /// <summary>
            /// 读取文件
            /// </summary>
            /// <param name="filePath">文件路径</param>
            /// <returns></returns>
            public static string ReadFile(string filePath)
            {
                string result = string.Empty;
    
                if (File.Exists(filePath) == false)
                {
                    return result;
                }
    
                try
                {
                    using (var streamReader = new StreamReader(filePath, Encoding.UTF8))
                    {
                        result = streamReader.ReadToEnd();
                    }
                }
                catch (Exception)
                {
                    result = string.Empty;
                }
    
                return result;
            }
    
            #endregion 读文件
    
            #region 写入文件
            /// <summary>
            /// 写入文件
            /// </summary>
            /// <param name="filePath">文件路径</param>
            /// <param name="strValue">写入内容</param>
            /// <returns></returns>
            public static bool WriteFile(string filePath, string strValue)
            {
                try
                {
                    if (File.Exists(filePath) == false)
                    {
                        using (FileStream fileStream = File.Create(filePath)) { }
                    }
    
                    using (var streamWriter = new StreamWriter(filePath, true, Encoding.UTF8))
                    {
                        streamWriter.WriteLine(strValue);
                    }
    
                    return true;
                }
                catch (Exception)
                {
                    return false;
                }
            }
            #endregion
    
            #region 删除文件
            /// <summary>
            /// 删除文件
            /// </summary>
            /// <param name="filePath">文件路径</param>
            /// <returns></returns>
            public static bool DeleteFile(string filePath)
            {
                try
                {
                    File.Delete(filePath);
                    return true;
                }
                catch (Exception)
                {
                    return false;
                }
            }
            #endregion 删除文件
    
            #region 为文件添加用户组的完全控制权限
            /// <summary>
            /// 为文件添加用户组的完全控制权限
            /// </summary>
            /// <param name="userGroup">用户组</param>
            /// <param name="filePath">文件路径</param>
            /// <returns></returns>
            public static bool AddSecurityControll2File(string userGroup, string filePath)
            {
                try
                {
                    //获取文件信息
                    FileInfo fileInfo = new FileInfo(filePath);
                    //获得该文件的访问权限
                    FileSecurity fileSecurity = fileInfo.GetAccessControl();
                    //添加用户组的访问权限规则--完全控制权限
                    fileSecurity.AddAccessRule(new FileSystemAccessRule(userGroup, FileSystemRights.FullControl, AccessControlType.Allow));
                    //设置访问权限
                    fileInfo.SetAccessControl(fileSecurity);
                    //返回结果
                    return true;
                }
                catch (Exception)
                {
                    //返回结果
                    return false;
                }
            }
            #endregion
    
            #region 为文件夹添加用户组的完全控制权限
            /// <summary>
            /// 为文件夹添加用户组的完全控制权限
            /// </summary>
            /// <param name="userGroup">用户组</param>
            /// <param name="dirPath">文件夹路径</param>
            /// <returns></returns>
            public static bool AddSecurityControll2Folder(string userGroup,string dirPath)
            {
                try
                {
                    //获取文件夹信息
                    DirectoryInfo dir = new DirectoryInfo(dirPath);
                    //获得该文件夹的所有访问权限
                    DirectorySecurity dirSecurity = dir.GetAccessControl(AccessControlSections.All);
                    //设定文件ACL继承
                    InheritanceFlags inherits = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
                    //添加用户组的访问权限规则--完全控制权限
                    FileSystemAccessRule usersFileSystemAccessRule = new FileSystemAccessRule(userGroup, FileSystemRights.FullControl, inherits, PropagationFlags.None, AccessControlType.Allow);
                    dirSecurity.ModifyAccessRule(AccessControlModification.Add, usersFileSystemAccessRule, out bool isModified);
                    //设置访问权限
                    dir.SetAccessControl(dirSecurity);
                    //返回结果
                    return true;
                }
                catch (Exception)
                {
                    //返回结果
                    return false;
                }
            }
            #endregion
        }
    FileUtility.cs
        public static class ProcessUtility
        {
            #region 关闭进程
            /// <summary>
            /// 关闭进程
            /// </summary>
            /// <param name="processName">进程名</param>
            public static void KillProcess(string processName)
            {
                Process[] myproc = Process.GetProcesses();
                foreach (Process item in myproc)
                {
                    if (item.ProcessName == processName)
                    {
                        item.Kill();
                    }
                }
            }
            #endregion
        }
    ProcessUtility.cs
        /// <summary>
        /// Xml序列化与反序列化
        /// </summary>
        public static class XmlUtility
        {
            #region 序列化
    
            /// <summary>
            /// 序列化
            /// </summary>
            /// <param name="type">类型</param>
            /// <param name="obj">对象</param>
            /// <returns></returns>
            public static string Serializer(Type type, object obj)
            {
                MemoryStream Stream = new MemoryStream();
                XmlSerializer xml = new XmlSerializer(type);
                try
                {
                    //序列化对象
                    xml.Serialize(Stream, obj);
                }
                catch (InvalidOperationException)
                {
                    throw;
                }
                Stream.Position = 0;
                StreamReader sr = new StreamReader(Stream);
                string str = sr.ReadToEnd();
    
                sr.Dispose();
                Stream.Dispose();
    
                return str;
            }
    
            #endregion 序列化
    
            #region 反序列化
    
            /// <summary>
            /// 反序列化
            /// </summary>
            /// <param name="type">类型</param>
            /// <param name="xml">XML字符串</param>
            /// <returns></returns>
            public static object Deserialize(Type type, string xml)
            {
                try
                {
                    using (StringReader sr = new StringReader(xml))
                    {
                        XmlSerializer xmldes = new XmlSerializer(type);
                        return xmldes.Deserialize(sr);
                    }
                }
                catch (Exception ex)
                {
                    return ex.Message;
                }
            }
    
            /// <summary>
            /// 反序列化
            /// </summary>
            /// <param name="type"></param>
            /// <param name="xml"></param>
            /// <returns></returns>
            public static object Deserialize(Type type, Stream stream)
            {
                XmlSerializer xmldes = new XmlSerializer(type);
                return xmldes.Deserialize(stream);
            }
    
            #endregion 反序列化
        }
    XmlUtility.cs

    五、AutoUpdaterTest

    5.1、实体类

    作用:本地配置AutoUpdateConfig.xml文件的序列化及反序列化实体对象。

        public class AutoUpdateConfig
        {
            /// <summary>
            /// 自动升级模式:当前仅支持HTTP
            /// </summary>
            public string AutoUpdateMode { get; set; }
    
            /// <summary>
            /// HTTP自动升级模式时的URL地址
            /// </summary>
            public string AutoUpdateHttpUrl { get; set; }
        }
    AutoUpdateConfig.cs

    5.2、通用类

    作用:应用程序全局静态常量。全局参数都在此设置,方便统一管理。注:客户端是否检测更新,也是在此设置默认值。

        /// <summary>
        /// 应用程序全局静态常量
        /// </summary>
        public static class GlobalParam
        {
            #region 自动更新参数
            /// <summary>
            /// 是否检查自动更新:默认是true
            /// </summary>
            public static string CheckAutoUpdate = "true";
    
            /// <summary>
            /// 本地自动更新配置XML文件名
            /// </summary>
            public const string AutoUpdateConfig_XmlFileName = "AutoUpdateConfig.xml";
    
            /// <summary>
            /// 本地自动更新下载临时存放目录
            /// </summary>
            public const string TempDir = "Temp";
    
            /// <summary>
            /// 远端自动更新信息XML文件名
            /// </summary>
            public const string AutoUpdateInfo_XmlFileName = "AutoUpdateInfo.xml";
    
            /// <summary>
            /// 远端自动更新文件存放目录
            /// </summary>
            public const string RemoteDir = "AutoUpdateFiles";
    
            /// <summary>
            /// 主线程名
            /// </summary>
            public const string MainProcess = "AutoUpdaterTest";
            #endregion
        }
    GlobalParam.cs

    作用:应用程序上下文。

        /// <summary>
        /// 应用程序上下文
        /// </summary>
        public class AppContext
        {
            /// <summary>
            /// 客户端配置文件
            /// </summary>
            public static AutoUpdateConfig AutoUpdateConfigData { get; set; }
        }
    AppContext.cs

    作用:应用程序配置。

        public class AppConfig
        {
            private static readonly object _lock = new object();
            private static AppConfig _instance = null;
    
            #region 自动更新配置
            /// <summary>
            /// 自动更新配置数据
            /// </summary>
            public AutoUpdateConfig AutoUpdateConfigData { get; set; }
    
            private AppConfig()
            {
                AutoUpdateConfigData = new AutoUpdateConfig();
            }
    
            public static AppConfig Instance
            {
                get
                {
                    if (_instance == null)
                    {
                        lock (_lock)
                        {
                            if (_instance == null)
                            {
                                _instance = new AppConfig();
                            }
                        }
                    }
                    return _instance;
                }
            }
    
            /// <summary>
            /// 本地自动更新下载临时文件夹路径
            /// </summary>
            public string TempPath
            {
                get
                {
                    return string.Format("{0}\{1}", Application.StartupPath, GlobalParam.TempDir);
                }
            }
    
            /// <summary>
            /// 初始化系统配置信息
            /// </summary>
            public void InitialSystemConfig()
            {
                AutoUpdateConfigData.AutoUpdateMode = AppContext.AutoUpdateConfigData.AutoUpdateMode;
                AutoUpdateConfigData.AutoUpdateHttpUrl = AppContext.AutoUpdateConfigData.AutoUpdateHttpUrl;
            }
            #endregion
        }
    AppConfig.cs

    5.3、工具类

    作用:配置文件的读写。

        public class AutoUpdateHelper
        {
            private readonly string AutoUpdateMode = string.Empty;
    
            public AutoUpdateHelper(string autoUpdateMode)
            {
                AutoUpdateMode = autoUpdateMode;
            }
    
            /// <summary>
            /// 加载本地自动更新配置文件
            /// </summary>
            /// <returns></returns>
            public static AutoUpdateConfig Load()
            {
                string filePath = string.Empty, fileContent = string.Empty;
                filePath = Path.Combine(Application.StartupPath, GlobalParam.AutoUpdateConfig_XmlFileName);
                AutoUpdateConfig config = new AutoUpdateConfig();
                fileContent = FileUtility.ReadFile(filePath);
                object obj = XmlUtility.Deserialize(typeof(AutoUpdateConfig), fileContent);
                config = obj as AutoUpdateConfig;
                return config;
            }
    
            /// <summary>
            /// 获取远端自动更新信息的版本号
            /// </summary>
            /// <returns></returns>
            public string GetRemoteAutoUpdateInfoVersion()
            {
                XDocument doc = new XDocument();
                doc = XDocument.Parse(GetRemoteAutoUpdateInfoXml());
                return doc.Element("AutoUpdateInfo").Element("NewVersion").Value;
            }
    
            /// <summary>
            /// 获取远端自动更新信息的XML文件内容
            /// </summary>
            /// <returns></returns>
            public string GetRemoteAutoUpdateInfoXml()
            {
                string remoteXmlAddress = AppConfig.Instance.AutoUpdateConfigData.AutoUpdateHttpUrl + "/" + GlobalParam.AutoUpdateInfo_XmlFileName;
                string receiveXmlPath = Path.Combine(AppConfig.Instance.TempPath, GlobalParam.AutoUpdateInfo_XmlFileName);
                string xmlString = string.Empty;
    
                if (Directory.Exists(AppConfig.Instance.TempPath) == false)
                {
                    Directory.CreateDirectory(AppConfig.Instance.TempPath);
                }
    
                if (AutoUpdateMode.ToUpper() == "HTTP")
                {
                    WebClient client = new WebClient();
                    client.DownloadFile(remoteXmlAddress, receiveXmlPath);
                }
    
                if (File.Exists(receiveXmlPath))
                {
                    xmlString = FileUtility.ReadFile(receiveXmlPath);
                    return xmlString;
                }
    
                return string.Empty;
            }
    
            /// <summary>
            /// 写入本地自动更新配置的XML文件内容
            /// </summary>
            /// <returns></returns>
            public string WriteLocalAutoUpdateInfoXml()
            {
                string xmlPath = string.Empty, xmlValue = string.Empty;
    
                xmlPath = Path.Combine(AppConfig.Instance.TempPath, GlobalParam.AutoUpdateConfig_XmlFileName);
                xmlValue = XmlUtility.Serializer(typeof(AutoUpdateConfig), AppConfig.Instance.AutoUpdateConfigData);
    
                if (File.Exists(xmlPath))
                {
                    File.Delete(xmlPath);
                }
    
                bool blSuccess = FileUtility.WriteFile(xmlPath, xmlValue);
                return blSuccess == true ? xmlPath : "";
            }
        }
    AutoUpdateHelper.cs

    5.4、本地配置文件

    作用:配置自动更新模式及相关。

    注1:复制到输出目录选择始终复制。

    注2:主程序运行时,先读取此配置更新文件,然后给AppContext上下文赋值,接着给AppConfig配置赋值。

    <?xml version="1.0" encoding="utf-8" ?>
    <AutoUpdateConfig>
      <!--自动升级模式:当前仅支持HTTP-->
      <AutoUpdateMode>HTTP</AutoUpdateMode>
      <!--HTTP自动升级模式时的URL地址-->
      <AutoUpdateHttpUrl>http://127.0.0.1:6600/AutoUpdateDir</AutoUpdateHttpUrl>
    </AutoUpdateConfig>
    AutoUpdateConfig.xml

    5.5、主程序

    新建一个Windows 窗体MainForm,此处理仅需要一个空白窗体即可,作测试用。

        public partial class MainForm : Form
        {
            private static MainForm _Instance;
    
            /// <summary>
            /// MainForm主窗体实例
            /// </summary>
            public static MainForm Instance
            {
                get
                {
                    if (_Instance == null)
                    {
                        _Instance = new MainForm();
                    }
                    return _Instance;
                }
            }
    
            public MainForm()
            {
                InitializeComponent();
            }
        }
    MainForm.cs

    5.6、应用程序主入口

    作用:检测应用程序是否需要自动更新,如里需要则检测远程服务端的版本号。假如远程服务端有新版本,则调用自动更新器AutoUpdater并向其传递4个参数。

        internal static class Program
        {
            /// <summary>
            /// 应用程序的主入口点
            /// </summary>
            [STAThread]
            private static void Main(string[] args)
            {
                //尝试设置访问权限
                FileUtility.AddSecurityControll2Folder("Users", Application.StartupPath);
    
                //未捕获的异常处理
                Application.ThreadException += Application_ThreadException;
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    
                //是否检查自动更新赋值
                if (args.Length > 0)
                {
                    GlobalParam.CheckAutoUpdate = args[0];
                }
    
                //加载自动更新配置文件,给上下文AppServiceConfig对象赋值。
                var config = AutoUpdateHelper.Load();
                AppContext.AutoUpdateConfigData = config;
    
                //窗体互斥体
                var instance = new Mutex(true, GlobalParam.MainProcess, out bool isNewInstance);
                if (isNewInstance == true)
                {
                    if (GlobalParam.CheckAutoUpdate.ToBoolean())
                    {
                        if (CheckUpdater())
                            ProcessUtility.KillProcess(GlobalParam.MainProcess);
                    }
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(MainForm.Instance);
                    instance.ReleaseMutex();
                }
                else
                {
                    MessageBox.Show("已经启动了一个程序,请先退出。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Application.Exit();
                }
            }
    
            /// <summary>
            /// 自动更新检测
            /// </summary>
            /// <returns></returns>
            private static bool CheckUpdater()
            {
                if (GlobalParam.CheckAutoUpdate.ToBoolean() == false) return false;
    
                #region 检查版本更新
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
    
                bool blFinish = false;
                AppConfig.Instance.InitialSystemConfig();
                var helper = new AutoUpdateHelper(AppConfig.Instance.AutoUpdateConfigData.AutoUpdateMode);
                string fileVersion = FileVersionInfo.GetVersionInfo(Application.ExecutablePath).FileVersion;
    
                long localVersion = 0;
                long remoteVersion = 0;
                try
                {
                    localVersion = fileVersion.Replace(".", "").ToLong();
                    remoteVersion = helper.GetRemoteAutoUpdateInfoVersion().Replace(".", "").ToLong();
    
                    if ((localVersion > 0) && (localVersion < remoteVersion))
                    {
                        blFinish = true;
                        string autoUpdateConfigXmlPath = helper.WriteLocalAutoUpdateInfoXml();
                        string autoUpdateInfoXmlPath = Path.Combine(AppConfig.Instance.TempPath, GlobalParam.AutoUpdateInfo_XmlFileName);
                        string argument1 = autoUpdateConfigXmlPath;
                        string argument2 = autoUpdateInfoXmlPath;
                        string argument3 = GlobalParam.MainProcess;
                        string argument4 = GlobalParam.RemoteDir;
                        string arguments = argument1 + " " + argument2 + " " + argument3 + " " + argument4;
                        Process.Start("AutoUpdater.exe", arguments);
                        Application.Exit();
                    }
                }
                catch (TimeoutException)
                {
                    blFinish = false;
                }
                catch (WebException)
                {
                    blFinish = false;
                }
                catch (Exception)
                {
                    blFinish = false;
                }
                
                return blFinish;
                #endregion
            }
    
            /// <summary>
            /// UI线程未捕获异常处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
            {
                string strError = "", strLog = "", strDateInfo = DateTime.Now.ToString() + " 出现应用程序未处理的异常:
    ";
                var error = e.Exception;
    
                if (error != null)
                {
                    strError = strDateInfo + $"异常类型:{error.GetType().Name}
    异常消息:{error.Message}";
                    strLog = strDateInfo + $"异常类型:{error.GetType().Name}
    异常消息:{error.Message}
    堆栈信息:{error.StackTrace}
    来源信息:{error.Source}
    ";
                }
                else
                {
                    strError = $"Application ThreadException:{e}";
                }
    
                WriteLog(strLog);
                MessageBox.Show(strError, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
    
            /// <summary>
            /// 非UI线程未捕获异常处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                string strError = "", strLog = "", strDateInfo = DateTime.Now.ToString() + " 出现应用程序未处理的异常:
    ";
    
                if (e.ExceptionObject is Exception error)
                {
                    strError = strDateInfo + $"异常消息:{error.Message}";
                    strLog = strDateInfo + $"异常消息:{error.Message}
    堆栈信息:{error.StackTrace}";
                }
                else
                {
                    strError = $"Application UnhandledError:{e}";
                }
    
                WriteLog(strLog);
                MessageBox.Show(strError, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
    
            /// <summary>
            /// 写入日志
            /// </summary>
            /// <param name="strLog"></param>
            private static void WriteLog(string strLog)
            {
                string dirPath = @"LogMainProcess", fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                string strLine = "----------------------------------------------------------------------------------------------------";
    
                FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLog);
                FileUtility.WriteFile(Path.Combine(dirPath,fileName), strLine);
            }
        }
    Program.cs

    六、AutoUpdater

    6.1、实体类

    作用:配置自动更新模式及相关。

        /// <summary>
        /// 自动更新配置信息
        /// </summary>
        public class AutoUpdateConfig
        {
            /// <summary>
            /// 自动升级模式:当前仅支持HTTP
            /// </summary>
            public string AutoUpdateMode { get; set; }
    
            /// <summary>
            /// HTTP自动升级模式时的URL地址
            /// </summary>
            public string AutoUpdateHttpUrl { get; set; }
        }
    AutoUpdateConfig.cs

    作用:自动更新内容信息。

        /// <summary>
        /// 自动更新内容信息
        /// </summary>
        [Serializable]
        public class AutoUpdateInfo
        {
            /// <summary>
            /// 新版本号
            /// </summary>
            public string NewVersion { get; set; }
    
            /// <summary>
            /// 更新日期
            /// </summary>
            public string UpdateTime { get; set; }
    
            /// <summary>
            /// 更新内容说明
            /// </summary>
            public string UpdateContent { get; set; }
    
            /// <summary>
            /// 更新文件列表
            /// </summary>
            public List<string> FileList { get; set; }
        }
    AutoUpdateInfo.cs

    6.2、通用类

    作用:应用程序全局静态常量。全局参数都在此设置,方便统一管理。

        /// <summary>
        /// 应用程序全局静态常量
        /// </summary>
        public static class GlobalParam
        {
            /// <summary>
            /// 调用程序主线程名称
            /// </summary>
            public static string MainProcess = string.Empty;
    
            /// <summary>
            /// 远程更新程序所在文件夹的名称
            /// </summary>
            public static string RemoteDir = string.Empty;
        }
    GlobalParam.cs

    6.3、Window 窗体

    新建一个Windows 窗体HttpStartUp。

        public partial class HttpStartUp : Form
        {
            private bool _blSuccess = false;
            private string _autoUpdateHttpUrl = null;
            private AutoUpdateInfo _autoUpdateInfo = null;
    
            public HttpStartUp(string autoUpdateHttpUrl, AutoUpdateInfo autoUpdateInfo)
            {
                InitializeComponent();
                _autoUpdateHttpUrl = autoUpdateHttpUrl;
                _autoUpdateInfo = autoUpdateInfo;
                _blSuccess = false;
            }
    
            /// <summary>
            /// 窗体加载事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Main_Load(object sender, EventArgs e)
            {
                Text = GlobalParam.MainProcess + "-更新程序";
                lblUpdateTime.Text = _autoUpdateInfo.UpdateTime;
                lblNewVersion.Text = _autoUpdateInfo.NewVersion;
                txtUpdate.Text = _autoUpdateInfo.UpdateContent;
            }
    
            /// <summary>
            /// 立即更新
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnRun_Click(object sender, EventArgs e)
            {
                ProcessUtility.KillProcess(GlobalParam.MainProcess);
                btnRun.Enabled = false;
                btnLeave.Enabled = false;
                
                Thread thread = new Thread(() =>
                {
                    try
                    {
                        var downFileList = _autoUpdateInfo.FileList.OrderByDescending(s => s.IndexOf("\"));
                        foreach (var fileName in downFileList)
                        {
                            string fileUrl = string.Empty, fileVaildPath = string.Empty;
                            if (fileName.StartsWith("\"))
                            {
                                fileVaildPath = fileName.Substring(fileName.IndexOf("\"));
                            }
                            else
                            {
                                fileVaildPath = fileName;
                            }
                            fileUrl = _autoUpdateHttpUrl.TrimEnd(new char[] { '/' }) + @"/" + GlobalParam.RemoteDir + @"/" + fileVaildPath.Replace("\", "/");    //替换文件目录中的路径为网络路径
                            DownloadFileDetail(fileUrl, fileName);
                        }
                        _blSuccess = true;
                    }
                    catch (Exception ex)
                    {
                        BeginInvoke(new MethodInvoker(() =>
                        {
                            throw ex;
                        }));
                    }
                    finally
                    {
                        BeginInvoke(new MethodInvoker(delegate ()
                        {
                            btnRun.Enabled = true;
                            btnLeave.Enabled = true;
                        }));
                    }
                    if (_blSuccess)
                    {
                        Process.Start(GlobalParam.MainProcess + ".exe");
                        BeginInvoke(new MethodInvoker(delegate ()
                        {
                            Close();
                            Application.Exit();
                        }));
                    }
                })
                {
                    IsBackground = true
                };
                thread.Start();
            }
    
            private void DownloadFileDetail(string httpUrl, string filename)
            {
                string fileName = Application.StartupPath + "\" + filename;
                string dirPath = GetDirPath(fileName);
                if (!Directory.Exists(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(httpUrl);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream httpStream = response.GetResponseStream();
                long totalBytes = response.ContentLength;
                if (progressBar != null)
                {
                    BeginInvoke(new MethodInvoker(delegate ()
                    {
                        lblDownInfo.Text = "开始下载...";
                        progressBar.Maximum = (int)totalBytes;
                        progressBar.Minimum = 0;
                    }));
                }
                FileStream outputStream = new FileStream(fileName, FileMode.Create);
                int bufferSize = 2048;
                int readCount;
                byte[] buffer = new byte[bufferSize];
                readCount = httpStream.Read(buffer, 0, bufferSize);
                int allByte = (int)response.ContentLength;
                int startByte = 0;
                BeginInvoke(new MethodInvoker(delegate ()
                {
                    progressBar.Maximum = allByte;
                    progressBar.Minimum = 0;
                }));
                while (readCount > 0)
                {
                    outputStream.Write(buffer, 0, readCount);
                    readCount = httpStream.Read(buffer, 0, bufferSize);
                    startByte += readCount;
                    BeginInvoke(new MethodInvoker(delegate ()
                    {
                        lblDownInfo.Text = "已下载:" + startByte / 1024 + "KB/" + "总长度:"+ allByte / 1024 + "KB" + " " + " 文件名:" + filename;         
                        progressBar.Value = startByte;
                    }));
                    Application.DoEvents();
                    Thread.Sleep(5);
                }
                BeginInvoke(new MethodInvoker(delegate ()
                {
                    lblDownInfo.Text = "下载完成。";
                }));
                httpStream.Close();
                outputStream.Close();
                response.Close();
            }
    
            public static string GetDirPath(string filePath)
            {
                if (filePath.LastIndexOf("\") > 0)
                {
                    return filePath.Substring(0, filePath.LastIndexOf("\"));
                }
                return filePath;
            }
    
            /// <summary>
            /// 暂不更新
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnLeave_Click(object sender, EventArgs e)
            {
                if (MessageBox.Show("确定要放弃此次更新吗?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    Process.Start(GlobalParam.MainProcess + ".exe", "false");
                    Close();
                    Application.Exit();
                }
            }      
        }
    HttpStartUp.cs

    6.4、应用程序主入口

        internal static class Program
        {
            /// <summary>
            /// 应用程序的主入口点
            /// </summary>
            [STAThread]
            private static void Main(string[] args)
            {
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                #region 测试
                //string strArgs = @"E:LinkTo.AutoUpdaterAutoUpdaterTestinDebugTempAutoUpdateConfig.xml"+" "+@"E:LinkTo.AutoUpdaterAutoUpdaterTestinDebugTempAutoUpdateInfo.xml"+" "+"AutoUpdaterTest"+" "+"AutoUpdateFiles";
                //args = strArgs.Split(' ');
                #endregion
    
                if (args.Length > 0)
                {
                    string autoUpdateConfigXmlPath = args[0].ToString();
                    string autoUpdateInfoXmlPath = args[1].ToString();
                    GlobalParam.MainProcess = args[2].ToString();
                    GlobalParam.RemoteDir = args[3].ToString();
    
                    var autoUpdateConfigXml = FileUtility.ReadFile(autoUpdateConfigXmlPath);
                    var autoUpdateInfoXml = FileUtility.ReadFile(autoUpdateInfoXmlPath);
                    AutoUpdateConfig config = XmlUtility.Deserialize(typeof(AutoUpdateConfig), autoUpdateConfigXml) as AutoUpdateConfig;
                    AutoUpdateInfo info = XmlUtility.Deserialize(typeof(AutoUpdateInfo), autoUpdateInfoXml) as AutoUpdateInfo;
    
                    if (config.AutoUpdateMode.ToUpper() == "HTTP")
                    {
                        Application.Run(new HttpStartUp(config.AutoUpdateHttpUrl, info));
                    }
                }
                else
                {
                    Application.Exit();
                }
            }
    
            /// <summary>
            /// UI线程未捕获异常处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            public static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
            {
                string strError = "", strLog = "", strDateInfo = DateTime.Now.ToString() + " 出现应用程序未处理的异常:
    ";
                var error = e.Exception;
    
                if (error != null)
                {
                    strError = strDateInfo + $"异常类型:{error.GetType().Name}
    异常消息:{error.Message}";
                    strLog = strDateInfo + $"异常类型:{error.GetType().Name}
    异常消息:{error.Message}
    堆栈信息:{error.StackTrace}
    来源信息:{error.Source}
    ";
                }
                else
                {
                    strError = $"Application ThreadException:{e}";
                }
    
                WriteLog(strLog);
                MessageBox.Show(strError, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
    
            /// <summary>
            /// 非UI线程未捕获异常处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                string strError = "", strLog = "", strDateInfo = DateTime.Now.ToString() + " 出现应用程序未处理的异常:
    ";
    
                if (e.ExceptionObject is Exception error)
                {
                    strError = strDateInfo + $"异常消息:{error.Message}";
                    strLog = strDateInfo + $"异常消息:{error.Message}
    堆栈信息:{error.StackTrace}";
                }
                else
                {
                    strError = $"Application UnhandledError:{e}";
                }
    
                WriteLog(strLog);
                MessageBox.Show(strError, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
    
            /// <summary>
            /// 写入日志
            /// </summary>
            /// <param name="strLog"></param>
            private static void WriteLog(string strLog)
            {
                string dirPath = @"LogAutoUpdater", fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                string strLine = "----------------------------------------------------------------------------------------------------";
    
                FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLog);
                FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLine);
            }
        }
    Program.cs

    七、AutoUpdateXmlBuilder

    7.1、实体类

    作用:自动更新内容信息。

        /// <summary>
        /// 自动更新内容信息
        /// </summary>
        [Serializable]
        public class AutoUpdateInfo
        {
            /// <summary>
            /// 新版本号
            /// </summary>
            public string NewVersion { get; set; }
    
            /// <summary>
            /// 更新日期
            /// </summary>
            public string UpdateTime { get; set; }
    
            /// <summary>
            /// 更新内容说明
            /// </summary>
            public string UpdateContent { get; set; }
    
            /// <summary>
            /// 更新文件列表
            /// </summary>
            public List<string> FileList { get; set; }
        }
    AutoUpdateInfo.cs

    7.2、通用类

    作用:应用程序全局静态常量。全局参数都在此设置,方便统一管理。

        /// <summary>
        /// 应用程序全局静态常量
        /// </summary>
        public static class GlobalParam
        {
            /// <summary>
            /// 远端自动更新信息XML文件名
            /// </summary>
            public const string AutoUpdateInfo_XmlFileName = "AutoUpdateInfo.xml";
    
            /// <summary>
            /// 远端自动更新目录
            /// </summary>
            public const string AutoUpdateDir = "AutoUpdateDir";
    
            /// <summary>
            /// 远端自动更新文件存放目录
            /// </summary>
            public const string RemoteDir = "AutoUpdateFiles";
    
            /// <summary>
            /// 主线程名
            /// </summary>
            public const string MainProcess = "AutoUpdaterTest";
        }
    GlobalParam.cs

    7.3、Window 窗体

    1)新建一个Windows 窗体Main。

        public partial class Main : Form
        {
            //自动更新目录路径
            private static readonly string AutoUpdateDirPath = Application.StartupPath + @"" + GlobalParam.AutoUpdateDir;
            //自动更新信息XML文件路径
            private static readonly string AutoUpdateInfoXmlPath = Path.Combine(AutoUpdateDirPath, GlobalParam.AutoUpdateInfo_XmlFileName);
            //自动更新文件目录路径
            private static readonly string RemoteDirPath = Application.StartupPath + @"" + GlobalParam.AutoUpdateDir + @"" + GlobalParam.RemoteDir;
    
            public Main()
            {
                InitializeComponent();
            }
    
            /// <summary>
            /// 窗体加载
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Main_Load(object sender, EventArgs e)
            {
                if (!Directory.Exists(RemoteDirPath))
                {
                    Directory.CreateDirectory(RemoteDirPath);
                }
                LoadBaseInfo();
                LoadDirectoryFileList();
            }
    
            /// <summary>
            /// 刷新
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnRefresh_Click(object sender, EventArgs e)
            {
                LoadBaseInfo();
                LoadDirectoryFileList();
            }
    
            /// <summary>
            /// 初始化
            /// </summary>
            private void LoadBaseInfo()
            {
                dtUpdateTime.Text = DateTime.Now.ToString("yyyy-MM-dd");
                txtNewVersion.Text = GetMainProcessFileVersion();
                CreateHeaderAndFillListView();
            }
    
            /// <summary>
            /// 获取主程序文件版本
            /// </summary>
            /// <returns></returns>
            private string GetMainProcessFileVersion()
            {
                string fileVersion = "";
                if (File.Exists(RemoteDirPath + "\" + GlobalParam.MainProcess + ".exe"))   //如果更新中有主程序文件
                {
                    FileVersionInfo info = FileVersionInfo.GetVersionInfo(RemoteDirPath + "\" + GlobalParam.MainProcess + ".exe");
                    fileVersion = info.FileVersion;
                }
                return fileVersion;
            }
    
            /// <summary>
            /// 添加ListView列名
            /// </summary>
            private void CreateHeaderAndFillListView()
            {
                lstFileList.Columns.Clear();
                int lvWithd = lstFileList.Width;
                ColumnHeader columnHeader;
    
                //First Header
                columnHeader = new ColumnHeader
                {
                    Text = "#",
                    Width = 38
                };
                lstFileList.Columns.Add(columnHeader);
    
                //Second Header
                columnHeader = new ColumnHeader
                {
                    Text = "文件名",
                    Width = (lvWithd - 38) / 2
                };
                lstFileList.Columns.Add(columnHeader);
    
                //Third Header
                columnHeader = new ColumnHeader
                {
                    Text = "更新路径",
                    Width = (lvWithd - 38) / 2
                };
                lstFileList.Columns.Add(columnHeader);
            }
    
            /// <summary>
            /// 加载目录文件列表
            /// </summary>
            private void LoadDirectoryFileList()
            {
                if (!Directory.Exists(RemoteDirPath))
                {
                    Directory.CreateDirectory(RemoteDirPath);
                }
                FileHelper fileHelper = new FileHelper(RemoteDirPath);
                var fileArrary = fileHelper.GetUpdateList(fileHelper.GetAllFilesInDirectory(RemoteDirPath)).ToList();
                var lastFile = fileArrary.FirstOrDefault(s => s == GlobalParam.MainProcess + ".exe");
                //exe作为最后的文件更新,防止更新过程中出现网络错误,导致文件未全部更新。
                if (lastFile != null)
                {
                    fileArrary.Remove(lastFile);
                    fileArrary.Add(lastFile);
                }
                PopulateListViewWithArray(fileArrary.ToArray());
            }
    
            /// <summary>
            /// 使用路径字符数组填充列表
            /// </summary>
            /// <param name="strArray"></param>
            private void PopulateListViewWithArray(string[] strArray)
            {
                lstFileList.Items.Clear();
                if (strArray != null)
                {
                    //只过滤根目录下的特殊文件
                    strArray = strArray.Where(s => !new string[] { GlobalParam.AutoUpdateInfo_XmlFileName }.Contains(s.Substring(s.IndexOf('\') + 1))).ToArray();
                    for (int i = 0; i < strArray.Length; i++)
                    {
                        ListViewItem lvi = new ListViewItem
                        {
                            Text = (i + 1).ToString()
                        };
                        int intStart = strArray[i].LastIndexOf('\') + 1;
                        lvi.SubItems.Add(strArray[i].Substring(intStart, strArray[i].Length - intStart));
                        lvi.SubItems.Add(strArray[i]);
                        lstFileList.Items.Add(lvi);
                    }
                }
            }
    
            /// <summary>
            /// 生成更新XML文件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnBuild_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtNewVersion.Text))
                {
                    MessageBox.Show("更新版本号不能为空。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    txtNewVersion.Focus();
                    return;
                }
    
                if (string.IsNullOrEmpty(txtMainProcessName.Text))
                {
                    MessageBox.Show("主进程名不能为空。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    txtMainProcessName.Focus();
                    return;
                }
    
                AutoUpdateInfo info = new AutoUpdateInfo()
                {
                    NewVersion = txtNewVersion.Text.Trim(),
                    UpdateTime = dtUpdateTime.Value.ToString("yyyy-MM-dd"),
                    UpdateContent = txtUpdateContent.Text,
                    FileList = lstFileList.Items.Cast<ListViewItem>().Select(s => s.SubItems[2].Text).ToList()
                };
    
                string xmlValue = XmlUtility.Serializer(typeof(AutoUpdateInfo), info);
                using (StreamWriter sw = new StreamWriter(AutoUpdateInfoXmlPath))
                {
                    sw.WriteLine(xmlValue);
                    sw.Flush();
                    sw.Close();
                }
                MessageBox.Show("生成成功。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
    
            /// <summary>
            /// 打开本地目录
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnOpen_Click(object sender, EventArgs e)
            {
                ProcessStartInfo psi = new ProcessStartInfo("Explorer.exe")
                {
                    Arguments = AutoUpdateDirPath
                };
                Process.Start(psi);
            }
        }
    Main.cs

    2)在binDebug下新建一个AutoUpdateDir文件夹,然后再在AutoUpdateDir下新建一个AutoUpdateFiles文件夹。

    3)在AutoUpdaterTest中,将程序集版本及文件版本都改成1.0.0.1并重新生成,接着将AutoUpdaterTest.exe拷贝到AutoUpdateFiles下,最后将程序集版本及文件版本都改回1.0.0.0。

    4)此时运行AutoUpdateXmlBuilder,点击生成更新XML文件即打包成功。程序会自动在AutoUpdateDir下生成打包信息文件AutoUpdateInfo.xml。

    7.4、应用程序主入口

        internal static class Program
        {
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            [STAThread]
            private static void Main()
            {
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Main());
            }
    
            /// <summary>
            /// UI线程未捕获异常处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            public static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
            {
                string strError = "", strLog = "", strDateInfo = DateTime.Now.ToString() + " 出现应用程序未处理的异常:
    ";
                var error = e.Exception;
    
                if (error != null)
                {
                    strError = strDateInfo + $"异常类型:{error.GetType().Name}
    异常消息:{error.Message}";
                    strLog = strDateInfo + $"异常类型:{error.GetType().Name}
    异常消息:{error.Message}
    堆栈信息:{error.StackTrace}
    来源信息:{error.Source}
    ";
                }
                else
                {
                    strError = $"Application ThreadException:{e}";
                }
    
                WriteLog(strLog);
                MessageBox.Show(strError, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
    
            /// <summary>
            /// 非UI线程未捕获异常处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                string strError = "", strLog = "", strDateInfo = DateTime.Now.ToString() + " 出现应用程序未处理的异常:
    ";
    
                if (e.ExceptionObject is Exception error)
                {
                    strError = strDateInfo + $"异常消息:{error.Message}";
                    strLog = strDateInfo + $"异常消息:{error.Message}
    堆栈信息:{error.StackTrace}";
                }
                else
                {
                    strError = $"Application UnhandledError:{e}";
                }
    
                WriteLog(strLog);
                MessageBox.Show(strError, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
    
            /// <summary>
            /// 写入日志
            /// </summary>
            /// <param name="strLog"></param>
            private static void WriteLog(string strLog)
            {
                string dirPath = @"LogXmlBuilder", fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                string strLine = "----------------------------------------------------------------------------------------------------";
    
                FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLog);
                FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLine);
            }
        }
    Program.cs

    八、远程服务端配置

    注:此处为本机测试。

    1)在某个盘符如E盘下新建一个AutoUpdate文件夹,将AutoUpdateXmlBuilder打包文件夹AutoUpdateDir拷贝到AutoUpdate文件夹下。

    2)在IIS中新建一个网站,对应的虚拟目录为E:AutoUpdate,同时将端口设置为6600。

    3)运行AutoUpdaterTest,如出现自动更新器即代表成功。

    源码下载

  • 相关阅读:
    Allegro PCB Design GXL (legacy) 使用slide无法将走线推挤到焊盘的原因
    OrCAD Capture CIS 16.6 导出BOM
    Altium Designer (17.0) 打印输出指定的层
    Allegro PCB Design GXL (legacy) 将指定的层导出为DXF
    Allegro PCB Design GXL (legacy) 设置十字大光标
    Allegro PCB Design GXL (legacy) 手动更改元器件引脚的网络
    magento产品导入时需要注意的事项
    magento url rewrite
    验证台湾同胞身份证信息
    IE8对css文件的限制
  • 原文地址:https://www.cnblogs.com/atomy/p/15260695.html
Copyright © 2011-2022 走看看