C# WinForm universal automatic updater

C# WinForm universal automatic updater

 

1, Introduction

For C/S architecture, software update is a very common function. Here is a very practical automatic software upgrade scheme.

2, Schematic diagram

3, Project description

3.1 project creation

Create 4 new projects as follows:

3.2 project relationship

4, LinkTo.Toolkit

LinkTo.Toolkit is mainly some Utility and Helper files to realize the functions of conversion and expansion, file reading and writing, process processing, etc.

    /// <summary>
    /// Transform extension class
    /// </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 Convert to entity class
        /// </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>
        /// Universal simple entity type conversion
        /// </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 type
                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>
        /// Universal simple entity type conversion
        /// </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>
        /// Convert to DataTable,If there is no data row in the collection, an exception will be thrown.
        /// </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]Represents an object, list When there are no rows, exceptions will be thrown.
                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))    //Filter properties with indexers
                    {
                        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();   //Filter properties with indexers
                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>
        /// Entity class public attribute value replication
        /// </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);   //Create reference object
                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;
        }
    }
    public class FileHelper
    {
        private readonly string strUpdateFilesPath;

        public FileHelper(string strDirector)
        {
            strUpdateFilesPath = strDirector;
        }

        //Save all file information
        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>
        /// Delete all files in the folder without deleting the directory
        /// </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);
            }
        }
    }
    public static class FileUtility
    {
        #region read file
        /// <summary>
        /// read file
        /// </summary>
        /// <param name="filePath">File path</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 read file

        #region write file
        /// <summary>
        /// write file
        /// </summary>
        /// <param name="filePath">File path</param>
        /// <param name="strValue">Write content</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 Delete file
        /// <summary>
        /// Delete file
        /// </summary>
        /// <param name="filePath">File path</param>
        /// <returns></returns>
        public static bool DeleteFile(string filePath)
        {
            try
            {
                File.Delete(filePath);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        #endregion Delete file

        #region Add full control permissions for user groups to files
        /// <summary>
        /// Add full control permissions for user groups to files
        /// </summary>
        /// <param name="userGroup">User group</param>
        /// <param name="filePath">File path</param>
        /// <returns></returns>
        public static bool AddSecurityControll2File(string userGroup, string filePath)
        {
            try
            {
                //Get file information
                FileInfo fileInfo = new FileInfo(filePath);
                //Gain access to the file
                FileSecurity fileSecurity = fileInfo.GetAccessControl();
                //Add access rules for user groups--Full control authority
                fileSecurity.AddAccessRule(new FileSystemAccessRule(userGroup, FileSystemRights.FullControl, AccessControlType.Allow));
                //Set access rights
                fileInfo.SetAccessControl(fileSecurity);
                //Return results
                return true;
            }
            catch (Exception)
            {
                //Return results
                return false;
            }
        }
        #endregion

        #region Add full control permissions for the user group for the folder
        /// <summary>
        /// Add full control permissions for the user group for the folder
        /// </summary>
        /// <param name="userGroup">User group</param>
        /// <param name="dirPath">Folder path</param>
        /// <returns></returns>
        public static bool AddSecurityControll2Folder(string userGroup,string dirPath)
        {
            try
            {
                //Get folder information
                DirectoryInfo dir = new DirectoryInfo(dirPath);
                //Get all access to this folder
                DirectorySecurity dirSecurity = dir.GetAccessControl(AccessControlSections.All);
                //Setting file ACL inherit
                InheritanceFlags inherits = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
                //Add access rules for user groups--Full control authority
                FileSystemAccessRule usersFileSystemAccessRule = new FileSystemAccessRule(userGroup, FileSystemRights.FullControl, inherits, PropagationFlags.None, AccessControlType.Allow);
                dirSecurity.ModifyAccessRule(AccessControlModification.Add, usersFileSystemAccessRule, out bool isModified);
                //Set access rights
                dir.SetAccessControl(dirSecurity);
                //Return results
                return true;
            }
            catch (Exception)
            {
                //Return results
                return false;
            }
        }
        #endregion
    }
    public static class ProcessUtility
    {
        #region Close process
        /// <summary>
        /// Close process
        /// </summary>
        /// <param name="processName">Process name</param>
        public static void KillProcess(string processName)
        {
            Process[] myproc = Process.GetProcesses();
            foreach (Process item in myproc)
            {
                if (item.ProcessName == processName)
                {
                    item.Kill();
                }
            }
        }
        #endregion
    }
    /// <summary>
    /// Xml Serializable and Deserialize 
    /// </summary>
    public static class XmlUtility
    {
        #region serialize

        /// <summary>
        /// serialize
        /// </summary>
        /// <param name="type">type</param>
        /// <param name="obj">object</param>
        /// <returns></returns>
        public static string Serializer(Type type, object obj)
        {
            MemoryStream Stream = new MemoryStream();
            XmlSerializer xml = new XmlSerializer(type);
            try
            {
                //serialized objects 
                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 serialize

        #region Deserialization

        /// <summary>
        /// Deserialization
        /// </summary>
        /// <param name="type">type</param>
        /// <param name="xml">XML character string</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>
        /// Deserialization
        /// </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 Deserialization
    }

5, AutoUpdaterTest

5.1 entity class

Role: locally configure the serialization and deserialization of the AutoUpdateConfig.xml file.

    public class AutoUpdateConfig
    {
        /// <summary>
        /// Automatic upgrade mode: currently only supported HTTP
        /// </summary>
        public string AutoUpdateMode { get; set; }

        /// <summary>
        /// HTTP In auto upgrade mode URL address
        /// </summary>
        public string AutoUpdateHttpUrl { get; set; }
    }

5.2 general

Function: application global static constant. Global parameters are set here for unified management. Note: whether the client detects updates is also the default value set here.

    /// <summary>
    /// Application global static constants
    /// </summary>
    public static class GlobalParam
    {
        #region Automatically update parameters
        /// <summary>
        /// Check for automatic updates: Yes by default true
        /// </summary>
        public static string CheckAutoUpdate = "true";

        /// <summary>
        /// Local automatic update configuration XML file name
        /// </summary>
        public const string AutoUpdateConfig_XmlFileName = "AutoUpdateConfig.xml";

        /// <summary>
        /// Local automatic update download temporary storage directory
        /// </summary>
        public const string TempDir = "Temp";

        /// <summary>
        /// Remote automatic update information XML file name
        /// </summary>
        public const string AutoUpdateInfo_XmlFileName = "AutoUpdateInfo.xml";

        /// <summary>
        /// Remote automatic update of file storage directory
        /// </summary>
        public const string RemoteDir = "AutoUpdateFiles";

        /// <summary>
        /// Main thread name
        /// </summary>
        public const string MainProcess = "AutoUpdaterTest";
        #endregion
    }

Role: application context.

    /// <summary>
    /// Application context
    /// </summary>
    public class AppContext
    {
        /// <summary>
        /// Client profile
        /// </summary>
        public static AutoUpdateConfig AutoUpdateConfigData { get; set; }
    }

Role: application configuration.

    public class AppConfig
    {
        private static readonly object _lock = new object();
        private static AppConfig _instance = null;

        #region Automatic update configuration
        /// <summary>
        /// Automatically update configuration data
        /// </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>
        /// Local automatic update download temporary folder path
        /// </summary>
        public string TempPath
        {
            get
            {
                return string.Format("{0}\\{1}", Application.StartupPath, GlobalParam.TempDir);
            }
        }

        /// <summary>
        /// Initialize system configuration information
        /// </summary>
        public void InitialSystemConfig()
        {
            AutoUpdateConfigData.AutoUpdateMode = AppContext.AutoUpdateConfigData.AutoUpdateMode;
            AutoUpdateConfigData.AutoUpdateHttpUrl = AppContext.AutoUpdateConfigData.AutoUpdateHttpUrl;
        }
        #endregion
    }

5.3 tools

Function: read and write configuration files.

    public class AutoUpdateHelper
    {
        private readonly string AutoUpdateMode = string.Empty;

        public AutoUpdateHelper(string autoUpdateMode)
        {
            AutoUpdateMode = autoUpdateMode;
        }

        /// <summary>
        /// Load local automatic update profile
        /// </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>
        /// Get the version number of remote automatic update information
        /// </summary>
        /// <returns></returns>
        public string GetRemoteAutoUpdateInfoVersion()
        {
            XDocument doc = new XDocument();
            doc = XDocument.Parse(GetRemoteAutoUpdateInfoXml());
            return doc.Element("AutoUpdateInfo").Element("NewVersion").Value;
        }

        /// <summary>
        /// Get remote automatic update information XML File content
        /// </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>
        /// Write to local auto update configuration XML File content
        /// </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 : "";
        }
    }

5.4. Local configuration file

Function: configure automatic update mode and related.

Note 1: to copy to the output directory, select always copy.

Note 2: when the main program is running, first read the configuration update file, then assign a value to the AppContext context, and then assign a value to the AppConfig configuration.

<?xml version="1.0" encoding="utf-8" ?>
<AutoUpdateConfig>
  <!--Automatic upgrade mode: currently only supported HTTP-->
  <AutoUpdateMode>HTTP</AutoUpdateMode>
  <!--HTTP In auto upgrade mode URL address-->
  <AutoUpdateHttpUrl>http://127.0.0.1:6600/AutoUpdateDir</AutoUpdateHttpUrl>
</AutoUpdateConfig>

5.5 main program

Create a new Windows   Form MainForm, this processing only needs a blank form for test trial.

    public partial class MainForm : Form
    {
        private static MainForm _Instance;

        /// <summary>
        /// MainForm Main form instance
        /// </summary>
        public static MainForm Instance
        {
            get
            {
                if (_Instance == null)
                {
                    _Instance = new MainForm();
                }
                return _Instance;
            }
        }

        public MainForm()
        {
            InitializeComponent();
        }
    }

5.6. Application main entrance

Function: check whether the application needs to be updated automatically. If necessary, check the version number of the remote server. If the remote server has a new version, call the automatic updater AutoUpdater and pass four parameters to it.

    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application
        /// </summary>
        [STAThread]
        private static void Main(string[] args)
        {
            //Attempt to set access
            FileUtility.AddSecurityControll2Folder("Users", Application.StartupPath);

            //Uncapped exception handling
            Application.ThreadException += Application_ThreadException;
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            //Check automatic update assignment
            if (args.Length > 0)
            {
                GlobalParam.CheckAutoUpdate = args[0];
            }

            //Load the automatic update configuration file to the context AppServiceConfig Object assignment.
            var config = AutoUpdateHelper.Load();
            AppContext.AutoUpdateConfigData = config;

            //Form mutex
            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("A program has been started. Please exit first.", "Tips", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
            }
        }

        /// <summary>
        /// Automatic update detection
        /// </summary>
        /// <returns></returns>
        private static bool CheckUpdater()
        {
            if (GlobalParam.CheckAutoUpdate.ToBoolean() == false) return false;

            #region Check for version updates
            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 The thread did not catch exception handling
        /// </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() + " An exception occurred that was not handled by the application:\r\n";
            var error = e.Exception;

            if (error != null)
            {
                strError = strDateInfo + $"Exception type:{error.GetType().Name}\r\n Exception message:{error.Message}";
                strLog = strDateInfo + $"Exception type:{error.GetType().Name}\r\n Exception message:{error.Message}\r\n Stack information:{error.StackTrace}\r\n Source information:{error.Source}\r\n";
            }
            else
            {
                strError = $"Application ThreadException: {e}";
            }

            WriteLog(strLog);
            MessageBox.Show(strError, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// wrong UI The thread did not catch exception handling
        /// </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() + " An exception occurred that was not handled by the application:\r\n";

            if (e.ExceptionObject is Exception error)
            {
                strError = strDateInfo + $"Exception message:{error.Message}";
                strLog = strDateInfo + $"Exception message:{error.Message}\r\n Stack information:{error.StackTrace}";
            }
            else
            {
                strError = $"Application UnhandledError: {e}";
            }

            WriteLog(strLog);
            MessageBox.Show(strError, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// Write log
        /// </summary>
        /// <param name="strLog"></param>
        private static void WriteLog(string strLog)
        {
            string dirPath = @"Log\MainProcess", fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
            string strLine = "----------------------------------------------------------------------------------------------------";

            FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLog);
            FileUtility.WriteFile(Path.Combine(dirPath,fileName), strLine);
        }
    }

6, AutoUpdater

6.1 entity class

Function: configure automatic update mode and related.

    /// <summary>
    /// Automatically update configuration information
    /// </summary>
    public class AutoUpdateConfig
    {
        /// <summary>
        /// Automatic upgrade mode: currently only supported HTTP
        /// </summary>
        public string AutoUpdateMode { get; set; }

        /// <summary>
        /// HTTP In auto upgrade mode URL address
        /// </summary>
        public string AutoUpdateHttpUrl { get; set; }
    }

Function: automatically update content information.

    /// <summary>
    /// Automatically update content information
    /// </summary>
    [Serializable]
    public class AutoUpdateInfo
    {
        /// <summary>
        /// New version number
        /// </summary>
        public string NewVersion { get; set; }

        /// <summary>
        /// Update date
        /// </summary>
        public string UpdateTime { get; set; }

        /// <summary>
        /// Update content description
        /// </summary>
        public string UpdateContent { get; set; }

        /// <summary>
        /// Update file list
        /// </summary>
        public List<string> FileList { get; set; }
    }

6.2 general

Function: application global static constant. Global parameters are set here for unified management.

    /// <summary>
    /// Application global static constants
    /// </summary>
    public static class GlobalParam
    {
        /// <summary>
        /// Caller main thread name
        /// </summary>
        public static string MainProcess = string.Empty;

        /// <summary>
        /// The name of the folder where the remote updater is located
        /// </summary>
        public static string RemoteDir = string.Empty;
    }

6.3,Window   forms

Create a new Windows   Form 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>
        /// Form load event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_Load(object sender, EventArgs e)
        {
            Text = GlobalParam.MainProcess + "-Update program";
            lblUpdateTime.Text = _autoUpdateInfo.UpdateTime;
            lblNewVersion.Text = _autoUpdateInfo.NewVersion;
            txtUpdate.Text = _autoUpdateInfo.UpdateContent;
        }

        /// <summary>
        /// Update now
        /// </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("\\", "/");    //Replace the path in the file directory with the network path
                        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 = "Start downloading...";
                    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 = "Downloaded:" + startByte / 1024 + "KB/" + "Total length:"+ allByte / 1024 + "KB" + " " + " File name:" + filename;         
                    progressBar.Value = startByte;
                }));
                Application.DoEvents();
                Thread.Sleep(5);
            }
            BeginInvoke(new MethodInvoker(delegate ()
            {
                lblDownInfo.Text = "Download complete.";
            }));
            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>
        /// Not updated
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLeave_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure you want to discard this update?", "Tips", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                Process.Start(GlobalParam.MainProcess + ".exe", "false");
                Close();
                Application.Exit();
            }
        }      
    }

6.4. Application main entrance

    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application
        /// </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 test
            //string strArgs = @"E:\LinkTo.AutoUpdater\AutoUpdaterTest\bin\Debug\Temp\AutoUpdateConfig.xml"+" "+@"E:\LinkTo.AutoUpdater\AutoUpdaterTest\bin\Debug\Temp\AutoUpdateInfo.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 The thread did not catch exception handling
        /// </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() + " An exception occurred that was not handled by the application:\r\n";
            var error = e.Exception;

            if (error != null)
            {
                strError = strDateInfo + $"Exception type:{error.GetType().Name}\r\n Exception message:{error.Message}";
                strLog = strDateInfo + $"Exception type:{error.GetType().Name}\r\n Exception message:{error.Message}\r\n Stack information:{error.StackTrace}\r\n Source information:{error.Source}\r\n";
            }
            else
            {
                strError = $"Application ThreadException: {e}";
            }

            WriteLog(strLog);
            MessageBox.Show(strError, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// wrong UI The thread did not catch exception handling
        /// </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() + " An exception occurred that was not handled by the application:\r\n";

            if (e.ExceptionObject is Exception error)
            {
                strError = strDateInfo + $"Exception message:{error.Message}";
                strLog = strDateInfo + $"Exception message:{error.Message}\r\n Stack information:{error.StackTrace}";
            }
            else
            {
                strError = $"Application UnhandledError: {e}";
            }

            WriteLog(strLog);
            MessageBox.Show(strError, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// Write log
        /// </summary>
        /// <param name="strLog"></param>
        private static void WriteLog(string strLog)
        {
            string dirPath = @"Log\AutoUpdater", fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
            string strLine = "----------------------------------------------------------------------------------------------------";

            FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLog);
            FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLine);
        }
    }

7, AutoUpdateXmlBuilder

7.1 entity class

Function: automatically update content information.

    /// <summary>
    /// Automatically update content information
    /// </summary>
    [Serializable]
    public class AutoUpdateInfo
    {
        /// <summary>
        /// New version number
        /// </summary>
        public string NewVersion { get; set; }

        /// <summary>
        /// Update date
        /// </summary>
        public string UpdateTime { get; set; }

        /// <summary>
        /// Update content description
        /// </summary>
        public string UpdateContent { get; set; }

        /// <summary>
        /// Update file list
        /// </summary>
        public List<string> FileList { get; set; }
    }

7.2 general

Function: application global static constant. Global parameters are set here for unified management.

    /// <summary>
    /// Application global static constants
    /// </summary>
    public static class GlobalParam
    {
        /// <summary>
        /// Remote automatic update information XML file name
        /// </summary>
        public const string AutoUpdateInfo_XmlFileName = "AutoUpdateInfo.xml";

        /// <summary>
        /// Remote auto update directory
        /// </summary>
        public const string AutoUpdateDir = "AutoUpdateDir";

        /// <summary>
        /// Remote automatic update of file storage directory
        /// </summary>
        public const string RemoteDir = "AutoUpdateFiles";

        /// <summary>
        /// Main thread name
        /// </summary>
        public const string MainProcess = "AutoUpdaterTest";
    }

7.3,Window   forms

1) Create a new Windows   Form Main.

    public partial class Main : Form
    {
        //Automatically update directory path
        private static readonly string AutoUpdateDirPath = Application.StartupPath + @"\" + GlobalParam.AutoUpdateDir;
        //Automatically update information XML File path
        private static readonly string AutoUpdateInfoXmlPath = Path.Combine(AutoUpdateDirPath, GlobalParam.AutoUpdateInfo_XmlFileName);
        //Automatically update file directory path
        private static readonly string RemoteDirPath = Application.StartupPath + @"\" + GlobalParam.AutoUpdateDir + @"\" + GlobalParam.RemoteDir;

        public Main()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Form loading
        /// </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>
        /// Refresh
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            LoadBaseInfo();
            LoadDirectoryFileList();
        }

        /// <summary>
        /// initialization
        /// </summary>
        private void LoadBaseInfo()
        {
            dtUpdateTime.Text = DateTime.Now.ToString("yyyy-MM-dd");
            txtNewVersion.Text = GetMainProcessFileVersion();
            CreateHeaderAndFillListView();
        }

        /// <summary>
        /// Get main program file version
        /// </summary>
        /// <returns></returns>
        private string GetMainProcessFileVersion()
        {
            string fileVersion = "";
            if (File.Exists(RemoteDirPath + "\\" + GlobalParam.MainProcess + ".exe"))   //If there is a main program file in the update
            {
                FileVersionInfo info = FileVersionInfo.GetVersionInfo(RemoteDirPath + "\\" + GlobalParam.MainProcess + ".exe");
                fileVersion = info.FileVersion;
            }
            return fileVersion;
        }

        /// <summary>
        /// add to ListView Listing
        /// </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 = "file name",
                Width = (lvWithd - 38) / 2
            };
            lstFileList.Columns.Add(columnHeader);

            //Third Header
            columnHeader = new ColumnHeader
            {
                Text = "Update path",
                Width = (lvWithd - 38) / 2
            };
            lstFileList.Columns.Add(columnHeader);
        }

        /// <summary>
        /// Load directory file list
        /// </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 As the last file update, prevent network errors during the update process, resulting in incomplete file update.
            if (lastFile != null)
            {
                fileArrary.Remove(lastFile);
                fileArrary.Add(lastFile);
            }
            PopulateListViewWithArray(fileArrary.ToArray());
        }

        /// <summary>
        /// Populates the list with an array of path characters
        /// </summary>
        /// <param name="strArray"></param>
        private void PopulateListViewWithArray(string[] strArray)
        {
            lstFileList.Items.Clear();
            if (strArray != null)
            {
                //Filter only special files in the root directory
                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>
        /// Generate update XML file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBuild_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtNewVersion.Text))
            {
                MessageBox.Show("The update version number cannot be empty.", "Tips", MessageBoxButtons.OK, MessageBoxIcon.Information);
                txtNewVersion.Focus();
                return;
            }

            if (string.IsNullOrEmpty(txtMainProcessName.Text))
            {
                MessageBox.Show("The main process name cannot be empty.", "Tips", 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("Generation succeeded.", "Tips", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <summary>
        /// Open local directory
        /// </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);
        }
    }

2) Create a new AutoUpdateDir folder under bin\Debug \, and then create a new AutoUpdateFiles folder under AutoUpdateDir.

3) In AutoUpdaterTest, change the assembly version and file version to 1.0.0.1 and regenerate, then copy AutoUpdaterTest.exe to AutoUpdateFiles, and finally change the assembly version and file version back to 1.0.0.0.

4) Run AutoUpdateXmlBuilder and click generate update XML file to package successfully. The program will automatically generate the packaging information file AutoUpdateInfo.xml under AutoUpdateDir.

7.4 main entrance of application

    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </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 The thread did not catch exception handling
        /// </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() + " An exception occurred that was not handled by the application:\r\n";
            var error = e.Exception;

            if (error != null)
            {
                strError = strDateInfo + $"Exception type:{error.GetType().Name}\r\n Exception message:{error.Message}";
                strLog = strDateInfo + $"Exception type:{error.GetType().Name}\r\n Exception message:{error.Message}\r\n Stack information:{error.StackTrace}\r\n Source information:{error.Source}\r\n";
            }
            else
            {
                strError = $"Application ThreadException: {e}";
            }

            WriteLog(strLog);
            MessageBox.Show(strError, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// wrong UI The thread did not catch exception handling
        /// </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() + " An exception occurred that was not handled by the application:\r\n";

            if (e.ExceptionObject is Exception error)
            {
                strError = strDateInfo + $"Exception message:{error.Message}";
                strLog = strDateInfo + $"Exception message:{error.Message}\r\n Stack information:{error.StackTrace}";
            }
            else
            {
                strError = $"Application UnhandledError: {e}";
            }

            WriteLog(strLog);
            MessageBox.Show(strError, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// Write log
        /// </summary>
        /// <param name="strLog"></param>
        private static void WriteLog(string strLog)
        {
            string dirPath = @"Log\XmlBuilder", fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
            string strLine = "----------------------------------------------------------------------------------------------------";

            FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLog);
            FileUtility.WriteFile(Path.Combine(dirPath, fileName), strLine);
        }
    }

8, Remote server configuration

Note: This is the local test.

1) Create an AutoUpdate folder under a drive letter such as drive E, and copy the AutoUpdateXmlBuilder packaging folder AutoUpdateDir to the AutoUpdate folder.

2) Create a new website in IIS, the corresponding virtual directory is E:\AutoUpdate, and set the port to 6600.

3) Run AutoUpdaterTest. If the automatic updater appears, it means success.

Source download

 
posted @ 2021-09-13 13:16  Ethereal dust  Reading (598)   Comments (12)   edit   

Keywords: C#

Added by runnee on Fri, 03 Dec 2021 09:07:19 +0200