<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      我的服裝DRP之在線升級

      半年前,我辭掉朝八晚十的工作,告別研發部的兄弟和前臺MM,意氣風發地著手開發自己的服裝ERP。之所以這么有魄力,是因為我對當前市場上幾個主流服裝軟件頗不以為然,掂量著在服裝企業干過的這幾年,心說再不瘋狂就太對不起當初放棄寫字樓選擇進廠房的自己了。

      于是開始沒日沒夜地敲鍵盤,經歷無數困惑、失望、憤怒、迷茫、愉悅、興奮,多次大規模項目重構,0次的異性約會之后,到如今產品的分銷部分終于基本成型。這兩天在梳理代碼的過程中,覺得有必要將一些心得體會記錄下來。該記錄會形成一個系列,但并不會系統,屬于揀哪說哪(話說第一篇我原本想寫點關于打印方面的知識)。

      一兩年前,或更早以前,Ajax風靡全球,歷時長久的BS/CS之爭似乎可以蓋棺定論,當時我遇到的幾乎所有程序員都在孜孜不倦地談論著瀏覽器上的那檔子事。時至今日,BS應用仍然比CS更能迎合程序員的口味。不過主模塊架構我依然選擇CS模式,理由我就不贅述了。什么?非得給個說法?那我就陳列若干理由如下:

      1. 瀏覽器不是操作系統。微軟可以將HTML5和JS移入操作系統,卻不能將C#移入瀏覽器。互聯網發展將出現越來越多的應用,總有一天臃腫的瀏覽器會不堪重負,新的應用將只能依靠更多樣的其它技術平臺。你說Silverlight?這玩意我一直不看好,雖然我用WPF好久,雖然WPF程序轉成Silverlight應用號稱非常簡單,但是我從來沒去研究過Silverlight。Silverlight的前景也確實不甚光明。
      2. 隨著網速的提高,我估計CS中Client的概念也將模糊。未來的應用對于客戶端來說,也許就是一個快捷圖標,而指向的地址是服務器,應用程序不需要安裝,只是在需要的時候實時下載到客戶端。
      3. 上述兩條太空泛,也很容易被噴。如果站在客戶的角度,CS更有可能實現他們眾多的“無理要求”。對于服裝系統來說,BS適合數據展現(現在的領導都喜歡拿個IPAD在那算利潤,咱對IOS是外行,只能從瀏覽器上下手)。
      4. ……

      我認為CS的缺點主要在于安裝和升級,前者只能寄希望于上述第2條,咱們可以努力解決的就是版本升級。好的升級功能需要包含以下幾點:

      1. 版本發布工具
      2. 在線自動升級
      3. 運行時手動升級(可選擇升級版本)
      4. 不同客戶不同版本
      5. 可以設置是否強制升級
      6. 版本列表查看
      7. 版本還原(最多只能還原至最近強制升級版本)
      8. 升級失敗后回滾,并讓用戶選擇直接運行程序or重新升級
      9. 刪除過期文件
      10. ……

      上述紅字表示暫時未開發。本著通用的原則,我建了幾個產品無關的類。

      這幾個類簡單明了,無需多做解釋,我們需要的是一個工具來維護它們,下面是其中一個界面的截圖,由于開發倉促,該工具并不完善(我自己用用足矣)。

      不完善的其中一個點我已經在圖中注明,該點產生的原因是由于待更新文件列表支持文件夾,如<filelist><file name="fileA.dll"><directory path="dirA\childDirA"></filelist>,由于涉及到文件夾,路徑問題就出現了,完善該需求需要提供軟件發布根目錄信息和選擇文件和文件夾的樹形結構選擇器。另外這工具并不能說是真正意義上的版本發布,因為它沒有提供上傳文件到服務器的功能。

      當用戶運行軟件時,升級程序(另外一個小程序,專門用于處理版本升級)啟動,檢查軟件配置文件記錄的當前版本,并與數據庫中的版本記錄作一比較,若有強制升級的新版本則自動升級。需要注意的是可能新發布了多個版本,那么我們就要合并重復的文件。以下為主要代碼:

       1 /// <summary>
       2 /// 獲取需要升級的文件和目錄
       3 /// </summary>
       4 /// <param name="softPath">待升級軟件的路徑</param>
       5 private FilesNeedUpdate GetFilesNeedUpdate()
       6 {
       7     if (UpdateSection == null)
       8         return null;
       9     DataSet ds = null;
      10     using (ChannelFactory<IVersionService> channelFactory = new ChannelFactory<IVersionService>("VersionSVC"))
      11     {
      12         IVersionService service = channelFactory.CreateChannel();
      13         //ds = service.GetFilesNeedUpdate(Path.GetFileName(softPath), GetNowVersion(softPath));
      14         ds = service.GetFilesNeedUpdate(UpdateSection.CustomerKey, UpdateSection.SoftKey, UpdateSection.Version);
      15     }
      16     DataTable dt = ds.Tables[0];
      17     if (dt.Rows.Count == 0)
      18         return null;
      19     if (!IsCoerciveUpdate(dt))
      20         return null;
      21     UpdateSection.Version = dt.Rows[0]["VersionCode"].ToString();
      22     List<FileNeedUpdate> files = new List<FileNeedUpdate>();
      23     List<FileNeedUpdate> directories = new List<FileNeedUpdate>();
      24     XmlDocument doc = new XmlDocument();
      25     foreach (DataRow row in dt.Rows)
      26     {
      27         doc.LoadXml(row["UpdatedFileList"].ToString());
      28         var tempFiles = GetNodeNameList(doc.GetElementsByTagName("file")).ToList();
      29         var tempDires = GetNodeNameList(doc.GetElementsByTagName("directory")).ToList();
      30         files = Coverforward(tempFiles, files);
      31         directories = Coverforward(tempDires, directories);
      32     }
      33     return new FilesNeedUpdate { Files = files.ToArray(), Directories = directories.ToArray() };
      34 }
      35 
      36 private IEnumerable<FileNeedUpdate> GetNodeNameList(XmlNodeList nodes)
      37 {
      38     foreach (XmlNode node in nodes)
      39     {
      40         var name = node.Attributes["name"].Value;
      41         FileNeedUpdate item = new FileNeedUpdate { Name = name };
      42         var dnode = node.Attributes["isDelete"];
      43         if (dnode != null)
      44             item.IsDelete = Convert.ToBoolean(dnode.Value);
      45         yield return item;
      46     }
      47 }
      48 
      49 /// <summary>
      50 /// 前向覆蓋
      51 /// </summary>
      52 private List<FileNeedUpdate> Coverforward(List<FileNeedUpdate> filesFormer, List<FileNeedUpdate> filesAfter)
      53 {
      54     var diff = filesFormer.Except(filesAfter);
      55     filesAfter.AddRange(diff);
      56     return filesAfter;
      57 }
      58 
      59 /// <summary>
      60 /// 是否強制更新
      61 /// </summary>
      62 private bool IsCoerciveUpdate(DataTable dt)
      63 {
      64     foreach (var row in dt.Rows)
      65     {
      66         if (Convert.ToBoolean(dt.Rows[0]["IsCoerciveUpdate"]))
      67             return true;
      68     }
      69     return false;
      70 }

      獲取待更新的文件集合后,就可以去服務器端下載了(文件事先上傳到服務器)。為了節省帶寬(用戶可不想浪費太多干正事的時間),先將這些文件在服務器端壓縮后再下載,下載完畢后在客戶端解壓,并將服務器端的壓縮文件刪除。這塊我使用了ICSharpCode.SharpZipLib.dll,挺好用的,就不做贅述了。讓人頭大的是在升級過程中的消息提示需要各種異步,特別在WPF中,由于WPF沒有提供強制刷新界面的方法(有間接方式,但并不推薦),在某些方面令人牙疼。關于WPF中的“異步”編程,我會在以后做一總結。

        1 public partial class MainWindow : Window
        2 {
        3 private WebClient _client;
        4 private string _zipFileName, _mainApp, _bkZipFilePath;
        5 private Dispatcher _dispatcher;
        6 private FilesNeedUpdate _files;
        7 private UpdateHelper _helper;
        8 
        9 public MainWindow()
       10 {
       11     InitializeComponent();
       12     _dispatcher = this.Dispatcher;
       13     _client = new WebClient();
       14     _client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
       15     _client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
       16     _client.Proxy = WebRequest.DefaultWebProxy;
       17     _client.Proxy.Credentials = new NetworkCredential();
       18 }
       19 
       20 public MainWindow(UpdateHelper helper)
       21     : this()
       22 {
       23     _mainApp = helper.SoftPath;
       24     _files = helper.Files;
       25     _helper = helper;
       26     this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
       27 }
       28 
       29 void MainWindow_Loaded(object sender, RoutedEventArgs e)
       30 {
       31     try
       32     {
       33         LoadingLabel.Text = "有新版本發布,正在備份當前文件,請稍候……";
       34         Action bkaction = () => BackUpFiles();
       35         bkaction.BeginInvoke(new AsyncCallback(HandleFilesToUpdate), bkaction);
       36     }
       37     catch (Exception ex)
       38     {
       39         HandleException(ex);
       40     }
       41 }
       42 
       43 private void HandleException(Exception e)
       44 {
       45     _dispatcher.Invoke(new Action(() =>
       46     {
       47         tbError.Text = "系統升級出錯,錯誤原因:" + e.Message;
       48         pnlError.Visibility = Visibility.Visible;
       49     }));
       50 }
       51 
       52 void Init()
       53 {
       54     pnlError.Visibility = Visibility.Collapsed;
       55     this.RadProgressBar1.Value = 0;
       56     PercentageLabel.Text = "";
       57     if (!string.IsNullOrEmpty(_bkZipFilePath) && File.Exists(_bkZipFilePath))
       58         File.Delete(_bkZipFilePath);
       59     _zipFileName = _bkZipFilePath = "";
       60 }
       61 
       62 private void HandleFilesToUpdate(IAsyncResult res)
       63 {
       64     Action action = new Action(() =>
       65     {
       66         try
       67         {
       68             DeleteAbateFiles();
       69             var filesNeedDownload = new FilesNeedUpdate
       70             {
       71                 Files = _files.Files.ToList().FindAll(o => !o.IsDelete).ToArray(),
       72                 Directories = _files.Directories.ToList().FindAll(o => !o.IsDelete).ToArray()
       73             };
       74             if (!filesNeedDownload.IsEmpty)
       75                 StartDownload(filesNeedDownload);
       76             else
       77                 ReStartMainApp();
       78             _helper.SaveNewVersion();
       79         }
       80         catch (Exception ex)
       81         {
       82             HandleException(ex);
       83         }
       84     });
       85     action.BeginInvoke(null, null);
       86 }
       87 
       88 private bool ArrayIsEmpty(Array array)
       89 {
       90     return array == null || array.Length == 0;
       91 }
       92 
       93 private void StartDownload(FilesNeedUpdate files)
       94 {
       95     //var section = _helper.UpdateSection;
       96     //if (section == null || string.IsNullOrEmpty(section.SoftKey))
       97     //{
       98     //    ReStartMainApp();
       99     //}
      100     _dispatcher.Invoke(new Action(() =>
      101     {
      102         LoadingLabel.Text = "新版本文件遠程壓縮中……";
      103     }));//DispatcherPriority.SystemIdle:先繪制完界面再執行這段邏輯
      104     string url;
      105     using (ChannelFactory<IVersionService> channelFactory = new ChannelFactory<IVersionService>("VersionSVC"))
      106     {
      107         IVersionService service = channelFactory.CreateChannel();
      108         _zipFileName = service.CompressFilesNeedUpdate(files);
      109         url = service.GetFilesUpdateUrl(_helper.UpdateSection.SoftKey);
      110     }
      111     //var url = ConfigurationManager.AppSettings["VersionFileUrl"];
      112     if (!url.EndsWith("/"))
      113         url += "/";
      114     url += _zipFileName;
      115     _dispatcher.Invoke(new Action(() =>
      116     {
      117         //將壓縮文件下載到臨時文件夾
      118         LoadingLabel.Text = "新版本文件下載中……";
      119     }));
      120     _client.DownloadFileAsync(new Uri(url), GetTempFolder() + "\\" + _zipFileName);
      121 }
      122 
      123 /// <summary>
      124 /// 獲取下載文件夾地址及解壓文件存放地址
      125 /// 此地址默認為C:\Documents and Settings\當前用戶名\Local Settings\Temp 文件夾
      126 /// </summary>
      127 private string GetTempFolder()
      128 {
      129     string folder = System.Environment.GetEnvironmentVariable("TEMP");
      130     return new DirectoryInfo(folder).FullName;
      131 }
      132 
      133 void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
      134 {
      135     _dispatcher.BeginInvoke(new Action(() =>
      136     {
      137         this.RadProgressBar1.Value = e.ProgressPercentage;
      138         PercentageLabel.Text = e.ProgressPercentage.ToString() + " %";
      139     }));
      140 }
      141 
      142 void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
      143 {
      144     _dispatcher.Invoke(new Action(() =>
      145     {
      146         LoadingLabel.Text = PercentageLabel.Text = "";
      147         CompleteLabel.Text = "文件接收完成,正在更新……";
      148     }));
      149     HandleUploadedFiles();
      150 }
      151 
      152 private void HandleUploadedFiles()
      153 {
      154     FilesHandler.UnpackFiles(GetTempFolder() + "\\" + _zipFileName, this.GetAppRootPath());
      155 
      156     using (ChannelFactory<IVersionService> channelFactory = new ChannelFactory<IVersionService>("VersionSVC"))
      157     {
      158         IVersionService service = channelFactory.CreateChannel();
      159         service.DeleteCompressedFile(_zipFileName);
      160     }
      161     ReStartMainApp();
      162 }
      163 
      164 /// <summary>
      165 /// 刪除已過期的文件
      166 /// </summary>
      167 private void DeleteAbateFiles()
      168 {
      169     var filesNeedDelete = new FilesNeedUpdate
      170     {
      171         Files = _files.Files.ToList().FindAll(o => o.IsDelete).ToArray(),
      172         Directories = _files.Directories.ToList().FindAll(o => o.IsDelete).ToArray()
      173     };
      174     if (!filesNeedDelete.IsEmpty)
      175     {
      176         _dispatcher.Invoke(new Action(() =>
      177         {
      178             CompleteLabel.Text = "正在刪除已過期文件……";
      179         }), DispatcherPriority.Normal);
      180         FilesHandler.DeleteFiles(filesNeedDelete.Files.Select(o => o.Name).ToArray(), filesNeedDelete.Directories.Select(o => o.Name).ToArray(), _mainApp);
      181     }
      182 
      183 }
      184 
      185 private void ReStartMainApp(IAsyncResult res = null)
      186 {
      187     _dispatcher.Invoke(new Action(() =>
      188         {
      189             CompleteLabel.Text = "正在重啟應用程序,請稍候……";
      190         }));
      191 
      192     _dispatcher.BeginInvoke(new Action(() =>
      193         {
      194             Process.Start(_mainApp);
      195             this.Init();
      196             Process.GetCurrentProcess().Kill();
      197         }), DispatcherPriority.SystemIdle);
      198 }
      199 
      200 private string GetAppRootPath()
      201 {
      202     var rootPath = System.IO.Path.GetDirectoryName(_mainApp);
      203     if (!rootPath.EndsWith("\\"))
      204         rootPath += "\\";
      205     return rootPath;
      206 }
      207 
      208 //更新前備份文件
      209 private void BackUpFiles()
      210 {
      211     var rootPath = GetAppRootPath();
      212     _bkZipFilePath = rootPath + Guid.NewGuid().ToString() + ".zip";
      213     FilesHandler.CompressFiles(_files, rootPath, _bkZipFilePath);
      214 }
      215 }

      升級完畢后不要忘記保存新版本編號到配置文件。

      1 internal void SaveNewVersion()
      2 {
      3     UpdateSection.CurrentConfiguration.Save(ConfigurationSaveMode.Modified);
      4 }

      這里的UpdateSection定義如下:

       1 public class UpdateOnlineSection : ConfigurationSection
       2 {
       3     [ConfigurationProperty("CustomerKey", DefaultValue = "")]
       4     public string CustomerKey
       5     {
       6         get { return (string)base["CustomerKey"]; }
       7         set { base["CustomerKey"] = value; }
       8     }
       9 
      10     [ConfigurationProperty("SoftKey", DefaultValue = "")]
      11     public string SoftKey
      12     {
      13         get { return (string)base["SoftKey"]; }
      14         set { base["SoftKey"] = value; }
      15     }
      16 
      17     [ConfigurationProperty("Version", DefaultValue = "")]
      18     public string Version
      19     {
      20         get { return (string)base["Version"]; }
      21         set { base["Version"] = value; }
      22     }
      23 }

      對應的是主程序的版本節點。自定義配置節點有兩種方式,繼承IConfigurationSectionHandler或繼承自ConfigurationSection,由于我們要從外部程序(此處是升級程序)訪問主程序的配置,必須繼承自ConfigurationSection方可。

      主程序使用WCF獲取版本信息。代碼就不貼了,下面給個界面截圖。

      改進點:需要在該界面上增加手動升級的按鈕,以及當前運行版本標示

      文至此,想到尚有一些業務需求未完成,再無下筆欲望,若有朋友感興趣,我會在空閑時間將該功能涉及到的幾個工具完善后剝離出來提供下載。

      轉載本文請注明出處:http://www.rzrgm.cn/newton/archive/2013/01/12/2857722.html

      posted @ 2013-01-13 05:11  萊布尼茨  閱讀(3177)  評論(19)    收藏  舉報
      主站蜘蛛池模板: 白嫩少妇bbw撒尿视频| 欧美饥渴熟妇高潮喷水| 97se亚洲国产综合自在线观看| 欧美日本精品一本二本三区| 成人精品区| 日韩久久久久久中文人妻| 久久亚洲色www成人欧美| av午夜福利亚洲精品福利| 99久久亚洲综合精品成人网| 国产一区二区三区免费观看| av无码精品一区二区乱子| 国产在线国偷精品产拍| 风流少妇树林打野战视频| 曲阳县| 99精品国产综合久久久久五月天 | 国产一区精品在线免费看| 亚洲狠狠婷婷综合久久久| 东京热无码国产精品| 妓女妓女一区二区三区在线观看| 五月婷婷激情视频俺也去淫| 国产女人喷潮视频免费| 国产一区二区三区精美视频| 久爱www人成免费网站| 免费99视频| 风韵丰满妇啪啪区老老熟女杏吧 | 临汾市| 国产精品高清一区二区三区| 亚洲一二三区精品美妇| 隆德县| 日韩AV高清在线看片| AV在线亚洲欧洲日产一区二区| 大宁县| 久久无码av中文出轨人妻| 国产系列丝袜熟女精品视频 | 免费AV片在线观看网址| 久久91精品牛牛| japanese丰满奶水| 老司机免费的精品视频| 丝袜美腿视频一区二区三区| 无码成人午夜在线观看| 上饶县|