Asp.net 安装包制作 (转)

主要参考:
      http://xucanzhao.cnblogs.com/archive/2005/10/02/248063.html 这个比较详细,也是我看的第一个,照着一步一步来,最起码知道添加用户界面,添加操作了,可到最关键那步,代码那出问题了,他用的是vb,我熟悉的是C#,改了半天没改出来。
      在http://blog.csdn.net/abaowu/archive/2004/11/23/191908.aspx 提供的http://topic.csdn.net/t/20040913/17/3368253.html (7 楼goody9807的回复)里找到了,到这也基本上明白这个“安装程序类”的作用了
      还得在安装的同时配置虚拟目录,http://www.cnblogs.com/nerocool/archive/2008/08/13/1266733.html 这里有个实例(演示的很详细的,也有个制作安装包的过程,是个pdf文件),强烈推荐下载后看看

      接下来动手做一个,先创建个空白解决方案,选“其他项目类型”里的“Visual Studio 解决方案”,名字和位置自己随意定啊,在这就叫做InstallSolution了。

 

 

      在解决方案资源管理里新建项目,选“其他项目类型”里的“安装和部署”,选择“安装项目”【我选的是这个,在网上搜了几个都用的是web安装项目,从字面上来说web安装项目似乎更合适,但我这web安装项目我暂时没试成功,下去再试试】,名字就叫setup吧,



      注意下红色标注的这几个图标,在实际操作中可以很方便切换编辑解界面,



      然后对着项目右键选择“视图——用户界面”在出现的“用户界面”中



      在“启动”上右键“添加对话框(从字面上就可以猜出来这样做的目的就是要弹出个对话框)”选择需要的对话框



      先添加个“许可协议”的对话框吧(这个框的功能就是安装程序的时候弹出个窗口,内容是就是一些版权信息或者什么什么的,如果用户不点确定是不让进行下一步操作的),之后就可以在用户界面“启动”下面看到这个对话框了,默认新添加的对话框是在最后的,需要右键“上移”至合适位置,这个原因就不多说了。
      这个对话框是加上了,可内容呢?呵呵,不急,先来建个文件啊,打开word,在里面写上你想让在“许可协议”这块显示的内容,然后“另存为”,在弹出来的属性窗口中选择“Rtf”格式(不要随便建个文件,然后手动更改后缀名为rtf,要另存为是选择后缀名,否则不显示内容)



      切换到Vs上,在“许可协议”这一项右键选择“属性窗口”,



      在“LicenseFile”上选择“浏览”,找到你刚保存的那个Rtf文件,这个就好了



      接下来得把网站加进去,对着解决方案,如果你的网站建立的时候用的是WebApplication(这里指使用的是新建项目),就选添加现有项目,然后选择你的项目,如果你用的是“网站Website(这里只使用的是新建网站)”,就不用选择添加项目了,下面一个一个说。
      先说是website的,直接把你的website给生成了(就是说在你的website右键选择“发布网站”,要编译之后的文件【可以直接发布的,里面没有.cs最后缀名的文件,有.dll的】),接下来复制你编译好的网站(所有的文件),切换回刚建的这个项目中,切换到文件系统界面(找不到?看解决方案上面得那一串图标,把鼠标放到第2个上,点击就好了)。



      双击“应用程序文件夹(我的理解这个文件夹就是用户在安装程序的时候生成在用户计算机中的文件,就好像安装QQ的话就会生成个名叫QQ的文件夹,里面的文件应该就是编译好的,可以直接运行,其他的几个文件夹功能也能够从字面上看出来,这些自己尝试吧),在中间(如下图标注)”那块粘贴刚复制的文件(编译好的所有文件)




      项目右键——“生成”, 这样就做好了,点击右键“安装”看看……




      安装之后的文件时编译好的,接下来咱看看WebApplication的,刚说了在解决方案上“右键”——添加已有项目,添加你的webApplication到这个解决方案,将鼠标移到setup这个项目上来,右键——“添加”——“项目输出”



      在弹出来的窗口中选择刚加入的webApplication项目,然后选中“主输出”和“内容文件”(这个其他的也可以选择,根据自己的需要)。



      点击确定即可,之后和刚才一样,点击“生成”,按后“安装”试试。可以发现安装后的文件时编译好的。为什么website不这样呢?试试就知道了,



      这里不像webApplication那样有那么多的选项,只有内容文件,点击确定后生成,安装后是源文件,没有编译(原因尚不清楚)…… 这不行吧?如果在用户机上没法编译,那这网站就跑不起来了。

      在安装中你会发现下面这样的情况





      看下标记的,全是setup,安装别的程序的时候都是显示的程序名或者公司信息之类,还有默认路径怎么是这样的呢?这个这么改?呵呵,切换回VS,然后选中setup项目,点击属性窗口



      是那个红色的属性,不是右键属性,不一样的。



      把这几个改改就好了,而且可以改别的,像“Description”的……
      
      这样制作的安装包总感觉少点什么东西,用户安装之后还得自己去装数据库,改web.config文件。仔细想想,感觉这个安装包就是个解压缩,它就是把编译好的文件拷贝了一份,有些活还得额外做,能不能在安装的时候把数据库建了。O(∩_∩)O这个是可以的……
      现在就说怎么把数据库给封进去,在解决方案上“新建项目”,选择“类库”,

      把默认生成的class1.cs删除,新建“安装程序类”,



      具体代码先不说,一会在说
      在setup项目上,在添加个“视图”――“用户界面”,添加个对话框,这次选择“文本A”,之后在文本框A上右键――“属性窗口”,修改某些字段



      标记的那几个名字是以后要用的“变量名”,根据自己的需要设置,这个是很灵活的,只是我这个对话框的目的就是获取跟数据库有关的数据,所以就这么写了。
      这个界面跟写程序时用的控件的属性界面是一样的,做测试属性名,右侧是值。
      其中带有Label就是让用户看的,而带有Property是以后在写代码的时候要用到的,这先做个记号,待会还得看上面那个图。
      接下来在setup项目中 “视图”——“自定义操作



      在自定义操作界面,选择“安装”,右键“添加自定义操作”,在弹出的窗口中双击“应用程序文件夹”,然后选择“添加输出”,在“项目”中选择“InstallClassLibruary”这个类库项目,之后选择“主输出”和“内容文件”,这样在“自定义操作界面”就多了个内容,



      在那个多出来的项上右键选择属性,在CustomAction中填上    /dbname=[DBNAME]  /server=[SERVER]   /user=[UNAME]  /pwd=[PWD]  /targetdir="[TARGETDIR]"  最后一个带有“""”注意,“[]”中间的是刚在文本框A的属性中带有Property 那几项填写的的那几个,而这些“/”之后的则是在写程序中要用的,就是为了获取文本框中输入的值,targetdir是文件的安装路径,需要单独再加个双引号,这个是很有用的;

      之后就到刚才建立的那个“安装程序类”里写代码了,看代码

 

Code
/// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="DataBaseName"></param>
        /// <param name="Sql"></param>
        private void ExecuteSql(string DataBaseName, string Sql)
        {
            SqlConnection sqlConnection = new SqlConnection("Data Source=" + this.Context.Parameters["server"] +
              ";Initial Catalog=master;Persist Security Info=True;User ID=" + this.Context.Parameters["user"] + ";Password=" + this.Context.Parameters["pwd"] + "");

            System.Data.SqlClient.SqlCommand Command = new System.Data.SqlClient.SqlCommand(Sql, sqlConnection);
            Command.Connection.Open();
            Command.Connection.ChangeDatabase(DataBaseName);
            try
            {
                Command.ExecuteNonQuery();
            }
            catch
            {
               
            }
            finally
            {
                Command.Connection.Close();
            }
        }

        /// <summary>
        /// 创建数据库
        /// </summary>
        /// <param name="strDBName"></param>
        protected void AddDBTable(string strDBName)     
      {          
            try     
            {              
                ExecuteSql("master","CREATE   DATABASE   "+   strDBName);
            }     
            catch(Exception ee)
            {
              MessageBox.Show("数据库创建失败!您可以手动添加,但名称需要和刚才填写的数据库名称一致! 错误信息:\n" + ee.Message,"Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
            }     
      }


      这个是新建数据库(注意只有数据库,没有表啊,间表得自己写),就是一般的方法,但仅仅这样是不行的,它没法执行,加上这个

Code
 public override void Install(System.Collections.IDictionary stateSaver)
        {
            base.Install(stateSaver);
            AddDBTable(this.Context.Parameters["dbname"]);
           // updateWebConfig();
           // CreateVirtualDir();
        }


      这就可以执行了,把这个方法写到Install()里……
      注意public override void Install(IDictionary stateSaver) 这个,需要重写这个类,然后把你要执行的代码放在这个方法里,比方说
      建立数据库,同时得修改Web.config文件吧,再写个修改web.config的方法,也放到Install里,就可以执行了。
      注意到这个类中有“this.Context.Parameters["user"] ”的,这个就是刚才在自定义操作的“CustomAction”属性中那个字段,这样就可以把用户输入的信息获取到了。

      回忆一下啊
            第一:“添加用户界面”,选择文本框
            第二:为文本框中的带label和带property的字段赋值(如property为UNAME),
            第三:“自定义操作”,在属性窗口的“CustomAction”再次传递参数,如“/name=[UNAME] ”,
            第四:在自定义操作类中,获取这个参数,如“ this.Context.Parameters["name"] ”,这样就可以在类中使用用户输入的数据了。

      再附上两个方法,这个是修改web.config文件的(其实就是读取xml文件,然后修改一个节点的属性,需要添加命名空间System.XML)

Code

        private void updateWebConfig()
        {
            //加载配置文件
            try
            {
                System.IO.FileInfo FileInfo = new System.IO.FileInfo(this.Context.Parameters["targetdir"] + "/web.config");
                if (!FileInfo.Exists)
                {
                    throw new InstallException("缺少配置文件 :" + this.Context.Parameters["targetdir"] + "/web.config");
                }
                System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
                xmlDocument.Load(FileInfo.FullName);

                //修改连接字符串
                foreach (System.Xml.XmlNode Node in xmlDocument["configuration"]["connectionStrings"])
                {
                    if (Node.Name == "add")
                    {
                        if (Node.Attributes.GetNamedItem("name").Value == "你在项目中使用的连接数据库字符串的名字")
                        {
                            Node.Attributes.GetNamedItem("connectionString").Value = String.Format("Data Source={0};Initial Catalog={1};User ID={2};Password={3};", dserver, dbname, user, pwd); 
                        }
                    }
                }
                xmlDocument.Save(FileInfo.FullName);
            }
            catch
            {
                MessageBox.Show("Web.config 配置错误!", "安装提示", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
            }
        }


      还有个生成虚拟目录的(先添加引用 System.DirectoryServices,然后添加命名空间)

Code
 private void CreateVirtualDir()
        {
            try
            {
                string constIISWebSiteRoot = "IIS://" + iis + "/W3SVC/1/ROOT";
                DirectoryEntry root = new DirectoryEntry(constIISWebSiteRoot);
                //判断虚拟目录是否已存在,存在就先删除再创建【不建议这么做,建议直接报个错就行】
                DirectoryEntry Exist = root.Children.Find(virtualdir, root.SchemaClassName);
                if (Exist != null)
                {
                    //删除虚拟目录
                    root.Children.Remove(Exist);
                    root.CommitChanges();
                }
                DirectoryEntry newRoot = root.Children.Add(virtualdir, root.SchemaClassName);
                newRoot.Properties["Path"][0] = physicaldir;//设置物理地址
                newRoot.Properties["AppIsolated"][0] = 2;             // 值 0 表示应用程序在进程内运行,值 1 表示进程外,值 2 表示进程池
                newRoot.Properties["AccessScript"][0] = true;          // 可执行脚本
                newRoot.Invoke("AppCreate", true);
                //tbEntry.Properties["DefaultDoc"][0] = "Default.aspx";//设置起始页
                newRoot.Properties["AppFriendlyName"][0] = virtualdir;   // 应用程序名
                newRoot.CommitChanges();
                root.CommitChanges();
            }
            catch
            {
                MessageBox.Show("虚拟目录创建失败!", "Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
            }
        }


      再次生成看看,安装时就可以看到输入框了,数据库的数据也是有效的了……

      这两段代码均是参考http://www.cnblogs.com/nerocool/archive/2008/08/13/1266733.html 
 

      这里只是简单说了一下,还有些功能就没提,像修改注册表了(c/s用的比较多),添加桌面快捷方式,添加到快速启动栏等等,这些自己都去试试,对着那些项点击右键看看都有什么,都是什么,多摸索摸索……

      最后再给个链接:http://blog.csdn.net/superes/archive/2009/03/16/3994939.aspx  介绍了3种把数据库附件到安装程序里的,务必试试,刚我给的代码中只是见了个空库,没有表……

 ---------2009-10-29-----   

   对创建虚拟目录的代码加以修改,主要原因是按照原先的代码发布后,IIS中ASP.NET的版本是1.1.4322,这样是无法访问的,需要改成2.0.50727,在网上搜索之后,用”ASP.NET IIS注册工具“可以实现,下面就多加了修改的代码(搜到网上的还是1.1的,后来改成2.0的了)

 

创建虚拟目录
  /// <summary>
        /// 创建虚拟目录
        /// </summary>
        void CreateVirtualDir()
        {
            try
            {
                string constIISWebSiteRoot = "IIS://" + this.Context.Parameters["IISServer"] + "/W3SVC/1/ROOT";
                MessageBox.Show("start");
                DirectoryEntry root = new DirectoryEntry(constIISWebSiteRoot);          
                MessageBox.Show("no");
                DirectoryEntry newRoot = root.Children.Add(this.Context.Parameters["virtualdir"], root.SchemaClassName);
             //   newRoot.Properties["Path"][0] = @"D:\web";//设置物理地址
                newRoot.Properties["Path"][0] = this.Context.Parameters["targetdir"];
                newRoot.Properties["AppIsolated"][0] = 2;             // 值 0 表示应用程序在进程内运行,值 1 表示进程外,值 2 表示进程池
                newRoot.Properties["AccessScript"][0] = true;          // 可执行脚本
                newRoot.Invoke("AppCreate", true);
                newRoot.Properties["DefaultDoc"][0] = "Default.aspx";//设置起始页
                newRoot.Properties["AppFriendlyName"][0] = this.Context.Parameters["virtualdir"];   // 应用程序名
                newRoot.CommitChanges();
                root.CommitChanges();

                //修改IIS中asp.net版本
                //用v2.0.50727下的aspnet_regiis.exe,网上给的都是v1.1.4,如果这样就相当于没改
                string fileName = Environment.GetEnvironmentVariable("windir") + @"\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe";
                ProcessStartInfo startInfo = new ProcessStartInfo(fileName);
                //处理目录路径
                string path = newRoot.Path.ToUpper();
                int index = path.IndexOf("W3SVC");
                path = path.Remove(0, index);
                //启动aspnet_iis.exe程序,刷新教本映射
                startInfo.Arguments = "-s " + path;
                startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                startInfo.UseShellExecute = false;
                startInfo.CreateNoWindow = true;
                startInfo.RedirectStandardOutput = true;
                startInfo.RedirectStandardError = true;
                Process process = new Process();
                process.StartInfo = startInfo;
                process.Start();
                process.WaitForExit();
                string errors = process.StandardError.ReadToEnd();
                if (errors != string.Empty)
                    throw new Exception(errors);
             //   Console.WriteLine(process.StandardOutput.ReadToEnd());
            }
            catch (Exception ee)
            {
                MessageBox.Show("虚拟目录创建失败!您可以手动创建! " + ee.Message, "Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
            }

        }

 创建web安装项目的也试了,这次可以了,原因未知,不过我这次用的是2003系统,上次是2008的,创建虚拟目录的代码在2008下也无法运行,在03上就可以

web安装项目好处是可以自动生成虚拟目录,不用额外的添加代码,但遇到的新问题是文件的安装路径没法修改(没有选择路径[浏览]的那个对话框)……网上也查到了个,说是用orca软件修改 生成后的msi文件。

 

posted @ 2012-02-07 09:26  gds111789  阅读(375)  评论(0编辑  收藏  举报