|
|
|
|
|
本文使用VS2005 制作 web 安装程序 (附加数据库方式)
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>
ShortCut.cs 生成桌面或者开始菜单快捷方式
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();
}
/**//*
关于如何加密配置信息:
http://blog.joycode.com/ghj/archive/2006/02/12/71378.aspx
http://msdn2.microsoft.com/en-us/library/zhhddkxy.aspx
http://blogs.msdn.com/federaldev/archive/2005/11/08/490319.aspx
http://msdn2.microsoft.com/en-us/library/dtkwfdky.aspx
http://aspdot.net/articles/encryptedconnstring/
http://davidhayden.com/blog/dave/archive/2005/11/17/2572.aspx
http://weblogs.asp.net/owscott/archive/2005/07/29/421063.aspx
加密批处理:
echo off
PATH %PATH%;%SystemRoot%\Microsoft.NET\Framework\v2.0.50727
aspnet_regiis -pef "connectionStrings" ShopWeb -prov "RsaProtectedConfigurationProvider"
aspnet_regiis -pef "connectionStrings" ManagerWeb -prov "RsaProtectedConfigurationProvider"
@PAUSE
解密批处理:
echo off
PATH %PATH%;%SystemRoot%\\Microsoft.NET\Framework\v2.0.50727
aspnet_regiis -pdf "connectionStrings" ShopWeb
aspnet_regiis -pdf "connectionStrings" ManagerWeb
@PAUSE
ShopWeb和ShopWeb是当前目录下的一个子目录。
*/
}
}
安装类 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
发表于
2008-05-11 19:24
hxm
阅读( 3621)
评论()
编辑
收藏
举报
|
|