1 建立“空白解決方案”,添加WEB SETUP項目
2 添加website空白檔案夾夾内的檔案。
App_Data\Material_DB_Data.MDF
App_Data\Material_DB_Log.LDF 用來附加的資料庫
Snap1.ico 快捷方式圖示檔案
Web.Config (注:事先在檔案裡添加了connectionstring
<add name="dbconnectionString" connectionString="server=(local);uid=sa;pwd=;database=material_db"/>
)
剩下的都是web網頁檔案了。
全部拖入web站點檔案夾,之後右鍵屬性=》安裝包 選中系統依賴=》MDAC 2.8 和 .NET 2.0 FRAMWROK
3 切換安裝視圖=》使用者界面=》添加一個Textbox(A) 4個文本框 ,修改其屬性
BannerBitmap (None)
BannerText 安裝資料庫
BodyText 安裝程式将在目标機器上安裝資料庫
Edit1Label 資料庫名稱:
Edit1Property DBNAME
Edit1Value Material_DB
Edit1Visible True
Edit2Label 伺服器名:
Edit2Property SERVER
Edit2Value (local)
Edit2Visible True
Edit3Label 使用者名:
Edit3Property USER
Edit3Value sa
Edit3Visible True
Edit4Label 密碼:
Edit4Property PWD
Edit4Value
Edit4Visible True
同樣可以修改WEB安裝計劃的屬性
Misc
AddRemoveProgramsIcon (None)
Author google想要統治丢球
Description 不需要描述
DetectNewerInstalledVersion False
Keywords
Localization Chinese (Simplified)
Manufacturer 微軟
ManufacturerUrl www.microsoft.com
PostBuildEvent
PreBuildEvent
ProductCode {153A5F79-1E50-4ECD-B469-090A32EC2726}
ProductName google想要統治地球
RemovePreviousVersions False
RestartWWWService True
RunPostBuildEventOn successful build
SearchPath
Subject
SupportPhone
SupportUrl
TargetPlatform x86
Title google想要統治地球
UpgradeCode {39DEFB52-8F2F-47D1-9AB7-1D21691A8DF4}
Version 1.0.0
具體請看視訊 (注意不要遺漏将 resourceList.xml 設定為“嵌入的資源”,為Custome Action 中的install 定義DLL輸出 設定DBNAME等參數,為class library 添加 Interop.IWshRuntimeLibrary DLL 本篇使用該DLL注冊快捷方式 )
Visual Studio 2005 how to make a install package from gakaki on Vimeo
Untitled from gakaki on Vimeo
resourceList.xml 檔案
為了項目修改友善使用XML 注意資料庫我将其放置在App_Data中了,ico檔案在根目錄下,
<?xml version="1.0" encoding="utf-8" ?>
<configroot>
<Files>
<MDF>
<File name="Material_DB_Data.MDF"/>
</MDF>
<LDF>
<File name="Material_DB_Log.LDF"/>
</LDF>
<圖示ICO名>
<File name="Snap1.ico"/>
</圖示ICO名>
<預設首頁>
<File name="Default.aspx"/>
</預設首頁>
</Files>
</configroot>

Code
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using IWshRuntimeLibrary;
namespace InstallHelper

{
class ShortCut
{
public static void 生成快捷方式(string 存放路徑位址, string 快捷方式名字, string 連結到哪裡, string 描述, string ico檔案路徑, string 若存在提示消息, ref string 儲存的路徑)
{
string 添加到如下位址 = 儲存的路徑 = Path.Combine(存放路徑位址, 快捷方式名字 + ".lnk");
WshShell wshShell = new WshShellClass();//建立 Windows Script Host Shell 類
IWshShortcut favShortcut = (IWshShortcut)wshShell.CreateShortcut(添加到如下位址);//定義快捷方式檔案
favShortcut.TargetPath = 連結到哪裡;
favShortcut.WorkingDirectory = System.Environment.CurrentDirectory;
favShortcut.WindowStyle = 1;
favShortcut.Description = 描述;
favShortcut.IconLocation = string.Format("{0},0", ico檔案路徑);
if (System.IO.File.Exists(添加到如下位址))
{
if (
MessageBox.Show(string.Format("{0}快捷方式已經存在,是否覆寫?", 若存在提示消息), string.Format("安裝{0}快捷方式", 若存在提示消息), MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1) == DialogResult.Yes
)
{
favShortcut.Save();//儲存快捷方式
}
}
else
{
favShortcut.Save();
}
}
}
}
加密web.config檔案 (還不完美 ,加密的時候會彈出DOS視窗,bat檔案需要轉碼,不然不支援中文路徑)

Code
namespace InstallHelper

{
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
class EncryptWebConfig
{
/// <summary>
/// 調用寫一個加密的BAT檔案 之後調用那個bat檔案 加密 web.config Encrypts the web config.
/// </summary>
/// <param name="targetdir">The targetdir.</param>
public static void EncryptTheWebConfig(string targetdir)
{
WriteABatchToEncryptBat(targetdir);
string batFileName = Path.Combine(targetdir, "encrypt.bat") ; //這個方法會拼接 路徑和檔案 => 路徑/xx.bat
//MessageBox.Show(batFileName);
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;//隐藏式執行
p.StartInfo = new System.Diagnostics.ProcessStartInfo(batFileName);
p.Start();
p.WaitForExit(); //等待執行完畢
//執行完删除.bat
if (File.Exists(batFileName))
{ File.Delete(batFileName); }
}
/// <summary>
///撰寫一個加密web.config的檔案 Writes the A batch to encrypt bat.
/// </summary>
/// <param name="targetdir">The targetdir.</param>
public static void WriteABatchToEncryptBat(string targetdir)
{
string dir = Path.Combine(targetdir, "encrypt.bat");
StreamWriter EncryptBatFileStream = System.IO.File.CreateText(dir);
EncryptBatFileStream.WriteLine("echo off");
EncryptBatFileStream.WriteLine(@"PATH %PATH%;%SystemRoot%\Microsoft.NET\Framework\v2.0.50727");
string encrypt = string.Format("aspnet_regiis -pef connectionStrings \"
{0}\"", targetdir);
EncryptBatFileStream.WriteLine(encrypt);
EncryptBatFileStream.Flush();
EncryptBatFileStream.Close();
EncryptBatFileStream.Dispose();
UTF82ANSI(dir);
}
private static void UTF82ANSI(string filepath)
{
//bat檔案為ansi格式 需要轉換
StreamReader sr = new StreamReader(filepath, Encoding.UTF8, false);
string data = sr.ReadToEnd();
sr.Close();
StreamWriter sw = new StreamWriter(filepath, false, Encoding.Default);
sw.Write(data);
sw.Close();
}
}
}
安裝類 InstallerDB.cs

Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.IO;
using System.Xml;
using System.Text.RegularExpressions;
using InstallHelper;
using System.Windows.Forms;
using System.Diagnostics;
namespace InstallDB

{
[RunInstaller(true)]
public partial class InstallerDB : Installer
{
public InstallerDB()
{
InitializeComponent();
}
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
各配置檔案夾 變量初始化#region 各配置檔案夾 變量初始化
//讀取指定xml檔案中的配置資訊 資料庫,圖示ICO名字 友善将來修改 隻要替換xml檔案就可以了
System.IO.Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("InstallDB.resourceList.xml");
XmlDocument config = new XmlDocument();
config.Load(stream);
string TargetstrMdfName = "";
string TargetstrLdfName = "";
string iconName = "";
string 預設首頁 = "";
if (config != null)
{
TargetstrMdfName = config.SelectSingleNode("configroot/Files/MDF/File").Attributes["name"].Value;
TargetstrLdfName = config.SelectSingleNode("configroot/Files/LDF/File").Attributes["name"].Value;
iconName = config.SelectSingleNode("configroot/Files/圖示ICO名/File").Attributes["name"].Value;
預設首頁 = config.SelectSingleNode("configroot/Files/預設首頁/File").Attributes["name"].Value;
}
else
{
throw new InstallException("沒有找到指定資料庫檔案位置的xml!");
}
string web安裝檔案夾 = Context.Parameters["targetdir"].ToString();//注意 該路徑 末尾多一個"\" 在 安裝程式中預設設定了targetdir H:\Inetpub\wwwroot\wss\VirtualDirectories\80\發夾清算系統324234\
string web安裝檔案夾末尾沒有斜杠 = web安裝檔案夾.Remove(web安裝檔案夾.LastIndexOf("\\"),1);
string webDirWeb虛拟檔案夾 = GetWebDir(web安裝檔案夾);
string MDF檔案路徑 = web安裝檔案夾 + "App_Data\\" + TargetstrMdfName;
string LDF檔案路徑 = web安裝檔案夾 + "App_Data\\" + TargetstrLdfName;
string ICON圖示路徑 = Path.Combine(web安裝檔案夾, iconName);
string 資料庫附加名字 = this.Context.Parameters["dbname"].ToString();
#endregion
//MessageBox.Show(web安裝檔案夾末尾沒有斜杠);
//MessageBox.Show(web安裝檔案夾);
//MessageBox.Show(webDirWeb虛拟檔案夾);
//MessageBox.Show(MDF檔案路徑);
//MessageBox.Show(LDF檔案路徑);
//MessageBox.Show(ICON圖示路徑);
//擷取附加SQL 資料庫 語句指令
string AttachDbSQLStr = GetAttachDbSQLStr("dbname", MDF檔案路徑, LDF檔案路徑);
//MessageBox.Show(AttachDbSQLStr);
//執行SQL 附加資料庫
ExecuteSql(GetSqlConnectionStrDBMaster("server", "user", "pwd"), AttachDbSQLStr);
//使用安裝包中指定參數替換web.config字元串 注意這裡的dbconnectionString是web.config中本來我指定的
WriteWebConfig(GetSqlConnectionStr("server", "user", "pwd", "dbname"), "targetdir", "dbconnectionString");
//加密web.config
InstallHelper.EncryptWebConfig.EncryptTheWebConfig(web安裝檔案夾末尾沒有斜杠);
//快捷方式
string 開始菜單快捷方式_儲存路徑 = "";
string 桌面快捷方式_儲存路徑="";
開始和桌面快捷方式儲存(ICON圖示路徑, ref 開始菜單快捷方式_儲存路徑, ref 桌面快捷方式_儲存路徑, webDirWeb虛拟檔案夾, 預設首頁);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
throw ex;
}
//清理不需要的dll之類的安裝殘留檔案
//注意 *.InstallState 不能删除 哪就是statesave儲存資料的地方 有人說放web.config算了 不是一樣的嘛
}
private void DeleteIfExists(string filePath)
{
if (File.Exists(filePath))
{
File.Delete(filePath);
}
}
private void 開始和桌面快捷方式儲存(string icopath, ref string 開始菜單快捷方式_儲存路徑, ref string 桌面快捷方式_儲存路徑, string web虛拟路徑名, string 預設首頁)
{
try
{
string 開始菜單 = Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);
string 桌面 = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);//注意不是deskop 那可能會變成system32
string 快捷方式名字 = web虛拟路徑名;
string 連結到哪裡 = string.Format(@"http://localhost/{0}/{1}",web虛拟路徑名,預設首頁); //是網頁就要加上HTTP
string 描述 = web虛拟路徑名;
string ico檔案路徑 = icopath;
string 若存在提示消息_開始菜單 = "開始菜單";
string 若存在提示消息_桌面 = "桌面";
InstallHelper.ShortCut.生成快捷方式(開始菜單, 快捷方式名字, 連結到哪裡, 描述, ico檔案路徑, 若存在提示消息_開始菜單, ref 開始菜單快捷方式_儲存路徑);
InstallHelper.ShortCut.生成快捷方式(桌面, 快捷方式名字, 連結到哪裡, 描述, ico檔案路徑, 若存在提示消息_桌面, ref 桌面快捷方式_儲存路徑);
//MessageBox.Show(連結到哪裡);
//MessageBox.Show(開始菜單快捷方式_儲存路徑);
//MessageBox.Show(桌面快捷方式_儲存路徑);
}
catch (Exception exc)
{
throw new Exception("建立快捷方式錯誤!" + exc.Message);
}
}
/// <summary>
/// 寫入 web.config Writes the web config.
/// </summary>
/// <param name="modifiedSqlStr">The modified SQL STR.</param>
/// <param name="contextTargetDir">The context target dir.</param>
/// <param name="RegexPattern">The regex pattern.</param>
protected void WriteWebConfig(string modifiedSqlStr, string contextTargetDir, string RegexPattern)
{
try
{
string TargetDir = Context.Parameters[contextTargetDir].ToString();
string FileFullName = TargetDir + @"Web.config";
FileInfo file = new FileInfo(FileFullName);
Regex regex = new Regex(RegexPattern, RegexOptions.IgnoreCase);
XmlDocument doc = new XmlDocument();
doc.Load(file.FullName);
XmlElement root = doc.DocumentElement;
XmlNodeList list = root.SelectNodes("/configuration/connectionStrings/add");
foreach (XmlNode node in list)
{
if (regex.IsMatch(node.Attributes["name"].Value))
{
//string hxm = node.Attributes["connectionString"].Value;//用來測試的而已,可以儲存這裡的變量到一個文本檔案裡 最後 作為安裝日志顯示出來
//若為card_Clean_DB的連接配接字元串,修改 連接配接字元串
node.Attributes["connectionString"].Value = modifiedSqlStr;
doc.Save(file.FullName);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
throw ex;
}
}
/// <summary>
/// Attaches the data base 附加資料庫.
/// </summary>
/// <param name="strSql">The STR SQL.資料庫連接配接字元串</param>
/// <param name="DataName">資料庫名稱</param>
/// <param name="strMdf">mdf檔案名字</param>
/// <param name="strLdf">ldf檔案名字</param>
private void ExecuteSql(string connectionstring, string attachDbSQLStr)
{
//附加資料庫 ### 附加資料庫#region ### 附加資料庫
SqlConnection myConn = new SqlConnection(connectionstring);
SqlCommand myCommand = new SqlCommand(attachDbSQLStr, myConn);
try
{
myConn.Open();
myCommand.ExecuteNonQuery();
}
catch (SqlException ex)
{ throw ex; }
finally
{
myConn.Close();
}
////建立資料庫使用者的登陸名和密碼(登陸名:gakaki 密碼:z5896321) ###建立資料庫使用者的登陸名和密碼(登陸名:gakaki 密碼:z5896321)#region ###建立資料庫使用者的登陸名和密碼(登陸名:gakaki 密碼:z5896321)
//string str2 = "exec sp_addlogin 'gakaki','z5896321'" + " " + "use " + DataName + "" + " " + "exec sp_adduser 'gakaki'" + " " + "exec sp_addrolemember 'db_owner','gakaki'";
//SqlCommand cmd2 = new SqlCommand(str2, myConn);
//cmd2.ExecuteNonQuery();
//myConn.Close();
}
/// <summary>
/// 得到附加資料庫所用的sql語句.
/// </summary>
/// <param name="contextDataName">Name of the context data 安裝包中輸入的資料庫參數名</param>
/// <param name="strMdf">The STR MDF.資料庫實體檔案MDF名</param>
/// <param name="strLdf">The STR LDF..資料庫實體檔案LDF名</param>
/// <returns></returns>
public string GetAttachDbSQLStr(string contextDataName, string strMdf, string strLdf)
{
string DataName = this.Context.Parameters[contextDataName].ToString();
string attachDbSQLStr = "EXEC sp_attach_db @dbname = '" + DataName + "', @filename1 = '" + strMdf + "',@filename2='" + strLdf + "'";
return attachDbSQLStr;
}
//擷取web映射檔案夾的名字]
public string GetWebDir(string targetdir)
{
string webdir = Regex.Replace(targetdir, "\\\\$", "");
webdir = webdir = webdir.Substring(webdir.LastIndexOf(("\\")) + 1);
return webdir;
}
/// <summary>
/// Gets the SQL connection STR 根據安裝包輸入的資料庫連接配接 構成連接配接資料庫的sql語句.
/// </summary>
/// <param name="contextServer">The context server 安裝包中輸入的位址的參數名</param>
/// <param name="contextUid">The context uid.安裝包中輸入的SQL的使用者名</param>
/// <param name="contextPwd">The context PWD. .安裝包中輸入的SQL的密碼</param>
/// <param name="contextDb">The context db.安裝包中輸入的SQL的資料庫名</param>
/// <returns></returns>
private string GetSqlConnectionStr(string contextServer, string contextUid, string contextPwd, string contextDb)
{
string server = Context.Parameters[contextServer].ToString();
string uid = Context.Parameters[contextUid].ToString();
string pwd = Context.Parameters[contextPwd].ToString();
string dbName = Context.Parameters[contextDb].ToString();
string strSql = "server=" + server + ";uid=" + uid + ";pwd=" + pwd + ";database=" + dbName;
//string connStr = string.Format("server={0};uid={1};pwd={2};persist security info=false;packet size=4096;database={3}", server, uid, pwd, dbName);
return strSql;
}
/// <summary>
/// Gets the SQL connection STR 根據安裝包輸入的資料庫連接配接 構成連接配接資料庫的sql語句.
/// </summary>
/// <param name="contextServer">The context server 安裝包中輸入的位址的參數名</param>
/// <param name="contextUid">The context uid.安裝包中輸入的SQL的使用者名</param>
/// <param name="contextPwd">The context PWD. .安裝包中輸入的SQL的密碼</param>
/// <returns></returns>
private string GetSqlConnectionStrDBMaster(string contextServer, string contextUid, string contextPwd)
{
string server = Context.Parameters[contextServer].ToString();
string uid = Context.Parameters[contextUid].ToString();
string pwd = Context.Parameters[contextPwd].ToString();
string strSql = "server=" + server + ";uid=" + uid + ";pwd=" + pwd + ";database=master";
return strSql;
}
/// <summary>
/// 傳回 Web.confi中名為 cardCleanDB的 connectionString connectionString="server=.;Initial Catalog=Card_Clean_DB;User ID=sa;pwd=;" providerName="System.Data.SqlClient"/>
/// </summary>
/// <param name="server">The server.</param>
/// <param name="strUser">The STR user.</param>
/// <param name="strPass">The STR pass.</param>
/// <param name="DBNAME">The DBNAME.</param>
/// <returns></returns>
public string GetSetupConnectionString(string server, string strUser, string strPass, string DBNAME)
{
string connectionString = "server=" + server + ";uid=" + strUser + ";pwd=" + strPass + ";database=" + DBNAME;
return connectionString;
}
}
}
安裝包的整體思路
1 打開安裝包安裝,填寫資料庫的位置密碼,填寫虛拟站點名字,無誤之後下一步。
2 這個時候才到 Installer。cs 裡的 override void Install 方法裡
剛才輸入的資料庫位置密碼,已經被記錄下來,在安裝包的custome action裡的CustomActionData裡
/dbname=[DBNAME] /server=[SERVER] /user=[USER] /pwd=[PWD] /targetdir="[TARGETDIR]\"
3 找XML檔案夾裡的資料庫 附加,還有預設首頁
4 之後執行附加SQL的語句
5 使用新的連接配接資料庫參數拼接出connectionstring,從複制的webconfig中找出原來的connectionstring修改。
6 儲存快捷方式
難度不高,但是任何一個環節出問題,都會有問題導緻,安裝失敗。web站點必須的檔案是否齊全,資料庫,xml,web.config。
建議可以添加System.Windows.Forms用messagebox.show顯示資訊。
暫時有些小問題,按照之前cnblogs的很多文章的介紹,重載Unistall方法,在安裝的時候,可以在installstate.state檔案
裡存放目前資料庫的路徑,web站點的真實路徑。或者快捷方式的路徑。然後解除安裝的時候讀取state檔案就可以删除快捷方式的路徑,删除資料庫。
這個方式有一個缺點,萬一解除安裝的時候點了取消,彈出對話框問您是否真的要取消,點了“否”的話。解除安裝程式會Rollback,
解除安裝的檔案會COPY回去。但是确會把installstate.state檔案删除。這下好了,下次在要解除安裝的時候,因為找不到檔案state
就報異常(重載的Uninstall的方法裡有讀取state的動作)導緻不讓解除安裝了。當然這也不是什麼大問題,重新修改安裝檔案的productcode
就可以讓你重新安裝了(因為productid換了嘛)。然後不要寫state檔案将這些資料存放在XML檔案裡。(不想弄這個了,有好心人可以完善的話
可以聯系一下完善源代碼)
源代碼 注意需要 重新添加Web站點程式裡檔案夾裡的檔案
Future Reading: 把SQL資料庫部署到遠端主機環境
InstallShield 篇
InstallShield For .Net制作.Net項目安裝包之完整代碼
InstallShield X - Express Edition 10 制作.NET程式安裝包初探
使用Install Shield打包應用程式的初級應用 visual studio MSI篇
一次.NET Web應用程式安裝包的制作經曆:Sql資料庫安裝的3種方式
.net 程式打包
Conditional Install of Desktop anhttp://www.cnblogs.com/jenry/articles/428348.htmld Quick Launch Shortcuts
Editing MSI Deployment Packages with Orca and Adding Custom Shortcuts
wix篇
[Reference]Wix Restart IIS code snippet
[Wix] 添加自定義Action
轉載于:https://www.cnblogs.com/gakaki/archive/2008/05/11/1180087.html