站点: 如果新建默认的Web安装项目,那它将创建的默认网站下的一个虚拟应用程序目录而不是一个新的站点。故我们只有创建新的安装项目,而不是Web安装项目。然后通过安装类进行自定义操作,创建新站如下图:
2、创建新的安项目之后,在(文件系统编辑器)里的应用程序文件夹里,添加2.0的项目输出(还有第二种方法是用2.0发布网站到一个文件夹下面,再把这个文件夹下面所有文件复制粘贴过来,这样生成的安装文件,在安装之后就没有源代码文件了,我自己就是这样做的)如下图:
图1下图的MyPojectSetup项目下已有了Web项目的输出,以及一个SQL脚本(SQL脚本是通SQL生成的,将在安装类库里要使用的)
图2文件系统左边界面,添加了Web项目输出
2.2添加完项目输出之后,需要设置安装界面。我们的要求是第一、建一个新站点,所以需要所安装的IIS服务器地址,以及新站点的端口。第二、需要数据库的地址,新建的数据库名称,以及访问数据库的用户名和密码两项(需要有创库权限的)。
如图1在文件系统编辑器右边,选择用户界面,然后看到如下:
在启动选择单击右击菜单,添加对话框A,并在对话框A上单击右键=》上移到安装文件夹的上面:
再次设置右边属性,文本框A是站点信息输入如下信息,其中Edit1Property是一个需要传入安装类的参数。
按照以上方式再添加文本框B并移到文本框A的下面,如下图所示
注意:如上所示安装项目基本的事情已经做完了,但还有最后一个步骤没有做,那就是自定义操作,也就安装的重中之重的事情,安装类库的创建,如3点所示。创建安装类库之后就需要把它的输出来添加到安装项目里如同Web项目,然后设置自定义活动为这个项目就可以,详情在下面介绍。
3、需要创建一个安装类库,里面把Class1.cs删除,再添加一个新的安装文件。安装项目所有的自定义都是在这里用编码完成的(包括数据库生成,虚拟站点创建,IIS属性修改,Web.Config文件修改)。也就是说,安装项目是个外壳,通过创建一些界面接收用户参数,然后利用这个安装类库,提供的功能,进行自己的操作。
4、安装程序类新建之后,双击进入代码状态,用override重载Install函数如下所示:
usingSystem;
usingSystem.Collections.Generic;
ponentModel;
usingSystem.Configuration.Install;
namespaceMyProjectInstall
...{
[RunInstaller(true)]
publicpartialclassInstallerMySample:Installer
...{
publicInstallerMySample()
...{
InitializeComponent();
}
publicoverridevoidInstall(System.Collections.IDictionarystateSaver)
...{
}
}
}
安装数据库的代码如下,其中用了两种方法,一种是用SQL命令方式创建数据库,另一种是调用osql命令执行脚本,创建数据表结构等,最后用命令追加一条记录.
数据库操作#region数据库操作
protectedvoidAddDBTable()
...{
try
...{
//创建数据库
ExcuteSQL("master",string.Format("CREATEDATABASE{0}",this._dataBaseName));
//调用osql执行脚本
ExcuteScript();
//添加原始数据
ExcuteSQL(_dataBaseName,"INSERTINTOGV_SystemAdmin(SystemAdminUser,SystemAdminPass,SystemAdminName,SystemAdminMemo)VALUES('admin','admin','Administrator','系统默认超级用户')");
}
catch(Exceptionex)
...{
thrownewApplicationException(ex.Message);
}
}
//此方法在本例中未用到,因为最后只要追加一条记录,
//但如果有多条可以写成一个脚本,以资源的形式嵌入到这个项目
//然后用如下的方法读取,然后调用SQL命令执行
privatestringGetSQLScript(stringfileName)
...{
try
...{
//得到当前程序集
Assemblyasm=Assembly.GetExecutingAssembly();
//资源文件
Streamstrm=
asm.GetManifestResourceStream(asm.GetName().Name+"."+fileName);
//读取嵌入文件内容,文本文件内容必须为Unicode
StreamReaderreader=newStreamReader(strm);
returnreader.ReadToEnd();
}
catch
...{
returnString.Empty;
}
}
privatevoidExcuteSQL(stringdataBaseName,stringSQL)
...{
SqlConnectioncon=
newSqlConnection(string.Format("userid={0};password={1};InitialCatalog={2};DataSource={3};",_username,_saPassword,dataBaseName,_servername));
SqlCommandcmd=newSqlCommand(SQL,con);
cmd.Connection.Open();
cmd.Connection.ChangeDatabase(dataBaseName);
try
...{
cmd.ExecuteNonQuery();
}
finally
...{
//最后总要关闭数据库
cmd.Connection.Close();
}
}
privatevoidExcuteScript()
...{
try
...{
ProcesssqlProcess=newProcess();
//调用osql必须在目标机,也就是安装的机子上要有安装SQLServer服务器
//不然找不到这个命令
sqlProcess.StartInfo.FileName="osql.exe";
//如下所指的SQL脚本文件是打包打安装项目的文件名,
//targetPath就是在安装界面用户指定的安装目录
sqlProcess.StartInfo.Arguments=string.Format("-U{0}-P{1}-d{2}-S{3}-i{4}VideoMeetingCreateSQL2000.sql",
_username,_saPassword,_dataBaseName,_servername,_targetPath);
sqlProcess.StartInfo.WindowStyle=ProcessWindowStyle.Hidden;
sqlProcess.Start();
sqlProcess.WaitForExit();
sqlProcess.Close();
}
catch(Exceptionex)
...{
throwex;
}
}
#endregion
修改Web.Config配置的代码如下:
WriteWebConfig修改web.config的连接数据库的字符串#regionWriteWebConfig修改web.config的连接数据库的字符串
privateboolWriteWebConfig()
...{
System.IO.FileInfoFileInfo=newSystem.IO.FileInfo(this.Context.Parameters["targetdir"]+"/web.config");
if(!FileInfo.Exists)
...{
thrownewInstallException("Missingconfigfile:"+this.Context.Parameters["targetdir"]+"/web.config");
}
System.Xml.XmlDocumentxmlDocument=newSystem.Xml.XmlDocument();
xmlDocument.Load(FileInfo.FullName);
boolFoundIt=false;
foreach(System.Xml.XmlNodeNodeinxmlDocument["configuration"]["connectionStrings"])
...{
if(Node.Name=="add")
...{
if(Node.Attributes.GetNamedItem("name").Value=="MonitorConnectionString")
...{
Node.Attributes.GetNamedItem("connectionString").Value=String.Format("DataSource={0};database={1};UserID={2};Password={3}",_servername,_dataBaseName,_username,_saPassword);
FoundIt=true;
}
}
}
if(!FoundIt)
...{
thrownewInstallException("Errorwhenwritingtheconfigfile:web.config");
}
xmlDocument.Save(FileInfo.FullName);
returnFoundIt;
}
#endregion
创建IIS站点的代码如下(注我也是从网找到的,其中CreateNewWebsit这个方法中我加了IIS参数设置的代码,也就是在创建IIS时一并设置了):
注意这一句:string fileName = Environment.GetEnvironmentVariable("windir") + @"//Framework/v2.0.50727/ASPnet_regiis.exe";原因是当你不管是手动还是自动创建一个新站点,在它的属性页设置里都会有1.1版和2.0版这个选项,默认是1.1,现在我要部署2.0所以在默认情况下就不能够一步到位,安装完就可以访问执行,而要去设置成2.0才行.所以要调用FrameworkV2.0下的regiis.exe得新注册一下我们指定的虚拟目录,使它是2.0.
usingSystem;
usingSystem.DirectoryServices;
usingSystem.Collections;
usingSystem.Text.RegularExpressions;
usingSystem.Text;
usingSystem.Runtime;
usingSystem.Diagnostics;
/**//**
*@author吴海燕
*@emailwuhy80-usual@
*-6-25第一版
*/
namespaceWuhy.ToolBox
...{
/**////<summary>
///这个类是静态类。用来实现管理IIS的基本操作。
///管理IIS有两种方式,一是ADSI,一是WMI。由于系统限制的原因,只好选择使用ADSI实现功能。
///这是一个遗憾。只有等到只有使用IIS6的时候,才有可能使用WMI来管理系统
///不过有一个问题就是,我现在也觉得这样的一个方法在本地执行会比较的好。最好不要远程执行。
///因为那样需要占用相当数量的带宽,即使要远程执行,也是推荐在同一个网段里面执行
///</summary>
publicclassIISAdminLib
...{
UserName,Password,HostName的定义#regionUserName,Password,HostName的定义
publicstaticstringHostName
...{
get
...{
returnhostName;
}
set
...{
hostName=value;
}
}
publicstaticstringUserName
...{
get
...{
returnuserName;
}
set
...{
userName=value;
}
}
publicstaticstringPassword
...{
get
...{
returnpassword;
}
set
...{
if(UserName.Length<=1)
...{
thrownewArgumentException("还没有指定好用户名。请先指定用户名");
}
password=value;
}
}
publicstaticvoidRemoteConfig(stringhostName,stringuserName,stringpassword)
...{
HostName=hostName;
UserName=userName;
Password=password;
}
privatestaticstringhostName="localhost";
privatestaticstringuserName;
privatestaticstringpassword;
#endregion
根据路径构造Entry的方法#region根据路径构造Entry的方法
/**////<summary>
///根据是否有用户名来判断是否是远程服务器。
///然后再构造出不同的DirectoryEntry出来
///</summary>
///<paramname="entPath">DirectoryEntry的路径</param>
///<returns>返回的是DirectoryEntry实例</returns>
publicstaticDirectoryEntryGetDirectoryEntry(stringentPath)
...{
DirectoryEntryent;
if(UserName==null)
...{
ent=newDirectoryEntry(entPath);
}
else
...{
//ent=newDirectoryEntry(entPath,HostName+"/"+UserName,Password,AuthenticationTypes.Secure);
ent=newDirectoryEntry(entPath,UserName,Password,AuthenticationTypes.Secure);
}
returnent;
}
#endregion
添加,删除网站的方法#region添加,删除网站的方法
/**////<summary>
///创建一个新的网站。根据传过来的信息进行配置
///</summary>
///<paramname="siteInfo">存储的是新网站的信息</param>
publicstaticvoidCreateNewWebSite(NewWebSiteInfositeInfo)
...{
if(!EnsureNewSiteEnavaible(siteInfo.BindString))
...{
thrownewException("已经有了这样的网站了。"+Environment.NewLine+siteInfo.BindString);
}
stringentPath=String.Format("IIS://{0}/w3svc",HostName);
DirectoryEntryrootEntry=GetDirectoryEntry(entPath);
stringnewSiteNum=GetNewWebSiteID();
DirectoryEntrynewSiteEntry=rootEntry.Children.Add(newSiteNum,"IIsWebServer");
mitChanges();
//Hashtableahs1=newHashtable();
//foreach(stringa1innewSiteEntry.Properties.PropertyNames)
//{
//ahs1.Add(a1,newSiteEntry.Properties[a1].Value);
//}
newSiteEntry.Properties["ServerBindings"].Value=siteInfo.BindString;
newSiteEntry.Properties["ServerComment"].Value=mentOfWebSite;
mitChanges();
DirectoryEntryvdEntry=newSiteEntry.Children.Add("root","IIsWebVirtualDir");
mitChanges();
vdEntry.Properties["Path"].Value=siteInfo.WebPath;
vdEntry.Invoke("AppCreate",true);//创建应用程序
vdEntry.Properties["AccessRead"][0]=true;//设置读取权限
vdEntry.Properties["DefaultDoc"][0]="default.htm";//设置默认文档
vdEntry.Properties["AppFriendlyName"][0]="VideoMeeting";//应用程序名称
vdEntry.Properties["AccessScript"][0]=true;//执行权限
vdEntry.Properties["AuthFlags"][0]=1;//0表示不允许匿名访问,1表示就可以3为基本身份验证,7为windows继承身份验证
//Hashtableahs=newHashtable();
//ArrayListlist=newArrayList();
//foreach(stringainvdEntry.Properties.PropertyNames)
//{
//list.Add(a);
//ahs.Add(a,vdEntry.Properties[a].Value);
//}
mitChanges();
//启动ASPnet_iis.exe程序
stringfileName=Environment.GetEnvironmentVariable("windir")+@"Frameworkv2.0.50727ASPnet_regiis.exe";
ProcessStartInfostartInfo=newProcessStartInfo(fileName);
//处理目录路径
stringpath=vdEntry.Path.ToUpper();
intindex=path.IndexOf("W3SVC");
path=path.Remove(0,index);
//启动ASPnet_iis.exe程序,刷新教本映射
startInfo.Arguments="-s"+path;
startInfo.WindowStyle=ProcessWindowStyle.Hidden;
startInfo.UseShellExecute=false;
startInfo.CreateNoWindow=true;
startInfo.RedirectStandardOutput=true;
startInfo.RedirectStandardError=true;
Processprocess=newProcess();
process.StartInfo=startInfo;
process.Start();
process.WaitForExit();
stringerrors=process.StandardError.ReadToEnd();
if(errors!=string.Empty)
...{
thrownewException(errors);
}
}
/**////<summary>
///删除一个网站。根据网站名称删除。
///</summary>
///<paramname="siteName">网站名称</param>
publicstaticvoidDeleteWebSiteByName(stringsiteName)
...{
stringsiteNum=GetWebSiteNum(siteName);
stringsiteEntPath=String.Format("IIS://{0}/w3svc/{1}",HostName,siteNum);
DirectoryEntrysiteEntry=GetDirectoryEntry(siteEntPath);
stringrootPath=String.Format("IIS://{0}/w3svc",HostName);
DirectoryEntryrootEntry=GetDirectoryEntry(rootPath);
rootEntry.Children.Remove(siteEntry);
mitChanges();
}
#endregion
Start和Stop网站的方法#regionStart和Stop网站的方法
publicstaticvoidStartWebSite(stringsiteName)
...{
stringsiteNum=GetWebSiteNum(siteName);
stringsiteEntPath=String.Format("IIS://{0}/w3svc/{1}",HostName,siteNum);
DirectoryEntrysiteEntry=GetDirectoryEntry(siteEntPath);
siteEntry.Invoke("Start",newobject[]...{});
}
publicstaticvoidStopWebSite(stringsiteName)
...{
stringsiteNum=GetWebSiteNum(siteName);
stringsiteEntPath=String.Format("IIS://{0}/w3svc/{1}",HostName,siteNum);
DirectoryEntrysiteEntry=GetDirectoryEntry(siteEntPath);
siteEntry.Invoke("Stop",newobject[]...{});
}
#endregion
确认网站是否相同#region确认网站是否相同
/**////<summary>
///确定一个新的网站与现有的网站没有相同的。
///这样防止将非法的数据存放到IIS里面去
///</summary>
///<paramname="bindStr">网站邦定信息</param>
///<returns>真为可以创建,假为不可以创建</returns>
publicstaticboolEnsureNewSiteEnavaible(stringbindStr)
...{
stringentPath=String.Format("IIS://{0}/w3svc",HostName);
DirectoryEntryent=GetDirectoryEntry(entPath);
foreach(DirectoryEntrychildinent.Children)
...{
if(child.SchemaClassName=="IIsWebServer")
...{
if(child.Properties["ServerBindings"].Value!=null)
...{
if(child.Properties["ServerBindings"].Value.ToString()==bindStr)
...{
returnfalse;
}
}
}
}
returntrue;
}
#endregion
获取一个网站编号的方法#region获取一个网站编号的方法
/**////<summary>
///获取一个网站的编号。根据网站的ServerBindings或者ServerComment来确定网站编号
///</summary>
///<paramname="siteName"></param>
///<returns>返回网站的编号</returns>
///<exceptioncref="NotFoundWebSiteException">表示没有找到网站</exception>
publicstaticstringGetWebSiteNum(stringsiteName)
...{
Regexregex=newRegex(siteName);
stringtmpStr;
stringentPath=String.Format("IIS://{0}/w3svc",HostName);
DirectoryEntryent=GetDirectoryEntry(entPath);
foreach(DirectoryEntrychildinent.Children)
...{
if(child.SchemaClassName=="IIsWebServer")
...{
if(child.Properties["ServerBindings"].Value!=null)
...{
tmpStr=child.Properties["ServerBindings"].Value.ToString();
if(regex.Match(tmpStr).Success)
...{
returnchild.Name;
}
}
if(child.Properties["ServerComment"].Value!=null)
...{
tmpStr=child.Properties["ServerComment"].Value.ToString();
if(regex.Match(tmpStr).Success)
...{
returnchild.Name;
}
}
}
}
thrownewException("没有找到我们想要的站点"+siteName);
}
#endregion
获取新网站id的方法#region获取新网站id的方法
/**////<summary>
///获取网站系统里面可以使用的最小的ID。
///这是因为每个网站都需要有一个唯一的编号,而且这个编号越小越好。
///这里面的算法经过了测试是没有问题的。
///</summary>
///<returns>最小的id</returns>
publicstaticstringGetNewWebSiteID()
...{
ArrayListlist=newArrayList();
stringtmpStr;
stringentPath=String.Format("IIS://{0}/w3svc",HostName);
DirectoryEntryent=GetDirectoryEntry(entPath);
foreach(DirectoryEntrychildinent.Children)
...{
if(child.SchemaClassName=="IIsWebServer")
...{
tmpStr=child.Name.ToString();
list.Add(Convert.ToInt32(tmpStr));
}
}
list.Sort();
inti=1;
foreach(intjinlist)
...{
if(i==j)
...{
i++;
}
}
returni.ToString();
}
#endregion
}
新网站信息结构体#region新网站信息结构体
publicstructNewWebSiteInfo
...{
privatestringhostIP;//TheHostsIPAddress
privatestringportNum;//TheNewWebSitesPort.generallyis"80"
privatestringdescOfWebSite;//网站表示。一般为网站的网站名。例如""
privatestringcommentOfWebSite;//网站注释。一般也为网站的网站名。
privatestringwebPath;//网站的主目录。例如"e: mp"
publicNewWebSiteInfo(stringhostIP,stringportNum,stringdescOfWebSite,stringcommentOfWebSite,stringwebPath)
...{
this.hostIP=hostIP;
this.portNum=portNum;
this.descOfWebSite=descOfWebSite;
mentOfWebSite=commentOfWebSite;
this.webPath=webPath;
}
publicstringBindString
...{
get
...{
returnString.Format("{0}:{1}:{2}",hostIP,portNum,descOfWebSite);
}
}
publicstringCommentOfWebSite
...{
get
...{
returncommentOfWebSite;
}
}
publicstringWebPath
...{
get
...{
returnwebPath;
}
}
}
#endregion
}
最后重载的InStall函数如:
publicoverridevoidInstall(IDictionarystateSaver)
...{
//数据库安装程序入口
_saPassword=this.Context.Parameters["pwd"];
_dataBaseName=this.Context.Parameters["dbname"];
_targetPath=this.Context.Parameters["targetdir"];
_servername=this.Context.Parameters["server"];
_username=this.Context.Parameters["user"];
iis=this.Context.Parameters["iis"];
port=this.Context.Parameters["port"];
//添加数据库
AddDBTable();
//注册新站点
Wuhy.ToolBox.NewWebSiteInfositeInfo=newWuhy.ToolBox.NewWebSiteInfo(string.Empty,port,"","VideoMeeting",_targetPath);
Wuhy.ToolBox.IISAdminLib.HostName=iis;
Wuhy.ToolBox.IISAdminLib.UserName=null;
Wuhy.ToolBox.IISAdminLib.CreateNewWebSite(siteInfo);
Wuhy.ToolBox.IISAdminLib.StartWebSite(siteInfo.BindString);
//修改Web.Config文件
if(!WriteWebConfig())
...{
thrownewApplicationException("设置数据库连接字符串时出现错误");
}
}