热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

.NETWeb应用程序安装包的制作经历:Sql数据库安装的3种方式

一次难得的安装包制作经历,因为之前从没有制作过安装包,那就免不了遇到问题,在摸索和学习中获得了不少宝贵经验,在这里我将用图文并茂的形式详细描述一下流程及主要难点问题的解决方法,希望

一次难得的安装包制作经历,因为之前从没有制作过安装包,那就免不了遇到问题,在摸索和学习中获得了不少宝贵经验,在这里我将用图文并茂的形式详细描述一下流程及主要难点问题的解决方法,希望对需要的朋友有所帮助.

      首先建一个Web应用程序的安装项目


bubuko.com,布布扣 >


      建好项目后在该安装项目的文件系统中加入Web应用程序的所有文件,全选后拖到"Web应用程序文件夹"内即可,也可以在"Web应用程序文件夹"点击右键在菜单中选择添加文件


bubuko.com,布布扣 >


      如果有多个Web应用程序需要放在同一个安装包内安装,可以在"目标计算机上的文件系统"上点右键添加"Web自定义文件夹",如图中的WebControls


bubuko.com,布布扣 >


      在Web文件夹的属性里,可以设置一下默认页及虚拟目录名称,其他的属性可以无视,使用默认值就可以了


bubuko.com,布布扣 >


      到此,一个Web应用程序的安装包就基本完成了,直接生成的安装程序就可以将安装到/Inetpub/wwwroot目录下成为一个虚拟站点了,如果你的站点没有数据库的话,基本可以打完收工了^_^

      之后遇到的第一个问题就是如何安装数据库.在网上找了一些资料,虽然说的比较详细,但都没有图例,习惯了傻瓜教程的我花了不少时间去摸索,下面就图文说明一下

      先设计用户录入SQL数据库信息的界面,这个VS.NET有现成的界面,稍微修改一下即可,非常简单,打开安装包项目的用户界面


bubuko.com,布布扣

      在"启动"项里添加一个"文本框(A)"对话框


bubuko.com,布布扣


      将"文本框(A)"移动到安装流程中合适的位置,设置一下属性,请注意,这里的EditProperty的值是传递用户输入数据的关键字,必填

 


bubuko.com,布布扣

 
      下面就进入重点了,这个流程的操作搞了半天才搞明白,在解决方案中再建一个类库项目,名字叫DBInstall,在该项目创建一个继承于System.Configuration.Install.Installer的类


bubuko.com,布布扣 >


      暂时不写代码,将此类库与安装项目关联起来先,在"Web应用程序文件夹"下的任意文件夹里点击右键添加一个"项目输出"


bubuko.com,布布扣


      默认会选中当前的DBInstall项目,不用改任何选项直接点确定,会在文件夹中新增一个"主输出来自DBInstall(活动)"的文件项


bubuko.com,布布扣


      接下来在项目自定义操作的"安装"项上点右键添加自定义操作,选择刚刚新增"主输出来自DBInstall(活动)"的文件夹,选中确定添加到安装项内


bubuko.com,布布扣 >


      添加完毕后设置"主输出来自DBInstall(活动)"的CustomActionData属性的值为
/dbname=[CUSTOMTEXTA1] /server=[CUSTOMTEXTA2] /user=[CUSTOMTEXTA3]
/pwd=[CUSTOMTEXTA4] /targetdir="[TARGETDIR]/"
,通过该格式化字符串接收用户输入传递给安装程序的自定义数据,前4个传入值是"文本框(A)"中相关联的TextBox的值,第5个参数"TARGETDIR"返回的是Web应用程序安装路径


bubuko.com,布布扣


      现在,可以去写安装Sql数据库的代码,在继承于System.Configuration.Install.Installer的InstallDb类中重载Install方法,在该方法内编写安装过程中需要执行的代码

      先编写个执行SQL语句的方法,后面编写安装数据库的代码时需要用到,传入的参数分别是
connStr - 数据库链接字符串,DatabaseName - 链接的数据库名称,Sql - 待执行的SQL语句


 1 private void ExecuteSql(string connStr, string DatabaseName, string Sql) {
 2             SqlConnection conn = new SqlConnection(connStr);
 3             SqlCommand cmd = new SqlCommand(Sql, conn);
 4 
 5             conn.Open();
 6             conn.ChangeDatabase(DatabaseName);
 7             try {
 8                 cmd.ExecuteNonQuery();
 9             }
10             finally {
11                 conn.Close();
12             }
13         }


      在研究过程中,我尝试了3种安装数据库的方法,下面将一一讲解一下

      第一种方法是通过附加数据库的方式来实现安装数据库,首先将需要安装的初始化数据库从Sql
Server中分离,将该数据库的mdf和ldf文件添加到"Web应用程序文件夹"中,这里是放在DataBase文件夹中的,在Install方法中添加以下代码



1 string connStr = string.Format("data source={0};user id={1};password={2};persist security info=false;packet size=4096", this.Context.Parameters["server"], this.Context.Parameters["user"], this.Context.Parameters["pwd"]);
2 string strSql = "EXEC sp_attach_db  @dbname  =  N‘" + this.Context.Parameters["dbname"] + "‘,"
3                                 + "@filename1  =  N‘" + this.Context.Parameters["targetdir"] + "DataBase//DemoData.mdf‘,"
4                                 + "@filename2  =  N‘" + this.Context.Parameters["targetdir"] + "DataBase//DemoData_log.ldf‘";
5 ExecuteSql(connStr, "master", strSql); 


      可以看到,通过this.Context.Parameters["KeyName"]的方法,可以获取由应用程序传递的自定义数据,获取数据库的相关信息拼成链接字符串,再拼一个附加数据库的SQL语句,用的是master库中的存储过程sp_attach_db,3个参数分别是数据库的名称,及mdf和ldf完整路径,因此要拼完整具体目录并加上文件名,这样,执行一下这个Sql语句即能将数据库附加到Sql
Server,但是这样做有个问题,卸载安装时安装程序会删除mdf和ldf文件,如果数据库在使用中,则卸载出错,如果数据库未使用,则被删除,后果严重,因此,只能用脚本去安装数据库

      第二种方法是从网上看来的,在进程中通过osql.exe去执行SQL脚本文件安装数据库



1 System.Diagnostics.Process sqlProcess = new System.Diagnostics.Process();
2 sqlProcess.StartInfo.FileName = "osql.exe";
3 sqlProcess.StartInfo.Arguments = string.Format(" -U {0} -P {1} -d {2} -i {3}/db.sql", this.Context.Parameters["user"], this.Context.Parameters["pwd"], this.Context.Parameters["dbname"], this.Context.Parameters["targetdir"]);
4 sqlProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
5 sqlProcess.Start();
6 sqlProcess.WaitForExit(); //等待执行


      此种方法需要开一个进程,性能比较高,并且将进程的WindowStyle设置为Hidden,用户就看不到执行时的Dos窗体了,最后,一定要加上等待执行完成的WaitForExit方法,否则,数据库还未安装完成时安装程序很可能就已经完成安装提示用户可以退出了

      第三种方法是直接用先前所写的ExecuteSql方法执行安装脚本中的Sql语句



1 string connStr = string.Format("data source={0};user id={1};password={2};persist security info=false;packet size=4096", this.Context.Parameters["server"], this.Context.Parameters["user"], this.Context.Parameters["pwd"]);
2 ExecuteSql(connStr, "master", "CREATE DATABASE " + this.Context.Parameters["dbname"]);
3 
4 StringBuilder sb = this.GetSqlFile("Demo.sql");
5 ExecuteSql(connStr, this.Context.Parameters["dbname"], sb.ToString());
6 
7 sb = this.GetSqlFile("Demo_Data.sql");
8 ExecuteSql(connStr, this.Context.Parameters["dbname"], sb.ToString());


      通过GetSqlFile方法获得脚本中的Sql,这里用了两个脚本文件,一个是创建数据库的,一个是创建默认数据的,两个脚本文件是可以合并成一个文件的,执行一次即可



1 // 获取Sql文件里的脚本
2 private StringBuilder GetSqlFile(string pFileName) {
3             StringBuilder sqlTemp = new StringBuilder();
4 
5             sqlTemp.Append(File.ReadAllText(this.Context.Parameters["targetdir"] + "DataBase//" + pFileName, System.Text.Encoding.GetEncoding("GB2312")));
6 
7             return sqlTemp;
8 }


      需要提醒的是,创建数据库的脚本文件中,需要将"GO","SET
ANSI_NULLS ON","SET QUOTED_IDENTIFIER
ON"去掉,否则通过SqlCommand执行会出错,另外,如果默认数据的Insert脚本中包含中文,读取Sql语句时要加上System.Text.Encoding.GetEncoding("GB2312")这个参数,否则中文变乱码,默认数据的Insert脚本可以在网上找到导出所有数据Insert语句的存储过程

      3种安装数据库的方法中后两种比较实用,第一种方法虽然方便快捷,但是卸载时万一将数据库也误卸载,那就损失惨重了

      接下来说两个小问题,安装好了肯定要配置Web.Config中的数据库链接字符串,网上有现成的修改App.Config和Web.Config的方法,和安装数据库时的方法一样,拼好数据库链接字符串,调用修改Web.Config的方法,通过键名找到相应的键,将键值改为新的数据库链接字符串即可

      另一个问题是在不同系统环境下测试安装包时发现的,如果系统中有.NET
1.1和.NET 2.0两个环境,安装的虚拟站点默认使用1.1的.NET版本,如果系统先安装了.NET
2.0再安装IIS,那默认网站的ASP.NET版本选项是空的,没有选中2.0版本,因此安装的虚拟目录ASP.NET版本选项也是空的,问了不少网友,都说需要执行aspnet_regiis.exe
-i去注册2.0版本的.NET,但是如果安装好了再让用户去做这些操作总觉得有些别扭,看了一下aspnet_regiis.exe的参数说明,发现可以对某个虚拟站点进行.NET版本注册,就写下面这段代码去注册当天安装的虚拟目录



1 string path = Environment.GetFolderPath(Environment.SpecialFolder.System).ToUpper().Replace("SYSTEM32", "") + @"Microsoft.NET/Framework/v2.0.50727/aspnet_regiis.exe";
2 
3 System.Diagnostics.Process process = new System.Diagnostics.Process();
4 process.StartInfo.FileName = path;
5 process.StartInfo.Arguments = "-s
W3SVC/1/ROOT/" +
"虚拟站点名称";
6 process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
7 process.Start();
8 process.WaitForExit();


      第一行的代码是获取aspnet_regiis.exe的具体路径,然后通过一个进程去执行注册操作,这样,即使出现前两种情况,都不用担心没有将虚拟站点的ASP.NET版本注册正确Web应用程序无法运行了

      这两部分代码可以建一个像安装数据库一样继承于System.Configuration.Install.Installer的自定义操作来执行,不过,方便起见,直接放在InstallDB类中就可以了

      安装包的制作是件很复杂的事,通过这次经历,只是学到了一点皮毛,在这里班门弄斧一下,希望对需要的朋友有所帮助^_^ 

.NET Web应用程序安装包的制作经历:Sql数据库安装的3种方式,布布扣,bubuko.com


推荐阅读
  • gitlab重置password
    ruby没怎么学,自己搭建的gitlab的rootpassword又忘了。幸好看见此帖子,试验okhttp:roland.kierkels.netgitreset-your-git ... [详细]
  • 第8章 使用外部和内部链接
    8.1使用web地址LearnAboutafricanelephants. ... [详细]
  • 今天我们开始学习下拉及多级弹出菜单,包含以下内容和知识点:带下拉子菜单的导航菜单绝对定位和浮动的区别和运用css自适应宽度滑动门菜单一、带下拉子菜单的导航菜单下拉菜单在一些 ... [详细]
  • 在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用java.util包中的Date类。这个类最主要的作用就是获取当前时间,我们来看下Date类的使用:使用Date类的 ... [详细]
  • java的流分两大类,字节流和字符流。一般在cc++中,一个字节是8位,java也是一样。但是,在cc++中一个字符,即char一般也是8位(可能机器不同会有所不同),但java为 ... [详细]
  • 1.Listener是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时 ... [详细]
  • nginx+多个tomcat
    学习nginx的时候遇到的问题:nginx怎么部署两台tomcat?upstream在网上找的资源,我在nginx配置文件(nginx.conf)中添加了两个server。结果只显 ... [详细]
  • 前言:拿到一个案例,去分析:它该是做分类还是做回归,哪部分该做分类,哪部分该做回归,哪部分该做优化,它们的目标值分别是什么。再挑影响因素,哪些和分类有关的影响因素,哪些和回归有关的 ... [详细]
  • 4554:[Tjoi2016&Heoi2016]游戏 ... [详细]
  • Flutter 布局(四) Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth详解
    本文主要介绍Flutter布局中的Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth四种控件,详细介绍了其布局 ... [详细]
  • mysql  GROUP_CONCAT获取分组的前几名
    如果是oracle应该很容易用Partition By实现。比如说要获取班级的前3名,就可以用GROUP_CONCAT+ GROUPBY + substring_index实现。考 ... [详细]
  • 动手动脑,无法自拔(3)课时作业6
    1.动手动脑(五子棋棋盘排布)(1)源程序(2)实验截图2.动手动脑(数字转换成汉字)(1)源程序(2)实验截图3.动手动脑(大数计算)(1)源程序 ... [详细]
  • http:acm.hdu.edu.cnshowproblem.php?pid2052内容比较简单就是打印图案。。。但是方法是对于四个角,第一行第四行,中间行要进行分类。#inclu ... [详细]
  • substring( ) 和 substr( ) 的区别
    1、里面的参数定义不一样substring(x,y)substr(x,y);substring里面的x,y是位置,相当于坐标,substr里的x是位置,y是长度length特殊备注 ... [详细]
  • hadoop1.2.1文档中这样写:Nowcheckthatyoucansshtothelocalhostwithoutapassphrase:$sshlocalhostIfyou ... [详细]
author-avatar
LD系瑰精棂_142
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有