zoukankan      html  css  js  c++  java
  • 取经之旅——把WinForms开发的桌面应用移植到Silverlight开发的RIA(第2部分)

    6,数据文件的部署

    之前,数据文件是通过ClickOnce一起和应用程序部署的。ClickOnce会自动判断数据文件是否更新了,然后来确定是否下载这些数据文件。而在Silverlight中,如果把数据文件作为Content打包在XAP文件中,那么每次下载(或更新)XAP都会下载这些数据文件。解决方法有两种:把数据文件单独放在一个程序集中,把程序集设置为On-Demand下载或用Application Library Caching机制来缓存;或者,自定义一个数据文件下载和升级的机制。

    我采用了第二种方式,即自定义了数据文件的下载更新机制,下面就详细介绍。

    首先了解一下参考资料《Silverlight: Downloading Zipped files with the WebClient (stand Silverlight 2 beta 1)》

    http://www.galasoft.ch/mydotnet/articles/article-2008032301.html

    接着,说明一下我的思路:

    • 在承载Silverlight应用程序的Web应用程序上建立一个文件夹,如“LCADB”
    • 在Web端的LCADB目录中放置一个(或多个)数据文件的zip文件,和一个manifest.xml文件来描述LCADB包含哪些文件,这些文件的最新更新时间
    • 每个zip文件都包含了若干xml文件,我的基础数据都是保存在xml文件中的
    • 如果是Out-Of-Browser的话,在Silverlight程序启动的时候,首先要检查是应用程序本身否有更新,
      • 更新完毕提示用户重启应用程序,
      • 无更新则调用InstallOrUpdateDB
    • 如果不是OfB的话,要用InstallState属性来跳过应用程序更新的代码,直接调用InstallOrUpdateDB
    • InstallOrUpdateDB,检查是否已经分配独立存储区(我分配了100M,数据文件解压后大致用到30M,其他可能作为临时空间,这点后面叙述)
      • 如果未分配,显示一个“Install DB”的按钮给用户,让用户点击以运行IncreaseQuotaTo,这样做的原因是安全机制限制了IncreaseQuotaTo方法必须由用户的事件所引发
        • 分配完成,接着调用CheckDBManifest
      • 如果已分配,直接调用CheckDBManifest
    • CheckDBManifest,用来检查服务器上的manifest.xml内容,和本地保存的manifest.xml进行比较以确定需要下载那些zip文件,这里是通过DownloadStringAsync方法直接获得manifest.xml的文本内容
    • 如果需要下载zip文件,就调用DownloadAndExtract,
    • DownloadAndExtract,用来下载zip文件并解压到独立存储区中,这里是通过OpenReadAsync来获取文件流,
    • 在OpenReadAsync异步方法完成后,解压zip文件的内容到独立存储区中,解压完成后,继续处理下一个需要下载的zip文件,并不断重复。在此处,我对SharpZipLib进行扩展,可以把文件解压到独立存储区中。

    整个流程就是这样,由于我没有安装Visio 2010,就不画流程图了。相关代码如下:

    public partial class MainPage : UserControl
    {
       Application app = Application.Current;
       public MainPage()
       {
           InitializeComponent();
           //在OfB中才用代码去更新
           if (app.InstallState==InstallState.Installed)
               app.CheckAndDownloadUpdateCompleted += new CheckAndDownloadUpdateCompletedEventHandler(app_CheckAndDownloadUpdateCompleted);
       }
    
       void app_CheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
       {
           if (e.UpdateAvailable)
           {
               MessageBox.Show("An application update has been downloaded. " +
                   "Restart the application to run the new version.");
           }
           else if (e.Error != null &&
               e.Error is PlatformNotSupportedException)
           {
               MessageBox.Show("An application update is available, " +
                   "but it requires a new version of Silverlight. " +
                   "Visit the application home page to upgrade.");
           }
           else
           {
               MessageBox.Show("There is no update available.");
               this.IsEnabled = true;
               InstallOrUpdateDB();
           }
       }
    
       private void InstallOrUpdateDB()
       {
           if (ProgramBase.ShouldIncreaseQuota)
           {
               button1.Visibility = System.Windows.Visibility.Visible;
           }
           else
           {
               this.CheckDBManifest();
           }
       }
    
       private void UserControl_Loaded(object sender, RoutedEventArgs e)
       {
    
           // Do not load your data at design time.
           // if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
           // {
           //     //Load your data here and assign the result to the CollectionViewSource.
           //     System.Windows.Data.CollectionViewSource myCollectionViewSource = (System.Windows.Data.CollectionViewSource)this.Resources["Resource Key for CollectionViewSource"];
           //     myCollectionViewSource.Source = your data
           // }
           if (app.InstallState == InstallState.Installed)
           {
               if (NetworkInterface.GetIsNetworkAvailable())
                   this.IsEnabled = false;
                   app.CheckAndDownloadUpdateAsync();
           }
           else
               InstallOrUpdateDB();
       }
    
       private void CheckDBManifest()
       {
           if (!NetworkInterface.GetIsNetworkAvailable()) return;
           WebClient wc = new WebClient();
           wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
           wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
           label1.Content = "DB updated checking ...";
           var url = ProgramBase.LCADBWebPath + "manifest.xml";
           wc.DownloadStringAsync(new Uri(url));
       }
    
       void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
       {
           progressBar1.Value= e.ProgressPercentage;
       }
    
       List<LCADBZipFile> zipfilesWeb;
       List<LCADBZipFile> zipfilesLocal;
       int checkfileIndex = 0;
       void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
       {
           label1.Content = "Finished DB updated checking.";
    
           var lcadb_zipfiles_manifest = "lcadb_zipfiles_manifest.xml";
    
           XDocument docWeb = XDocument.Parse(e.Result);
           zipfilesWeb = (from m in docWeb.Descendants("file")
                          select new LCADBZipFile
                          {
                              Name = m.Attribute("name").Value,
                              Created = DateTime.Parse(m.Attribute("created").Value)
                          }).ToList();
           
           using (var store = ProgramBase.OpenStore())
           {
               if (store.FileExists(lcadb_zipfiles_manifest))
               {
                   var s = store.OpenFile(lcadb_zipfiles_manifest, FileMode.Open);
                   XDocument docLocal = XDocument.Load(s);
                   zipfilesLocal = (from m in docLocal.Descendants("file")
                                    select new LCADBZipFile
                                    {
                                        Name = m.Attribute("name").Value,
                                        Created = DateTime.Parse(m.Attribute("created").Value)
                                    }).ToList();
                   s.Close();
               }
               else
               {
                   zipfilesLocal = new List<LCADBZipFile>();
               }
               docWeb.Save(store.OpenFile(lcadb_zipfiles_manifest, FileMode.Create));
           }
    
           //检查哪些文件需要下载
           foreach (var item in zipfilesWeb)
           {
               var localfile = zipfilesLocal.FirstOrDefault(o => o.Name == item.Name);
               if (localfile == null || localfile.Created < item.Created)
               {
                   qDownloadFiles.Enqueue(item.Name);
               }
           }
           DownloadAndExtract();
       }
    
       private Queue<string> qDownloadFiles = new Queue<string>();
    
       private void DownloadAndExtract()
       {
           if (qDownloadFiles.Count > 0)
           {
               var name = qDownloadFiles.Dequeue();
               //下载并解压
               WebClient wc2 = new WebClient();
               wc2.OpenReadCompleted += new OpenReadCompletedEventHandler(wc2_OpenReadCompleted);
               wc2.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc2_DownloadProgressChanged);
               //显示下载进度
               label1.Content = "Downloading " + name;
               wc2.OpenReadAsync(new Uri(ProgramBase.LCADBWebPath + name));
           }
           else
           {
               //显示主页面
               label1.Content = "Downloaded!";
           }           
       }
    
       void wc2_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
       {
           progressBar1.Value = e.ProgressPercentage;
       }
    
       void wc2_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
       {
           FastZip zip = new FastZip();
           string path=IO.Path.Combine(ProgramBase.LCADBXmlPath,zipfilesWeb[checkfileIndex].Name.Split('_')[0]);
           using (var store=ProgramBase.OpenStore())
           {
               if (!store.DirectoryExists(path)) store.CreateDirectory(path);
               zip.ExtractZip(store, e.Result, path,FastZip.Overwrite.Always,null,"","",true);
           }
    
           //继续检查下载下一个
           DownloadAndExtract();
       }
    
       class LCADBZipFile
       {
           public string Name { get; set; }
           public DateTime Created { get; set; }
       }
    
       private void button1_Click(object sender, RoutedEventArgs e)
       {
           ProgramBase.CreateDBDirectory();
           this.CheckDBManifest();
       }
    }
    

    SharpZipLib的扩展代码如下:

    #region 在独立存储区中解压zip文件
    //developed by zyg, ITKE
    public void ExtractZip(IsolatedStorageFile store, Stream stream, string targetDirectory, Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
                        string fileFilter, string directoryFilter, bool restoreDateTime)
    {
      if ((overwrite == Overwrite.Prompt) && (confirmDelegate == null))
      {
          throw new ArgumentNullException("confirmDelegate");
      }
    
      continueRunning_ = true;
      overwrite_ = overwrite;
      confirmDelegate_ = confirmDelegate;
      targetDirectory_ = targetDirectory;
      fileFilter_ = new NameFilter(fileFilter);
      directoryFilter_ = new NameFilter(directoryFilter);
      restoreDateTimeOnExtract_ = restoreDateTime;
    
      using (zipFile_ = new ZipFile(stream))
      {
    
    #if !NETCF_1_0
          if (password_ != null)
          {
              zipFile_.Password = password_;
          }
    #endif
    
          System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator();
          while (continueRunning_ && enumerator.MoveNext())
          {
              ZipEntry entry = (ZipEntry)enumerator.Current;
              if (entry.IsFile)
              {
                  if (directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name))
                  {
                      ExtractEntryInIsolatedStorage(store, entry);
                  }
              }
              else if (entry.IsDirectory)
              {
                  if (directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories)
                  {
                      ExtractEntryInIsolatedStorage(store, entry);
                  }
              }
              else
              {
                  // Do nothing for volume labels etc...
              }
          }
      }
    }
    
    private void ExtractEntryInIsolatedStorage(IsolatedStorageFile store, ZipEntry entry)
    {
      bool doExtraction = false;
    
      string nameText = entry.Name;
    
      if (entry.IsFile)
      {
          // TODO: Translate invalid names allowing extraction still.
          doExtraction = NameIsValid(nameText) && entry.IsCompressionMethodSupported();
      }
      else if (entry.IsDirectory)
      {
          doExtraction = NameIsValid(nameText);
      }
    
      // TODO: Fire delegate were compression method not supported, or name is invalid?
    
      string dirName = null;
      string targetName = null;
    
      if (doExtraction)
      {
          // Handle invalid entry names by chopping of path root.
          if (Path.IsPathRooted(nameText))
          {
              string workName = Path.GetPathRoot(nameText);
              nameText = nameText.Substring(workName.Length);
          }
    
          if (nameText.Length > 0)
          {
              targetName = Path.Combine(targetDirectory_, nameText);
              if (entry.IsDirectory)
              {
                  dirName = targetName;
              }
              else
              {
                  //dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
                  dirName = targetDirectory_;
              }
          }
          else
          {
              doExtraction = false;
          }
      }
    
      if (doExtraction && !store.DirectoryExists(dirName))
      {
          if (!entry.IsDirectory || CreateEmptyDirectories)
          {
              try
              {
                  //Directory.CreateDirectory(dirName);
                  store.CreateDirectory(dirName);
              }
              catch (Exception ex)
              {
                  doExtraction = false;
                  if (events_ != null)
                  {
                      if (entry.IsDirectory)
                      {
                          continueRunning_ = events_.OnDirectoryFailure(targetName, ex);
                      }
                      else
                      {
                          continueRunning_ = events_.OnFileFailure(targetName, ex);
                      }
                  }
                  else
                  {
                      continueRunning_ = false;
                  }
              }
          }
      }
    
      if (doExtraction && entry.IsFile)
      {
          ExtractFileEntryIsolatedStorage(store,entry, targetName);
      }
    }
    
    private void ExtractFileEntryIsolatedStorage(IsolatedStorageFile store, ZipEntry entry, string targetName)
    {
      bool proceed = true;
      if (overwrite_ != Overwrite.Always)
      {
          if (store.FileExists(targetName))
          {
              if ((overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null))
              {
                  proceed = confirmDelegate_(targetName);
              }
              else
              {
                  proceed = false;
              }
          }
      }
    
      if (proceed)
      {
          if (events_ != null)
          {
              continueRunning_ = events_.OnProcessFile(entry.Name);
          }
    
          if (continueRunning_)
          {
              try
              {
                  using (var outputISStream=store.OpenFile(targetName,FileMode.OpenOrCreate))
                  {
                      if (buffer_ == null)
                      {
                          buffer_ = new byte[4096];
                      }
                      if ((events_ != null) && (events_.Progress != null))
                      {
                          StreamUtils.Copy(zipFile_.GetInputStream(entry), outputISStream, buffer_,
                              events_.Progress, events_.ProgressInterval, this, entry.Name);
                      }
                      else
                      {
                          StreamUtils.Copy(zipFile_.GetInputStream(entry), outputISStream, buffer_);
                      }
    
                      if (events_ != null)
                      {
                          continueRunning_ = events_.OnCompletedFile(entry.Name);
                      }
                  }
                  
              }
              catch (Exception ex)
              {
                  if (events_ != null)
                  {
                      continueRunning_ = events_.OnFileFailure(targetName, ex);
                  }
                  else
                  {
                      continueRunning_ = false;
                  }
              }
          }
      }
    }
    #endregion
    

    注意,以上代码未经过仔细测试,请谨慎使用!

    分享到: 更多
  • 相关阅读:
    Android(java)学习笔记15:匿名内部类实现多线程
    Android(java)学习笔记14:Java线程池
    Android(java)学习笔记13:线程组的概述和使用
    Android(java)学习笔记12:线程的状态转换图以及常见执行情况
    win2012R2打Windows8.1-KB2919355 问题
    win2012R2打Windows8.1-KB2919355 问题
    P2404
    P2404
    P2404
    抽签
  • 原文地址:https://www.cnblogs.com/redmoon/p/1700807.html
Copyright © 2011-2022 走看看