在不少年前,笔者在使用z-blog搭建我的部落格的时候,最大的感觉就是z-blog在线安装功能!php
由于在那个时候,以几K每秒的速度上传一个几M或者十几M的压缩包到虚拟主机上,是一个很痛苦的事情。特别是主机不支持在线解压功能,只能一个一个文件上传的时候。web
虽然z-blog实现该功能的只有php版本与之前的ASP版本,可是对于asp.net,咱们也能够作到一样的事情,只须要一个几K的ASPX文件,上传到服务器,就能够实现自动下载网站压缩包,解压并安装!算法
原本我担忧bin目录文件变动,会引起异常,可是实测结果很好。服务器
本文将经过三个步骤,实现现如下目标:asp.net
1.实现Asp.Net在线网站安装异步
2.尽可能使用最少的文件(实际咱们只须要一个aspx页)网站
步骤 一. 下载和解压spa
下载的话,咱们能够直接使用WebClient下载便可,新建一个aspx页,命名叫 DownloadAndDeCompress.aspx 把对应的cs文件删掉,并删除页中全部内容,在第一行中输入如下代码:.net
<%@ Page Language="C#" AutoEventWireup="true" Async="true" %>
注意这行的Async="true"这句,这是表示当前页面容许异步执行,由于咱们等下须要在下载时作进度条,因此必须加上此项。code
而后再把如下代码拷贝到页面中:
<script type="text/C#" runat="server">
protected void Page_Load(object sender, EventArgs e) { using (System.Net.WebClient wc = new System.Net.WebClient()) { wc.DownloadProgressChanged += new System.Net.DownloadProgressChangedEventHandler(downloadProgressChanged); wc.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(downloadFileCompleted); wc.DownloadFileAsync(new Uri("http://www.jiniannet.com/setup.zip"), Server.MapPath("~/setup.zip")); } } private void downloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { Response.Write("<script>window.parent.DeCompress()</"+"script>"); Response.Flush(); DeCompress(Server.MapPath("~/setup.zip"), Server.MapPath("~/")); Response.Write("<script>window.parent.DeCompressCompleted()</"+"script>"); Response.Flush(); } private void downloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e) { //script Response.Write("<script>window.parent.DownloadProgressChanged(" + e.ProgressPercentage.ToString() + ")</"+"script>"); Response.Flush(); } public void DeCompress(string fileName, string dirPath) { using (System.IO.Stream source = System.IO.File.OpenRead(fileName)) { using (System.IO.Stream destination = new System.IO.MemoryStream()) { using (System.IO.Compression.GZipStream input = new System.IO.Compression.GZipStream(source, System.IO.Compression.CompressionMode.Decompress, true)) { byte[] bytes = new byte[4096]; int n; while ((n = input.Read(bytes, 0, bytes.Length)) != 0) { destination.Write(bytes, 0, n); } } destination.Flush(); destination.Position = 0; DeSerializeFiles(destination, dirPath); } } } private void DeSerializeFiles(System.IO.Stream s, string dirPath) { System.Runtime.Serialization.Formatters.Binary.BinaryFormatter b = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); System.Collections.Generic.Dictionary<string, object> list = (System.Collections.Generic.Dictionary<string, object>)b.Deserialize(s); DeFiles(list, dirPath); } private void DeFiles(System.Collections.Generic.Dictionary<string, object> list, string dirPath) { foreach (System.Collections.Generic.KeyValuePair<string, object> n in list) { string newName = string.Concat(dirPath, n.Key.Remove(0, 1)); if (n.Key[0] == '0') { System.IO.Directory.CreateDirectory(newName); if (n.Value != null) { DeFiles((System.Collections.Generic.Dictionary<string, object>)n.Value, dirPath); } } else { using (System.IO.FileStream fs = new System.IO.FileStream(newName, System.IO.FileMode.Create, System.IO.FileAccess.Write)) { byte[] bytes = (byte[])n.Value; fs.Write(bytes, 0, bytes.Length); fs.Close(); } } } } </script>
page_load中,咱们直接经过webclient下载http://www.jiniannet.com/setup.zip这个安装包,第二个downloadFileCompleted方法用来向父页面输出下载完成事件与解压完成事件,第三个方法downloadProgressChanged则表示下载进度条。最后面的三个方法为解压相关方法。
这里咱们用使用Flush来即时输出信息,再配合一个父页面,就能够作进度条处理效果,因此原则上最少会有二个文件,可是最终咱们只会保留一个文件,这个在后面会讲处处理方法。
压缩算法的话,虽然如今压缩算法有不少种,像7Z,rar等压缩比例是至关高的,ZIP的压缩结果也不错,可是咱们要考虑文件精减,若是这个在线安装包搞得比完整安装包还大,就彻底没意义了,并且咱们的最终追求目标是只须要一个aspx页面,除了这个aspx页面,不须要再下任何文件。因此,我选择在这里使用系统自带的Gzip算法,这样能够尽可能解少咱们的安装文件对外面DLL的依赖,与尽可能减小安装文件的SIZE(注:不要被下载文件后缀ZIP迷惑,此ZIP也不能直接被压缩文件解压,具体缘由我将会在下面讲到)。
至此,最主要的一个功能性页面已经完成,在下一篇文章,我将介绍若是制做网站安装包与最后的install.aspx页面制做。
(原创做品,转载请注明做者与出处,本文同时发布于www.jiniannet.com)