web项目打包过程中数据库配置文件、以及虚拟目录、端口设置方式,具体如下:
第一步:创建一个空白的解决方案
1、打开vs平台,点击【新建】--》【项目】,进入新建项目窗口;
2、在项目类型中选择【其他类型项目】--》【安装和部署】,然后在右侧模版中选择【web安装项目】,录入项目名称WebSetupSln,点击确定;
第二步:创建安装过程中定义具体操作工程
1、在解决方案WebSetupSln上点击鼠标右键,点击【添加】--》【新建项目】,弹出【添加新项目】对话框,如下所示:
2、在其中选择【类库】,填写项目名称InstallLibruary,点击确定
3、删除新添加项目中默认文件Class1.cs,在项目上右键,点击【添加】--》【新建项】,进入【添加新项】,在其中选择【安装程序类】,录入名称WebInstaller.cs,点击确定
第三步:安装包项目输出添加
1、将需要打包的程序发布到指定目录
2、运行当前整个解决方案,然后选择前面添加web安装项目,点击右键---【添加】---【项目输出】,弹出【添加项目输出组】对话框,在其中选择InstallLibruary,然后选择下面列表框中的【主输出】,点击确定
3、在项目上点击右键--【视图】--【文件系统】,打开安装项目文件系统,在左侧列表中选择对应的【web应用程序文件夹】,然后将(1)中发布的文件复制之后粘贴到右边窗口中
(其实在该处操作有两种情况,如果你需要发布的是网站,可以按照该操作执行,如果你需要打包的是web应用程序,需要像(2)中步骤,将在项目输出中添加尽可,不过需要选择主输出与内容文件两项,这里就不作说明了)
第四步:在安装项目中添加自定义操作
1、右击安装项目--【视图】--【用户界面】,在左侧显示用户界面,右击【启动】--【添加对话框】,在其中选择【文本框A】、【文本框B】,点击确定(如果需要许可协议等其他的,同样在此处添加,具体不做详细说明)
2、回到用户界面,将添加的文本框A、文本框B移动到安装地址上方
3、编辑文本框A属性,具体内容如下如:
上述两个属性框中,A主要用于设置项目对应数据库配置、B主要用于web站点配置,在这里设置时需要注意EDITAPROPERTY与EDITAValue项,其中EDITAPROPERTY主要是在后面【自定义操作】设置时与对应的字符串相呼应,EDITAValue则为安装过程中对应项的默认值。
4、在安装项目上右击,点击【视图】--【自定义操作】,在左侧打开自定义操作界面,右击【安装】--【添加自定义操作】,弹出选择框,在对话框中双击【web应用程序文件夹】,选择其中InstallLibruary主输出项。然后会在【安装】下面出现【主输出来自InstallLibruary(活动)】项目,按F4,在右侧出现其属性项、设置CustomActionData属性:
/dbname=[DBNAME] /dbserver=[DBSERVER] /user=[USERNAME] /pwd=[PASSWORD] /port=[IISPORT] /virtualdir=[VIRTUALDIR] /targetdir="[TARGETDIR]\"
上面红色内容为(3)中设置的EDITAPROPERTY项,其中TARGETDIR为安装地址,对于web项目来讲,是基于iis根目录下的相对目录,这个至于如何设定成自定义的俺没搞懂。蓝色的内容将在后面InstallLibruary项目中具体编码时使用到,后面会有提及。
第四步:自定义操作具体代码实现
1、完成上面步骤之后,就需要为上述定义的自定义功能添加具体实现,首先打开InstallLibruary项目中的WebInstaller.cs,其中代码实现如下,逐步做出说明:
[RunInstaller(true)]
public partial class WebInstaller: Installer
{
private string dbname;
private string dbserver;
private string user;
private string pwd;
private string port;
private string physicaldir;
private string virtualdir;
public WebInstaller()
{
InitializeComponent();
}
#region Install 从这里开始启动安装
public override void Install(IDictionary stateSaver)
{
try
{
base.Install(stateSaver);
physicaldir = this.Context.Parameters["targetdir"].ToString(); //获取物理路径,对于web站点来讲是相对iis根目录的相对路径,一般使用虚拟目录名称即可
virtualdir = this.Context.Parameters["virtualdir"].ToString(); //获取虚拟目录
dbname = this.Context.Parameters["dbname"].ToString(); //获取数据库名称
dbserver = this.Context.Parameters["dbserver"].ToString(); //获取服务器名称
user = this.Context.Parameters["user"].ToString(); //用户名
pwd = this.Context.Parameters["pwd"].ToString(); //密码
port = this.Context.Parameters["port"].ToString(); //iis服务器
string defaultdoc = "Default.aspx" ; //默认首页
// 创建虚拟目录
CreateSite(port, virtualdir, defaultdoc);
// 修改web.config
WriteWebConfig();
//创建数据库,该部分执行起来我感觉比较麻烦,要求数据库服务器在本机,如果不在本机数据库还是安装不上,一般web项目数据库服务器都是分离的,所以直接手动附加或者还原更简单(个人看法,呵呵)
//if (AddDBTable(dbname) == -1)
//{
// MessageBox.Show("数据库安装失败,如果确认数据库不在当前机器上,请手工在数据库服务器上进行附加!");
//}
}
catch (Exception ee)
{
throw new Exception(ee.Message);
}
}
#endregion
public void CreateSite(string port, string siteExplain, string defaultDoc)
{
DirectoryEntry de = new DirectoryEntry("IIS://localhost/" + "w3svc"); //从活动目录中获取IIS对象。 对于服务器来讲,就是【网站】那个节点
int siteID = 1; //下属站点ID,通过下属方法找到没有使用的网站ID
oreach (DirectoryEntry e in de.Children)
{
if (e.SchemaClassName == "IIsWebServer") //IIsWebServer表示网站
{
int ID = Convert.ToInt32(e.Name);
if (ID >= siteID)
{
siteID = ID + 1;
}
}
}
// Create web site
DirectoryEntry site = (DirectoryEntry)de.Invoke("Create", "IIsWebServer", siteID); //创建网站
te.Properties["KeyType"][0] = "IIsWebServer";
site.Properties["ServerComment"][0] = siteExplain; //站点说明
site.Properties["ServerState"][0] = 2; //站点初始状态,1.停止,2.启动,3
site.Properties["ServerSize"][0] = 1;
site.Properties["ServerBindings"].Add(":" + port + ":"); //站点端口
site.CommitChanges(); //保存改变
de.CommitChanges();
DirectoryEntry root = site.Children.Add("Root", "IIsWebVirtualDir"); //添加站点下虚拟目录对象
root.Invoke("AppCreate", true); //创建IIS应用程序
root.Properties["path"][0] = physicaldir ; //虚拟目录指向的物理目录
root.Properties["EnableDirBrowsing"][0] = false;//目录浏览
root.Properties["AuthAnonymous"][0] = false;
root.Properties["AccessExecute"][0] = false; //可执行权限
root.Properties["AccessRead"][0] = true;
root.Properties["AccessWrite"][0] = true;
root.Properties["AccessScript"][0] = true;//纯脚本
root.Properties["AccessSource"][0] = false;
root.Properties["FrontPageWeb"][0] = false;
root.Properties["KeyType"][0] = "IIsWebVirtualDir";
root.Properties["AppFriendlyName"][0] = siteExplain; //应用程序名
root.Properties["AppIsolated"][0] = 2;
root.Properties["DefaultDoc"][0] = defaultDoc; //默认文档
root.Properties["EnableDefaultDoc"][0] = true; //是否启用默认文档
root.CommitChanges();
site.CommitChanges();
root.Close();
site.Close();
de.CommitChanges(); //保存
site.Invoke("Start", null); //除了在创建过程中置初始状态外,也可在此调用方法改变状态
}
private void WriteWebConfig()
{
int c = 20;
//加载配置文件
try
{
c++;
System.IO.FileInfo FileInfo = new System.IO.FileInfo(this.Context.Parameters["targetdir"] + "/web.config");
if (!FileInfo.Exists)
{
throw new InstallException("缺少配置文件 :" + this.Context.Parameters["targetdir"] + "/web.config");
}
c++;
System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
xmlDocument.Load(FileInfo.FullName);
c++;
//修改连接字符串
foreach (System.Xml.XmlNode Node in xmlDocument["configuration"]["appSettings"])
{
if (Node.Name == "add")
{
c++;
if (Node.Attributes.GetNamedItem("key").Value == "ConnectionString")
{
c++;
Node.Attributes.GetNamedItem("value").Value = String.Format("Database={0};Server={1};Uid={2};Pwd={3};", dbname, dbserver, user, pwd);
}
}
}
xmlDocument.Save(FileInfo.FullName);
}
catch
{
throw new Exception("数据库配置修改出错!");
}
}
private void ExecuteSql(string connStr, string DatabaseName, string Sql)
{
SqlConnection conn = new SqlConnection(connStr);
SqlCommand cmd = new SqlCommand(Sql, conn);
conn.Open();
conn.ChangeDatabase(DatabaseName);
try
{
cmd.ExecuteNonQuery();
}
finally
{
conn.Close();
}
}
/// <summary>
/// 创建数据库
/// </summary>
/// <param name="strDBName"></param>
protected int AddDBTable(string strDBName)
{
try
{
string strconn = "Data Source=" + this.Context.Parameters["dbserver"] +
";Initial Catalog=master;Persist Security Info=True;User ID=" + this.Context.Parameters["user"] + ";Password=" + this.Context.Parameters["pwd"] + "";
//ExecuteSql(strconn,"master", "CREATE DATABASE " + strDBName);
string strSql = "EXEC sp_attach_db @dbname = N'" + this.Context.Parameters["dbname"] + "',"
+ "@filename1 = N'" + this.Context.Parameters["targetdir"] + "DataBase\\Space.mdf',"
+ "@filename2 = N'" + this.Context.Parameters["targetdir"] + "DataBase\\Space_log.ldf'";
ExecuteSql(strconn, "master", strSql);
return 0;
}
catch
{
return -1;
}
}
#region Uninstall 删除
public override void Uninstall(IDictionary savedState)
{
//添加自定义的卸载代码
if (savedState == null)
{
throw new ApplicationException("未能卸载!");
}
else
{
base.Uninstall(savedState);
}
}
#endregion
}
至此基本结束了,如果添加网站不是使用端口,直接使用域名的话,可以使用下面代码,这个我具体还没有测试过,大家可以试试
public int CreateWebSite(string webSiteName, string pathToRoot, string bd) //创建网站
{
DirectoryEntry root = new DirectoryEntry("IIS://localhost/W3SVC");
// Find unused ID value for new web site
int siteID = 1;
foreach (DirectoryEntry e in root.Children)
{
if (e.SchemaClassName == "IIsWebServer")
{
int ID = Convert.ToInt32(e.Name);
if (ID >= siteID)
{
siteID = ID + 1;
}
}
}
// Create web site
DirectoryEntry site = (DirectoryEntry)root.Invoke("Create", "IIsWebServer", siteID);
site.Invoke("Put", "ServerComment", webSiteName);//网站名称
site.Invoke("Put", "ServerBindings", bd);//二级域名绑定
site.Invoke("Put", "ServerState", 2);//默认4
site.Invoke("Put", "DefaultDoc", "index.htm,index.asp,index.aspx,Default.aspx");
site.Invoke("Put", "ServerAutoStart", 1);//开启站点
site.Invoke("SetInfo");
DirectoryEntry siteVDir = site.Children.Add("ROOT", "IISWebVirtualDir");
siteVDir.Invoke("AppCreate", true); //创建应用程序站点
siteVDir.CommitChanges();
site.CommitChanges();
siteVDir.Properties["AppIsolated"][0] = 2;//默认2
siteVDir.Properties["Path"][0] = pathToRoot;//主目录路径
siteVDir.Properties["AccessFlags"][0] = 513;
siteVDir.Properties["FrontPageWeb"][0] = 1;
siteVDir.Properties["AppRoot"][0] = "/LM/W3SVC/" + siteID + "/Root";
siteVDir.Properties["AppFriendlyName"][0] = "默认应用程序";
siteVDir.Properties["AspEnableParentPaths"][0] = true; //父路径启用
siteVDir.CommitChanges();
site.CommitChanges();
return siteID;
}
这东西感觉没啥,实际上因为一直发布web项目都直接拷贝发布就行了,比较方便,所以从来没有这样搞过,这次整的有点烦躁,花了好几天,看了很多别人代码,拿过来没法用,老是报错,后来发现就是在创建网站跟目录时报1001错误,后来通过遍历站点的方式最终ok了,写下来,看看对大家有没有用。