C# 之Asp.net 安装包的创建,打包数据库

[RunInstaller(true)]

public partial class JSWyglInstaller : Installer

{

public JSWyglInstaller()

{

InitializeComponent();

}

#region 程序代码

/// <summary>

/// 数据库的操作

/// </summary>

#region 数据库的操作属性集合

private System.Data.SqlClient.SqlConnection sqlConn;

private System.Data.SqlClient.SqlCommand Command;

private System.Data.SqlClient.SqlTransaction Trans;

private string DBName;

private string ServerName;

private string AdminName;

private string AdminPwd;

///dbname=[DBNAME] /server=[DBSERVERNAME] /user=[USERNAME] /pwd=PASSWORD] /iis=[IISSERVER] /port=[PORT] /targetdir="[TARGETDIR]\"

#endregion

/// <summary>

///IIS的操作

/// </summary>

#region IIS操作属性

private string iis;

private string port;

private string dir;

public static string VirDirSchemaName = "IIsWebVirtualDir";

private string _target;

private DirectoryEntry _iisServer;

private ManagementScope _scope;

private ConnectionOptions _connection;

#endregion

//连接数据库服务器到方法:

#region ConnectDatabase 连接数据库

private bool ConnectDatabase()

{

if (Command.Connection.State != ConnectionState.Open)

{

try

{

Command.Connection.Open();

}

catch(Exception e)

{

MessageBox.Show("打开数据库失败:"+e.Message);

return false;

}

}

return true;

}

/// <summary>

/// 开启事物

/// </summary>

private void BeginTrans()

{

if (Trans == null)

Trans = sqlConn.BeginTransaction();

if(Command.Transaction==null)

Command.Transaction = Trans;

}

/// <summary>

/// 提交事物

/// </summary>

private void CommitTrans()

{

if (Trans != null)

Trans.Commit();

}

private void RollBack()

{

if (Trans != null)

Trans.Rollback();

}

#endregion

//如果不能正确连接数据库服务器,请检查你的连接字符串,或者将连接字符串写入文件查看

//读取SQL文件的方法:

#region GetSql 从文件中读取SQL,在读取包含SQL脚本的文件时需要用到,参考自MSDN

private string GetSql(string Name)

{

try

{

//MessageBox.Show("GetSql"+Name);

Assembly Asm = Assembly.GetExecutingAssembly();

Stream strm = Asm.GetManifestResourceStream(Asm.GetName().Name + "." Name);

StreamReader reader = new StreamReader(strm);

return reader.ReadToEnd();

}

catch (Exception getException)

{

MessageBox.Show("读取文件错误:" + getException.Message);

return string.Empty;

//throw new ApplicationException("读取文件错误:"+getException.Message);

}

}

#endregion

//可以将此需要执行的SQL脚本放在此文本中

//执行SQL语句的方法:

#region ExecuteSql 执行SQL语句,参考自MSDN

private void ExecuteSql(string DataBaseName, string sqlstring)

{

//MessageBox.Show("ExecuteSql:DataBaseName"+DataBaseName +"-SqlString:"+sqlstring);

Command = new System.Data.SqlClient.SqlCommand(sqlstring, sqlConn);

if (ConnectDatabase())

{

try

{

Command.Connection.ChangeDatabase(DataBaseName);

Command.ExecuteNonQuery();

//MessageBox.Show("ChangeDataBaseSuccess");

}

finally

{

Command.Connection.Close();

}

}

}

private void ExecuteSqlForTrans(string DataBaseName, string sqlstring)

{

//MessageBox.Show("ExecuteSql:DataBaseName"+DataBaseName +"-SqlString:"+sqlstring);

if(Command==null)

Command = new System.Data.SqlClient.SqlCommand(sqlstring, sqlConn);

if (ConnectDatabase())

{

try

{

BeginTrans();

Command.Connection.ChangeDatabase(DataBaseName);

Command.ExecuteNonQuery();

//MessageBox.Show("ChangeDataBaseSuccess");

}

catch(Exception ex)

{

if (Trans != null)

Trans.Rollback();

Command.Connection.Close();

//throw new Exception("创建数据库 [" + DBName + "] 错误:" + ex.Message);

MessageBox.Show("创建数据库 [" + DBName + "] 错误:" + ex.Message);

}

}

}

#endregion

//创建数据库及数据库表:

#region CreateDBAndTable 创建数据库及数据库表,参考自MSDN

protected bool CreateDBAndTable(string DBName)

{

bool Restult = false;

try

{

//MessageBox.Show("CreateDBAndTable");

if (string.IsNullOrEmpty(DBName))

return false;

ExecuteSqlForTrans("master", "USE MASTER IF EXISTS (SELECT NAME FROM SYSDATABASES WHERE NAME='" + DBName + "') DROP DATABASE " + DBName);

ExecuteSqlForTrans("master", "CREATE DATABASE " + DBName);

ExecuteSqlForTrans(DBName, GetSql("DBSQL.txt"));

CommitTrans();

Restult = true;

}

catch (Exception ex)

{

MessageBox.Show("CreateDBAndTable"+ex.Message);

//throw new Exception("创建数据库 [" + DBName + "] 错误:" + ex.Message);

}

finally

{

if(Command!=null)

Command.Connection.Close();

}

return Restult;

}

#endregion

//从备份文件恢复数据库及数据库表

#region RestoreDB 从备份文件恢复数据库及数据库表

///

/// 从备份文件恢复数据库及数据库表

///

///数据库名

///配件中数据库脚本资源的名称

///

protected bool RestoreDB(string DBName)

{

string dir = this.Context.Parameters["targetdir"];

//MessageBox.Show("DBDir:" + dir);

dir += @"DBInit\";

bool Restult = false;

string MSQL = "RESTORE DATABASE " + DBName +

" FROM DISK = N'" + dir + @"wygl.bak' " +

" WITH MOVE 'TXFee_Data' TO N'" + @"c:\" + DBName + ".mdf', " +

" MOVE 'TXFee_log' TO N'" + @"c:\" + DBName + ".ldf' ";

try

{

ExecuteSql("master", "USE MASTER IF EXISTS (SELECT NAME FROM SYSDATABASES WHERE NAME='" + DBName + "') DROP DATABASE " + DBName);

ExecuteSql("master", MSQL);

//CommitTrans();

Restult = true;

}

catch(Exception ex)

{

MessageBox.Show("创建数据库 [" + DBName + "] 错误:" + ex.Message);

//throw new Exception("创建数据库 [" + DBName + "] 错误:" + ex.Message);

}

finally

{

if (Command != null)

Command.Connection.Close();

#region 作废

// 删除备份文件

//try

//{

// File.Delete(dir + @"wygl.bak");

//}

//catch

//{

//}

#endregion

}

return Restult;

}

#endregion

//这里可以到注册表读取SQL Server的安装路径,把恢复后的数据库文件放到data目录地下。

//在本例中,只是实现了恢复,并未进行标准的操作。其中Test和Test_log时备份时数据库的文件信息。

//如果想要从备份文件中恢复,请把文件包含到项目里并且设置和DBSQL.txt一样,嵌入到程序里。最后执行删除。

//不过我想应该有办法不把文件先安装到目标机器上,而是有方法想读取DBSQL.txt文件一样,直接恢复数据库,不过确实没想到办法,失败!

//网站安装好后,需要设置web.config文件,这里只涉及到连接字符串到设置,其他的可以同理修改。

#region WriteWebConfig 修改web.config的连接数据库的字符串

private bool WriteWebConfig()

{

System.IO.FileInfo FileInfo = new System.IO.FileInfo(this.Context.Parameters["targetdir"] + "/web.config");

if (!FileInfo.Exists)

{

throw new InstallException("未找到Web.Config文件 :" + this.Context.Parameters["targetdir"] + "/web.config");

}

System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();

xmlDocument.Load(FileInfo.FullName);

bool FoundIt = false,FondReportServer=false;

foreach (System.Xml.XmlNode Node in xmlDocument["configuration"]["appSettings"])

{

if (Node.Name == "add")

{

//根据安装设置连接字符串

//if (Node.Attributes.GetNamedItem("key").Value == "ConnectionString")

//{

// Node.Attributes.GetNamedItem("value").Value = String.Format("Persist Security Info=False;Data Source={0};database={1};User , ServerName, DBName, AdminName, AdminPwd);

// FoundIt = true;

//}

//根据安装设置连接字符串

if (Node.Attributes.GetNamedItem("key").Value == "SqlConnectionString")

{

Node.Attributes.GetNamedItem("value").Value = String.Format("Persist Security Info=False;Data Source={0};database={1};User , ServerName, DBName, AdminName, AdminPwd);

FoundIt = true;

}

if (Node.Attributes.GetNamedItem("key").Value == "SqlConnectionADO")

{

Node.Attributes.GetNamedItem("value").Value = String.Format("Provider=SQLOLEDB.1;Password={3};Persist Security Info=False;User , ServerName, DBName, AdminName, AdminPwd);

FoundIt = true;

}

//根据安装设置连接字符串

if (Node.Attributes.GetNamedItem("key").Value == @"auV8CdDyCk/67slOZw5fh1KU7XuAjzSUq7ZCaBKfXsgHpdZ7RgCJHL0TWqbjkpIG")

{

string str= String.Format("Persist Security Info=False;Data Source={0};database={1};User , ServerName, DBName, AdminName, AdminPwd);

Node.Attributes.GetNamedItem("value").Value = WYDAL.FangChan.StringUtils.CryptographyUtility(str);

FoundIt = true;

}

if (Node.Attributes.GetNamedItem("key").Value == "WebReportServer")

{

string [] dir=this.Context.Parameters["targetdir"].ToString().TrimEnd('\\').Split('\\');

//string dirRootString = this.Context.Parameters["targetdir"].ToString();

string dirRootName=string.Empty;

if(dir!=null && dir.Length>0)

{

dirRootName=dir[dir.Length-1];

}

//Node.Attributes.GetNamedItem("value").Value = String.Format("http://{0}/{1}/ReprotServer/YaWebReportService.asmx?WSDL",this.Context.Parameters["iis"] ,dirRootName );

Node.Attributes.GetNamedItem("value").Value = String.Format("http://{0}/WebReportServer/YaWebReportService.asmx?WSDL", this.Context.Parameters["iis"]);

// MessageBox.Show(this.Context.Parameters["targetdir"]);

FondReportServer = true;

}

}

}

if (!FoundIt )

{

throw new InstallException("查找配置文件的数据库服务信息出错!");

}

if( !FondReportServer)

{

throw new InstallException("查找配置文件的报表服务器出错!");

}

xmlDocument.Save(FileInfo.FullName);

return FoundIt;

}

/// <summary>

/// 从WEBCONFIG 中获取数据库连接字符串

/// </summary>

/// <returns></returns>

private string GetDBNameFromWebConfig()

{

//MessageBox.Show("webconfig");

System.IO.FileInfo FileInfo = new System.IO.FileInfo(this.Context.Parameters["targetdir"] + "/web.config");

if (!FileInfo.Exists)

{

throw new InstallException("Missing config file :" + this.Context.Parameters["targetdir"] + "/web.config");

}

System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();

xmlDocument.Load(FileInfo.FullName);

// bool FoundIt = false, FondReportServer = false;

foreach (System.Xml.XmlNode Node in xmlDocument["configuration"]["appSettings"])

{

if (Node.Name == "add")

{

if (Node.Attributes.GetNamedItem("key").Value == "SqlConnectionString")

{

string strNodeConnection= Node.Attributes.GetNamedItem("value").Value ;//= String.Format("Persist Security Info=False;Data Source={0};database={1};User , ServerName, DBName, AdminName, AdminPwd);

if (string.IsNullOrEmpty(strNodeConnection))

{

int dataBaseIndex=strNodeConnection.IndexOf("database=")+10;

int dataBaseEnd = strNodeConnection.Substring(dataBaseIndex, strNodeConnection.Length - dataBaseIndex - 1).IndexOf(";");

MessageBox.Show(strNodeConnection.Substring(dataBaseIndex, dataBaseEnd));

return strNodeConnection.Substring(dataBaseIndex,dataBaseEnd);

}

}

}

}

return string.Empty;

}

#endregion

#region WriteRegistryKey 写注册表。安装部署中,直接有一个注册表编辑器,可以在那里面设置。

private void WriteRegistryKey()

{

// 写注册表

RegistryKey hklm = Registry.LocalMachine;

RegistryKey qzg = hklm.OpenSubKey("SOFTWARE", true);

RegistryKey F = qzg.CreateSubKey("QzgWygl");

//F.SetValue("FilePath", "kkkk"); old

F.SetValue("FilePath", "QzgFxWygl");

}

#endregion

//操作IIS,建立网站等。可参考:

//用VS2005制作网页对IIS进行操作

#region Connect 连接IIS服务器

public bool Connect()

{

if (iis == null)

return false;

try

{

_iisServer = new DirectoryEntry("IIS://" + iis + "/W3SVC/1");

_target = iis;

_connection = new ConnectionOptions();

_scope = new ManagementScope(@"\\" + iis + @"\root\MicrosoftIISV2", _connection);

_scope.Connect();

}

catch

{

return false;

}

return IsConnected();

}

public bool IsConnected()

{

if (_target == null || _connection == null || _scope == null) return false;

return _scope.IsConnected;

}

#endregion

#region IsWebSiteExists 判断网站是否已经存在

public bool IsWebSiteExists(string serverID)

{

try

{

string siteName = "W3SVC/" + serverID;

ManagementObjectSearcher searcher = new ManagementObjectSearcher(_scope, new ObjectQuery("SELECT * FROM IIsWebServer"), null);

ManagementObjectCollection webSites = searcher.Get();

foreach (ManagementObject webSite in webSites)

{

if ((string)webSite.Properties["Name"].Value == siteName)

return true;

}

return false;

}

catch

{

return false;

}

}

#endregion

#region GetNextOpenID 获得一个新的ServerID

private int GetNextOpenID()

{

DirectoryEntry iisComputer = new DirectoryEntry("IIS://localhost/w3svc");

int nextID = 0;

foreach (DirectoryEntry iisWebServer in iisComputer.Children)

{

string sname = iisWebServer.Name;

try

{

int name = int.Parse(sname);

if (name > nextID)

{

nextID = name;

}

}

catch

{

}

}

return ++nextID;

}

#endregion

#region CreateWebsite 添加网站

public string CreateWebSite(string serverID, string serverComment, string defaultVrootPath, string HostName, string IP, string Port)

{

try

{

ManagementObject oW3SVC = new ManagementObject(_scope, new ManagementPath(@"IIsWebService='W3SVC'"), null);

if (IsWebSiteExists(serverID))

{

return "Site Already Exists...";

}

ManagementBaseObject inputParameters = oW3SVC.GetMethodParameters("CreateNewSite");

ManagementBaseObject[] serverBinding = new ManagementBaseObject[1];

serverBinding[0] = CreateServerBinding(HostName, IP, Port);

inputParameters["ServerComment"] = serverComment;

inputParameters["ServerBindings"] = serverBinding;

inputParameters["PathOfRootVirtualDir"] = defaultVrootPath;

inputParameters["ServerId"] = serverID;

ManagementBaseObject outParameter = null;

outParameter = oW3SVC.InvokeMethod("CreateNewSite", inputParameters, null);

// 启动网站

string serverName = "W3SVC/" + serverID;

ManagementObject webSite = new ManagementObject(_scope, new ManagementPath(@"IIsWebServer='" + serverName + "'"), null);

webSite.InvokeMethod("Start", null);

return (string)outParameter.Properties["ReturnValue"].Value;

}

catch (Exception ex)

{

return ex.Message;

}

}

//创建网站管理服务

public ManagementObject CreateServerBinding(string HostName, string IP, string Port)

{

try

{

ManagementClass classBinding = new ManagementClass(_scope, new ManagementPath("ServerBinding"), null);

ManagementObject serverBinding = classBinding.CreateInstance();

serverBinding.Properties["Hostname"].Value = HostName;

serverBinding.Properties["IP"].Value = IP;

serverBinding.Properties["Port"].Value = Port;

serverBinding.Put();

return serverBinding;

}

catch

{

return null;

}

}

#endregion

//好了,准备工作已经做完,现在开始写最重要的Install方法了

//整个方法写完后如下:

#region Install 安装

///

/// 安装数据库

///

///

public override void Install(IDictionary stateSaver)

{

base.Install(stateSaver);

dir = this.Context.Parameters["targetdir"];

DBName = this.Context.Parameters["dbname"].ToString();

ServerName = this.Context.Parameters["server"].ToString();

AdminName = this.Context.Parameters["user"].ToString();

AdminPwd = this.Context.Parameters["pwd"].ToString();

iis = this.Context.Parameters["iis"].ToString();

port = this.Context.Parameters["port"].ToString();

//MessageBox.Show("Initial-"+DBName+"-"+ServerName+"-"+AdminName+"-"+AdminPwd+"-iis:"+iis+"-"+port+"-"+dir+"}");

//写入获取的安装程序中的变量,此段代码为调试用可以不添加

if(sqlConn==null)

sqlConn = new SqlConnection();

this.sqlConn.ConnectionString = "Packet size=4096;User ;Data Source=" + ServerName + ";Password=" + AdminPwd + ";Persist Security Info=False;Integrated Security=false";

//本安装程序采用附加数据库的方式,所以去掉本段代码

// 执行SQL 安装数据库 可选择时恢复或者时直接创建

//if (!CreateDBAndTable(DBName))

//{

// MessageBox.Show("qzg-dbname");

// throw new ApplicationException("创建数据库时出现严重错误!");

//}

// 从备份数据库文件恢复数据库

if (!RestoreDB(DBName))

{

MessageBox.Show("恢复数据库时出现严重错误,请与管理员联系!");

}

//部署桌面快捷方式*******************#region//部署桌面快捷方式*******************

string strDeskTop = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

StreamWriter sw2 = System.IO.File.CreateText(strDeskTop + "\\亿联物业管理系统.url");

stateSaver.Add("DeskQuick", strDeskTop + "\\亿联物业管理系统.url"); //保存桌面快诫方式文件绝对地址

string[] aryTh = dir.TrimEnd('\\').Split('\\');

string webdirs = aryTh[aryTh.Length-1];

string Urls = @"URL=http://"+iis+"/" + webdirs + @"/default.aspx";

sw2.WriteLine("[InternetShortcut]");

sw2.WriteLine(Urls);

sw2.WriteLine("modified=228928983");

sw2.WriteLine("IconIndex=0");

sw2.WriteLine("IconFile=" + dir + "http://www.cnblogs.com/bingyun84/admin/file://wygl.ico/");

sw2.Flush();

sw2.Close();

//#endregio

////部署开始菜单 ***************#region 部署开始菜单 ***************

string startMenue=Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);

if(File.Exists(startMenue+"\\亿联物业管理系统.url"))

{

if(MessageBox.Show("开始菜单已经存在,是否有覆盖它?","安装开始菜单",MessageBoxButtons.YesNo,MessageBoxIcon.Question,

MessageBoxDefaultButton.Button1) == DialogResult.Yes)

{

File.Copy(strDeskTop + "\\亿联物业管理系统.url", startMenue + "\\亿联物业管理系统.url", true);

}

else

{

throw new InstallException("开始菜单已经存在,安装取消");

}

}

else

{

File.Copy(strDeskTop + "\\亿联物业管理系统.url", startMenue + "\\亿联物业管理系统.url", false);

}

stateSaver.Add("StartMenueFile",startMenue+"\\亿联物业管理系统.url"); //保存开始菜单文件绝对地址

// 添加网站

Connect();

// 下面的信息为测试,可以自己编写文本框来接收用户输入信息

string serverID = "5555";

string serverComment = "QZG";

string defaultVrootPath = this.Context.Parameters["targetdir"];

if (defaultVrootPath.EndsWith(@"\"))

{

defaultVrootPath = defaultVrootPath.Substring(0, defaultVrootPath.Length-1);

}

string HostName = "";

string IP = "";

string Port = port;

string sReturn = CreateWebSite(serverID, serverComment, defaultVrootPath, HostName, IP, Port);

// 修改web.config

if (!WriteWebConfig())

{

//throw new ApplicationException("设置数据库连接字符串时出现错误");

MessageBox.Show("设置数据库连接字符串时出现错误");

}

// 写注册表

WriteRegistryKey();

}

#endregion

//删除时的方法。在本文中未详细操作,比如删除站点,删除数据库等。如果需要,请你自己补足

#region Uninstall 删除

//QZG

private bool DeleteDatabase()

{

try

{

DBName = this.Context.Parameters["dbname"].ToString();

if (string.IsNullOrEmpty(DBName))

{

DBName= GetDBNameFromWebConfig();

}

if (string.IsNullOrEmpty(DBName))

return false;

ExecuteSql("master", "USE MASTER IF EXISTS (SELECT NAME FROM SYSDATABASES WHERE NAME='" + DBName + "') DROP DATABASE "+DBName+" ");

return true;

}

catch

{

return false;

}

}

public override void Uninstall(IDictionary savedState)

{

//MessageBox.Show("卸载过程....");

if (savedState == null)

throw new ApplicationException("卸载数据库失败,未能卸载![qzg]");

else

{

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

if (!DeleteDatabase())

{

MessageBox.Show("卸载数据库错误,请手动删除物业管理系统的数据库!");

//throw new ApplicationException("卸载过程中发生错误,未能卸载!");

}

}

}

//END

#endregion

//end

#endregion

}