简单的ASP.NET部署,运行环境:vs2003,SqlServer2000
(一)前提:
http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&FamilyID=627921a0-d9e7-43d6-a293-72f9c370bd19
下载"Microsoft Visual Studio .NET 2003 引导程序插件",它用于在 Microsoft® Visual Studio® .NET 2003 中创建包含 .NET Framework 1.1 版和/或 Microsoft Data Access Components (MDAC) 2.7 版的部署项目。
(二)建立简单的asp.net项目WebSetupTest
1.web.config文件里添加保存数据库连接字符串的key,部署的时候将初始化它.
< add key ="Conn_WebSetupTest" value ="" ></ add >
</ appSettings >
2.
创建index.aspx文件
测试部署数据库和开始菜单/桌面快捷方式
< br >
< asp:DataGrid id ="DataGrid1" runat ="server" Width ="100%" AllowPaging ="True" PageSize ="5" >
< PagerStyle Mode ="NumericPages" ></ PagerStyle >
</ asp:DataGrid >< br >
< p align ="center" >< img src ="images/images_res.gif" ></ p >
</ form >
index.aspx.cs里绑定数据
{
connE.strSql = "select * from users order by id desc";
DataGrid1.DataSource = connE.GetDt();
DataGrid1.DataBind();
}
3.项目根目录下创建SqlScript目录用来存放部署数据需要的3个数据库脚本文件
(1)CreateDataBase.sql用来创建数据库 --创建数据库<<DATABASE_NAME>>
Go
IF EXISTS ( SELECT name FROM master.dbo.sysdatabases WHERE name = ' <<DATABASE_NAME>> ' )
DROP DATABASE [ <<DATABASE_NAME>> ]
GO
Create Database << DATABASE_NAME >>
Go
use << DATABASE_NAME >>
-- 创建表
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[Users] ' ) and OBJECTPROPERTY (id, N ' IsUserTable ' ) = 1 )
drop table [ dbo ] . [ Users ]
GO
CREATE TABLE [ dbo ] . [ Users ] (
[ id ] [ int ] IDENTITY ( 1 , 1 ) NOT NULL ,
[ name ] [ varchar ] ( 50 ) COLLATE Chinese_PRC_CI_AS NULL ,
[ address ] [ varchar ] ( 50 ) COLLATE Chinese_PRC_CI_AS NULL ,
[ createDate ] [ datetime ] NULL
) ON [ PRIMARY ]
GO
(2)InsertData.sql用来向数据库里插入记录
declare @i int
set @i = 0
set xact_abort on
begin transaction
while @i < 50
begin
insert into users (name,address,createdate) values ( ' name ' + cast ( @i as varchar ), ' address ' + cast ( @i as varchar ), getDate ())
set @i = @i + 1
end
-- rollback transaction
commit transaction
set xact_abort off
(3)DropDataBase.sql用来卸载的时候删除数据库.
IF EXISTS ( SELECT name FROM master.dbo.sysdatabases WHERE name = ' <<DATABASE_NAME>> ' )
DROP DATABASE [ <<DATABASE_NAME>> ]
4.把快捷方式图标文件usa_folder_dialup.ico放在项目根目录下的确images目录里.
(三)在同一解决方案里添加"类库"项目WebSetupLib
1.把存放数据库脚本文件名称的DataBase.xml和用户许可协议文件UserProtocol.rtf放在Resources目录下.
UserProtocol.rtf文件可以通过Word直接创建,DataBase.xml要作为嵌入式资源,设置方法如图:
DataBase.xml内容:
< configroot >
< Files >
< DataBase >
< Add >
< File name ="CreateDataBase.sql" />
</ Add >
< Remove >
< File name ="DropDataBase.sql" />
</ Remove >
</ DataBase >
< Insert >
< File name ="InsertData.sql" />
</ Insert >
</ Files >
</ configroot >
2.添加部署数据库的类文件DataBase.cs,在下面的安装程序类文件WebSetupTest.cs里将使用此类
sing System;
using System.Diagnostics;
using System.Configuration.Install;
using System.Xml ;
using System.Windows.Forms;
namespace WebSetupLib
{
/** <summary>
/// DataBase 的摘要说明。
/// </summary>
public class DataBase
{
string serverName=null;
string databaseName =null;
string userName=null;
string Password=null;
bool trustedconnection=false;
string targetPath=null;
XmlDocument config=null;
public const string CONST_DATBASE_PLACEHOLDER ="<<DATABASE_NAME>>";
//构造方法#region //构造方法
public DataBase()
{
//
// TODO: 在此处添加构造函数逻辑
//
//System.IO.Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("WebSetupLib.DataBase.xml");
System.IO.Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("WebSetupLib.Resources.DataBase.xml");
config=new XmlDocument();
//MessageBox.Show("before load1111");
config.Load(stream);
//MessageBox.Show("after load 111");
}
public DataBase(string servername,string databasename,string username,
string password,string targetpath):this()
{
this.serverName =servername;
this.databaseName=databasename;
this.userName=username;
this.Password=password;
this.targetPath=targetpath;
}
/** <summary>
/// 信任连接
/// </summary>
/// <param name="servername"></param>
/// <param name="databasename"></param>
/// <param name="targetpath"></param>
public DataBase(string servername,string databasename,string targetpath):this()
{
this.serverName =servername;
this.databaseName=databasename;
this.trustedconnection=true;
this.targetPath =targetpath;
}
#endregion
/** <summary>
/// 安装数据库
/// </summary>
/// <returns></returns>
public bool CreateDataBase()
{
string fileName=null;
try
{
ProcessStartInfo processInfo =new ProcessStartInfo("osql.exe");
processInfo.WindowStyle=ProcessWindowStyle.Hidden;
//Get the name of the file from the assembly's embedded resource.
//MessageBox.Show("createDatabase");
if(config !=null)
{
fileName = config.SelectSingleNode("configroot/Files/DataBase/Add/File").Attributes["name"].Value;
}
else
{
throw new InstallException("创建数据库的脚本文件不存在!");
}
//Get arguments
//MessageBox.Show("master");
processInfo.Arguments=GetCommonProcessArguments(fileName,"master");
EventLog.WriteEntry("安装数据库",processInfo.Arguments);
PopulateDatabaseNamePlaceHolder(GetFullPath(fileName));
Process osql = Process.Start(processInfo);
//Wait till it is done
osql.WaitForExit();
EventLog.WriteEntry( "安装数据库","数据库创建完成..");
osql.Dispose();
return true;
}
catch(Exception ex)
{
//Customize if required.
EventLog.WriteEntry("安装数据库",ex.Message,EventLogEntryType.Error) ;
throw new InstallException(ex.Message);
}
}
/** <summary>
/// 删除数据库
/// </summary>
/// <returns></returns>
public bool DropDataBase()
{
string fileName=null;
try
{
ProcessStartInfo processInfo =new ProcessStartInfo("osql.exe");
processInfo.WindowStyle=ProcessWindowStyle.Hidden;
//Get the name of the file from the assembly's embedded resource.
if(config !=null)
{
fileName = config.SelectSingleNode("configroot/Files/DataBase/Remove/File").Attributes["name"].Value;
}
else
{
throw new InstallException("删除数据库的脚本文件不存在!");
}
//Get arguments
processInfo.Arguments=GetCommonProcessArguments(fileName,"master");
EventLog.WriteEntry("安装数据库",processInfo.Arguments);
PopulateDatabaseNamePlaceHolder(GetFullPath(fileName));
Process osql = Process.Start(processInfo);
osql.WaitForExit();
EventLog.WriteEntry("安装数据库","删除数据库");
osql.Dispose();
return true;
}
catch(Exception ex)
{
//Customize if required.
EventLog.WriteEntry("安装数据库",ex.Message,EventLogEntryType.Error) ;
throw new InstallException(ex.Message);
}
}
/** <summary>
/// 插入数据
/// </summary>
/// <returns></returns>
public bool InsertDate()
{
try
{
ExecuteScripts("configroot/Files/Insert/File");
EventLog.WriteEntry("安装数据库","记录增加完成");
return true;
}
catch(Exception ex)
{
//Customize if required.
EventLog.WriteEntry("安装数据库",ex.Message,EventLogEntryType.Error) ;
throw new InstallException(ex.Message);
}
}
/** <summary>
/// 执行数据库脚本
/// </summary>
/// <param name="Xpath"></param>
void ExecuteScripts(string Xpath)
{
XmlNodeList objectlist=null;
ProcessStartInfo processInfo =new ProcessStartInfo("osql.exe");
processInfo.WindowStyle=ProcessWindowStyle.Hidden;
//Get the name of the file from the assembly's embedded resource.
if(config !=null)
{
objectlist = config.SelectNodes(Xpath);
}
else
{
throw new InstallException("保存数据库脚本文件名称的XML文件不存在!");
}
foreach(XmlNode objectFile in objectlist)
{
//Get arguments
processInfo.Arguments=GetCommonProcessArguments(objectFile.Attributes["name"].Value,databaseName);
EventLog.WriteEntry("安装数据库",processInfo.Arguments);
Process osql = Process.Start(processInfo);
//Wait till it is done
osql.WaitForExit();
EventLog.WriteEntry( "安装数据库", objectFile.InnerText +" file executed..");
}
}
/** <summary>
/// 获得数据库脚本的完整路径
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private string GetFullPath(string fileName)
{
//The destination folder for this will be the Install/scripts folder under the
//installation root
//MessageBox.Show(targetPath + @"SqlScript/" + fileName);
string FullPath = targetPath + @"SqlScript/" + fileName;
return FullPath;
}
/** <summary>
/// 读数据库脚本文件的内容
/// </summary>
/// <param name="filepath"></param>
void PopulateDatabaseNamePlaceHolder(string filepath)
{
//Read the contents
System.IO.StreamReader reader = new System.IO.StreamReader(filepath);
string content=reader.ReadToEnd();
reader.Close();
//Replace the placeholder with database name
content =content.Replace(CONST_DATBASE_PLACEHOLDER,databaseName);
//Writeback the contents
System.IO.StreamWriter writer = new System.IO.StreamWriter(filepath,false);
//MessageBox.Show(content);
writer.Write(content);
writer.Flush();
writer.Close();
}
string GetCommonProcessArguments(string fileName, string overridendatabasename)
{
//是否是信任连接
if(!trustedconnection)
{
/**//* Arguments configured.
* osql [-S server] [-d use database name] [-U login id] [-P password]
[-i inputfile] [-o outputfile]
*/
return " -S " + serverName + " -d " + overridendatabasename +" -U " + userName + " -P " +Password + " -i " + Char.ToString('"') + GetFullPath(fileName) + Char.ToString('"') + " -o " + Char.ToString('"') + targetPath + "Log.txt" + Char.ToString('"');
}
else
{
/**//* Arguments configured.
* osql [-S server] [-d use database name] [-E trusted connection]
[-i inputfile] [-o outputfile]
*/
return " -S " + serverName + " -d " + overridendatabasename + " -E " + " -i " + Char.ToString('"') + GetFullPath(fileName) + Char.ToString('"') + " -o " + Char.ToString('"') + targetPath + "Log.txt" + Char.ToString('"');
}
}
}
}
3.添加安装程序类文件WebSetupTest.cs 里面重载Install和Uninstall方法.
public override void Install(IDictionary stateSaver)
{
bool TrustedConnection=false;
base.Install (stateSaver);
try
{
if(this.Context!=null)
{
StringDictionary parameters = Context.Parameters ;
string[] keys =new string[parameters.Count];
parameters.Keys.CopyTo(keys,0);
"把数据库/服务器名/数据库用户名/数据库密码/安装路径写进 stateSaver"#region "把数据库/服务器名/数据库用户名/数据库密码/安装路径写进 stateSaver"
//MessageBox.Show(this.Context.Parameters["target"].ToString());
stateSaver.Add("database",this.Context.Parameters["database"].ToString());
stateSaver.Add("server",this.Context.Parameters["server"].ToString());
stateSaver.Add("username",this.Context.Parameters["username"].ToString());
stateSaver.Add("password",this.Context.Parameters["password"].ToString());
stateSaver.Add("target",this.Context.Parameters["target"].ToString());
#endregion
//测试连接#region //测试连接
//can encrypt here
string connectionstring= "Data Source=" + stateSaver["server"].ToString() ;
connectionstring+= ";Initial Catalog=" + stateSaver["database"].ToString() ;
if(stateSaver["username"]!=null && stateSaver["username"].ToString().Length!=0)
{
SqlConnection conn =new SqlConnection( "server=" + stateSaver["server"].ToString()
+ ";database=master;Uid=" + stateSaver["username"].ToString() +";Password=" + stateSaver["password"].ToString());
conn.Open();
conn.Close();
conn.Dispose();
connectionstring+= ";User ID=" + stateSaver["username"].ToString() ;
connectionstring+= ";Password=" + stateSaver["password"].ToString() ;
}
else
{
//信任连接
SqlConnection conn =new SqlConnection( "Data Source=" + stateSaver["server"].ToString()
+ ";Initial Catalog=master;trusted_connection=yes");
conn.Open();
conn.Close();
conn.Dispose();
TrustedConnection=true;
stateSaver.Add("trustedconnection",true);
connectionstring+=";Trusted_connection=yes";
}
#endregion
//把数据库连接字符串写进web.config文件.#region //把数据库连接字符串写进web.config文件.
XmlDocument doc = new XmlDocument();
doc.Load(stateSaver["target"].ToString()+ @"Web.config");
XmlNode connectionNode = doc.SelectSingleNode(@"configuration/appSettings/add[@key='Conn_WebSetupTest']");
if(connectionNode!=null)
{
connectionNode.Attributes["value"].Value = connectionstring;
doc.Save( stateSaver["target"].ToString()+ @"Web.config");
EventLog.WriteEntry("安装数据","Configuration file processed"); //写日志
}
else
{
//This error will ensure installation is uncomplete
throw new InstallException("没有数据库连接串!");
}
#endregion
//执行数据库脚本,安装数据库#region //执行数据库脚本,安装数据库
DataBase dbInstall =null;
if(TrustedConnection)
{
dbInstall= new DataBase(stateSaver["server"].ToString(),stateSaver["database"].ToString(),
stateSaver["target"].ToString());
}
else
{
dbInstall= new DataBase(stateSaver["server"].ToString(),stateSaver["database"].ToString(),
stateSaver["username"].ToString(),stateSaver["password"].ToString(),stateSaver["target"].ToString());
}
dbInstall.CreateDataBase();
dbInstall.InsertDate();
#endregion
//部署桌面快捷方式*******************#region//部署桌面快捷方式*******************
StreamWriter sw2=System.IO.File.CreateText(Context.Parameters["des"].ToString()+"WebSetupTest.url");
stateSaver.Add("DeskQuick",Context.Parameters["des"].ToString()+"WebSetupTest.url"); //保存桌面快诫方式文件绝对地址
//Context.Parameters["des"].ToString()是对应的桌面地址
string webdirs=Context.Parameters["webdir"].ToString();
//Context.Parameters["webdir"].ToString()对应的路径,在安装项目里面作为参数传入
string webdirsNew = webdirs.Substring(0,webdirs.Length-1);
webdirs = webdirsNew.Substring(webdirsNew.LastIndexOf(@"/")+1);
string Urls=@"URL=http://localhost/"+webdirs+@"/index.aspx";
sw2.WriteLine("[InternetShortcut]");
sw2.WriteLine(Urls);
sw2.WriteLine("modified=228928983");
sw2.WriteLine("IconIndex=0");
//sw2.WriteLine("IconFile="+webdirsNew+"//Resources//usa_folder_dialup.ico");
sw2.WriteLine("IconFile="+webdirsNew+"//images//usa_folder_dialup.ico");
sw2.Flush();
sw2.Close();
#endregion
部署开始菜单 ***************#region 部署开始菜单 ***************
string startMenue=Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);
if(File.Exists(startMenue+"//WebSetupTest.url"))
{
if(MessageBox.Show("开始菜单已经存在,是否有覆盖它?","安装开始菜单",MessageBoxButtons.YesNo,MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1) == DialogResult.Yes)
{
File.Copy(Context.Parameters["des"].ToString()+"WebSetupTest.url",startMenue+"//WebSetupTest.url",true);
}
else
{
throw new InstallException("开始菜单已经存在,安装取消");
}
}
else
{
File.Copy(Context.Parameters["des"].ToString()+"WebSetupTest.url",startMenue+"//WebSetupTest.url",false);
}
stateSaver.Add("StartMenueFile",startMenue+"//WebSetupTest.url"); //保存开始菜单文件绝对地址
#endregion
}
}
catch(Exception ex1)
{
throw new System.Configuration.Install.InstallException(ex1.ToString());
}
}
public override void Uninstall(IDictionary savedState)
{
try
{
if(savedState!=null)
{
base.Uninstall (savedState);
删除快捷键,删除开始菜单#region 删除快捷键,删除开始菜单
//删除快捷键
if(File.Exists(savedState["DeskQuick"].ToString()))
{
File.Delete(savedState["DeskQuick"].ToString());
}
//删除开始菜单
if(File.Exists(savedState["StartMenueFile"].ToString()))
{
File.Delete(savedState["StartMenueFile"].ToString());
}
#endregion
//删除数据库#region //删除数据库
if(MessageBox.Show("要删除数据库吗?" +savedState["database"].ToString()+"./n ","确认删除数据库",MessageBoxButtons.YesNo,MessageBoxIcon.Question ,MessageBoxDefaultButton.Button2)== DialogResult.No)
{
return;
}
DataBase dbInstall=null;
if(savedState["trustedconnection"]!=null && (bool)savedState["trustedconnection"])
{
dbInstall= new DataBase(savedState["server"].ToString(),savedState["database"].ToString(),
savedState["target"].ToString());
}
else
{
dbInstall= new DataBase(savedState["server"].ToString(),savedState["database"].ToString(),
savedState["username"].ToString(),savedState["password"].ToString(),savedState["target"].ToString());
}
dbInstall.DropDataBase();
#endregion
}
else
{
MessageBox.Show("Saved state was nullsome error.");
throw new ApplicationException("卸载需要的参数不存在!");
}
}
catch(InstallException inst)
{
throw new InstallException(inst.Message);
}
catch(Exception generic)
{
throw new InstallException(generic.Message);
}
}
(四)在同一解决方案里添加'Web安装项目"WebSetup
1.打开"文件系统"视图
(1)"web应用程序文件夹"-->右键"添加"-->"项目输出" 选择"WebSetupTest"里的"主输出"和"内容文件",如下图:
主输出一般是dll文件,内容文件包括aspx文件/web.config/images目录等等.
(2)"web应用程序文件夹"--新建目录"install",然后"install"右键"项目输出" 选择"WebSetupLib"里的"主输出"和"内容文件"
2.打开"用户界面"视图.
(1)."安装"--"启动"-->右键"添加对话完"--"许可协议".
添加完毕后在"许可协议"的"属性窗口"中添加刚才的UserProtocol.rtf文件.
(2).用上面一样的方法添加"文本框(A)",在其属性里设置服务器和数据库信息
下图是上面是两个对话框添加完毕后的"用户界面"视图.
3.打开"自定义操作"视图.
(1)"安装"-->右键"添加自定义操作"选择"install"目录下的"主输出来自WebSegtupLib",命名为Install
它是设置自定义的数据/快捷方式/开菜单等.
(2)在上面的install属性窗口里"CustomActionData"的值为/server=[SERVER_NAME] /target="[TARGETDIR]/" /database=[DATABASE_NAME] /username=[USER_NAME] /password=[PASSWORD] /version=[WINDOWSVERSION] /des="[DesktopFolder]/" /webdir="[TARGETDIR]/"
(3)"卸载"--右键"添加自定义操作"选择"install"目录下的"主输出来自WebSegtupLib".命名为UnInstall
这样卸载的时候将删除数据库/快捷方式/开菜单等.下图是两个子定义操作后的"自定义操作"视图.
4."启动条件"视图使用默认值.
五.编译安装项目
编译后将生成WebSetup.msi安装文件.这样就可以安装了.下面是安装效果图
六.参考资料
自定义 MSI 安装(里面有详细的数据库部署代码实例)
http://www.netscum.dk/china/msdn/library/langtool/vsdotnet/usvs04j7.mspx