web打包和IIS配置
关于打包web项目很简单,但是要顺便配置IIS,做到安装完后就能用的话,要重写Installer类的Install方法.
网上找了很多套方案,结果都有问题,东拼西凑折腾好几天终于做出来了.
准备:
1,web发布文件(里面可以放其他东西,不影响,也可以是web发布的文件夹)
2,vs(我是2017,也不影响)
3,要能创建visual studio installer项目,没有这个要在拓展和更新搜索下载,如下图:
废话不多说,开始吧
一:新建web setup安装项目,可以和其他项目不在同目录下,或者干脆新建个解决方案:
二:右键解决方案>添加>现有网站>选择web发布文件夹
三:新建类库(名字随意)>在类库下新建安装程序类
注意:记得是安装程序类,不是普通的类,
打开类后有单击此处切换到代码视图这个东东,并且自动继承安装类
[RunInstaller(true)]
public partial class WebCardInstaller : Installer
配置IIS就在重写这个类的方法里:
public override void Install(IDictionary stateSaver)
四:右键安装项目>视图>用户界面>右键Start>添加对话框>选择你要的界面
常用的就是文本框AB,一个用来输入数据库配置,一个IIS配置,一个许可条款(不要也行),
注意:自己添加的框要拖拽到欢迎使用和安装地址之间,要不会有波浪线警告.
分别在文本框AB的属性上设置参数,由于我没在这装数据库,所以就贴IIS的参数吧
注意了:property这个属性很重要,代码区要根据这个读取value里的值和拼接关键字属性字符串,默认全是大写的.
如果只要3个参数,把其中一个visible设为false即可.
数据库类似的,传入必要的服务器名,账号,密码,数据库名即可.
五:右键安装项目>视图>文件系统>右键web安装文件夹>添加>项目输出>选择web发布文件夹和刚刚添加的类库
添加类库和发布文件选的方式也不同,还可以直接把发布文件夹整个拖进去,这样只要加类库输出,但是不建议这样,因为拖进去的文件不能操作,删除替换全都不行.
在文件系统的属性界面可以设置IIS的参数,比如默认起始页,读写权限,访问脚本权限等,也可以用代码来设置.
六:右键安装项目>视图>启动条件>在IIS Condition的属性上,把启动版本改下
七:右键安装项目>视图>自定义操作,在install(安装)再右键添加操作
添加在步骤五添加的主输出(类库)
注意:箭头指向的那个add output可以指定到web项目,据说这样就不用发布文件了,打包的时候会自动提取发布文件,但是我试过,直接把dll文件给打包了...
而且这样搞需要把安装项目和web项目放在同个解决方案.
添加后:
uninstall是卸载,也可以这样搞,但是感觉默认的卸载够用了,就不加了.
关键的来了,还记得在步骤四里设置的属性参数吗?在这需要用到它们来拼接关键字了,格式如下:
/iis=[IISSERVER] /ip=[IP] /port=[PORT] /isname=[ISNAME] /targetdir="[TARGETDIR]\"
中括号里大写的字符是步骤四里的property属性值,小写的是在代码中用来读取的关键字,可以看成是key.
每组关键字有个空格,最后有眼号的是IIS安装路径,眼号不能省略,最后一个是反斜杠 \
如果要装数据库,则数据库界面的属性也要加进来.
选中主输出,切换到属性,贴上上面拼接的关键字:
补充下,许可条款那个界面只要在文件系统传入一个文档,用户界面右键条款添加操作,指定文件系统里的文档就行,可有可无的东西就不弄了.
现在,所有能用鼠标点的设置都做完了,下面进入重点---代码.
思路是这样:
把服务器,端口,IP,站点ID等设置成字段,这样值设置一次,参数也不用传来传去弄的眼花.
必要的操作有:判断网站名和端口是否存在,站点ID取最小的,创建快捷方式,记录网站信息
主方法:
Context.Parameters就是获取用户输入的参数,
字段:
private string iis;//服务器
private string port;//端口
private string serverID;//站点ID
private string ip;//IP
private DirectoryEntry _iisServer;
private ManagementScope _scope;
private ConnectionOptions _connection;
/// <summary>
/// 安装设置
/// </summary>
/// <param name="stateSaver"></param>
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
/*/iis=[IISSERVER] /ip=[IP] /port=[PORT] /isname=[ISNAME] /targetdir="[TARGETDIR]\"*/
ip = Context.Parameters["ip"].ToString();
iis = Context.Parameters["iis"].ToString();
port = Context.Parameters["port"].ToString();
string defaultVrootPath = Context.Parameters["targetdir"];
serverID = GetNextOpenID().ToString();//获得一个最小ServerID
string serverComment = Context.Parameters["isname"].ToString();//网站名
if (IsExistSitePort())//判断端口重复
{
throw new Exception("端口号已被占用!");
}
Connect();// 连接IIS服务器
if (defaultVrootPath.EndsWith(@"\"))//检查是否\结尾
{
defaultVrootPath = defaultVrootPath.Substring(0, defaultVrootPath.Length - 1);
}
string sReturn = CreateWebSite(serverComment, defaultVrootPath);
string _path = defaultVrootPath + @"\App_Data\";
SaveLog(_path, serverID, "serverID");//保存网站信息
SaveLog(_path, port, "port");//保存网站信息
SaveLog(_path, sReturn, "result");//保存网站信息
CreateShortcut(port);//创建快捷方式
}
获取最小网站ID是获取IIS虚拟目录下的所有站点ID,一个个比大小,最后返回一个最大的加1
/// <summary> /// 获得一个最小ServerID /// </summary> /// <returns></returns> private int GetNextOpenID() { //DirectoryEntry iisComputer = new DirectoryEntry("IIS://localhost/w3svc"); DirectoryEntry iisComputer = new DirectoryEntry("IIS://" + iis + "/w3svc"); int nextID = 0, name = 0; string sname = ""; foreach (DirectoryEntry iisWebServer in iisComputer.Children) { sname = iisWebServer.Name; try { name = int.Parse(sname); if (name > nextID) { nextID = name; } } catch { } } return ++nextID; }
根据用户输入的端口直接测试连接来判断是否已有
/// <summary>
/// 端口号是否重复
/// </summary>
/// <returns></returns>
private bool IsExistSitePort()
{
Process p = new Process();
p.StartInfo = new ProcessStartInfo("netstat", "-a");
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string result = p.StandardOutput.ReadToEnd();
if (result.IndexOf(Environment.MachineName.ToLower() + ":" + port) >= 0)
{
//端口被占用
return true;
}
else
{
return false;
}
}
添加网站时,主要设置网站的属性,注意大小写
/// <summary>
/// 添加网站
/// </summary>
/// <param name="serverComment"></param>
/// <param name="defaultVrootPath"></param>
/// <param name="HostName"></param>
/// <returns></returns>
private string CreateWebSite(string serverComment, string defaultVrootPath)
{
try
{
ManagementObject oW3SVC = new ManagementObject(_scope, new ManagementPath(@"IIsWebService='W3SVC'"), null);
if (IsWebSiteExists(serverID))//判断同名网站
{
throw new Exception("已有同名网站");
}
ManagementBaseObject inputParameters = oW3SVC.GetMethodParameters("CreateNewSite");
ManagementBaseObject[] serverBinding = new ManagementBaseObject[1];
serverBinding[0] = CreateServerBinding();//绑定IP地址和端口
inputParameters["ServerComment"] = serverComment;//网站名
inputParameters["ServerBindings"] = serverBinding;//网站绑定的数据(IP和端口)
inputParameters["PathOfRootVirtualDir"] = defaultVrootPath;//安装路径
inputParameters["ServerId"] = serverID;//网站ID
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);
// 网站属性设置
DirectoryEntry virtualDirectory = (DirectoryEntry)webSite.InvokeMethod("Create", new object[] { "IIsWebVirtualDir", "Root" });
virtualDirectory.CommitChanges();//保存
virtualDirectory.Properties["AccessExecute"][0] = false;//可执行文件
virtualDirectory.Properties["AccessScript"][0] = true;// 可访问脚本
virtualDirectory.Properties["EnableDefaultDoc"][0] = true;
virtualDirectory.Properties["DefaultDoc"][0] = "Login.aspx";//默认开打文件
virtualDirectory.CommitChanges();//保存
virtualDirectory.Properties["AccessRead"][0] = true;// 读取
virtualDirectory.Properties["AccessWrite"][0] = true;// 写入
virtualDirectory.Properties["ContentIndexed"][0] = true;// 资源索引
virtualDirectory.Properties["AppIsolated"][0] = 2;// 值 0 表示应用程序在进程内运行,值 1 表示进程外,值 2 表示进程池
virtualDirectory.CommitChanges();//保存
virtualDirectory.Invoke("AppCreate", new object[] { 2 });
virtualDirectory.CommitChanges();//保存
return (string)outParameter.Properties["ReturnValue"].Value;
}
catch (Exception ex)
{
return ex.Message;
}
}
/// <summary>
/// 判断网站是否已经存在
/// </summary>
/// <param name="serverID"></param>
/// <returns></returns>
private 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;
}
}
网站绑定注意了,
Hostname是站点名称,一般放空
/// <summary>
/// 网站绑定,绑定IP地址和端口
/// </summary>
/// <param name="HostName"></param>
/// <returns></returns>
private ManagementObject CreateServerBinding()
{
try
{
ManagementClass classBinding = new ManagementClass(_scope, new ManagementPath("ServerBinding"), null);
ManagementObject serverBinding = classBinding.CreateInstance();
serverBinding.Properties["Hostname"].Value = "";
serverBinding.Properties["IP"].Value = ip;
serverBinding.Properties["Port"].Value = port;
serverBinding.Put();//提交更改
return serverBinding;
}
catch
{
return null;
}
}
最后是创建快捷方式和保存网站信息:
/// <summary>
/// 创建快捷方式
/// </summary>
/// <param name="Port">端口</param>
private void CreateShortcut(string Port)
{
//获取软件安装的物理目录
//string urlpath = this.Context.Parameters["targetdir"];
if (Port != "80")
{
string URL = "http://" + ip + ":" + Port + "/Login.aspx";
string DeskPhath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
//创建URL快捷方式(文件)
DeskPhath = DeskPhath + "\\" + "你的名字.url";
StreamWriter sw = new StreamWriter(File.Open(DeskPhath, FileMode.Create, FileAccess.ReadWrite));
sw.WriteLine("[DEFAULT]");
sw.WriteLine("BASEURL=" + URL);
sw.WriteLine("[InternetShortcut]");
sw.WriteLine("URL=" + URL);
//sw.WriteLine("IconFile=" + SetupPath + "\\park.ico");
// sw.WriteLine("IconIndex=0");
sw.Flush();
sw.Close();
}
}
/// <summary>
/// 保存网站信息
/// </summary>
/// <param name="path"></param>
private void SaveLog(string path, string data, string name)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
path = path + name + ".txt";
using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(data);
sw.Flush();
sw.Close();
}
}
问我为什么不用xml?因为TXT文件代码更少
最后右键安装项目,重新生成,然后在debug下会生成2安装文件,双击就能装了.
补充下:
因为项目需要,所以把安装数据库的功能搬出来了,就说下我的思路吧.
用winform来安装,
根据用户输入的数据生成SQL创建数据库语句,
把语句连接到数据库执行下就行,
如果创建数据库同时还要创建表和存储过程什么的,建议把数据库内容做成.sql格式的脚本,
先建库,接着use 数据库 go,再执行脚本,
注意:脚本里不能有建库语句,因为数据库执行是一次性加载,一次性执行的,而且GO必须单独一行,所以构建语句要注意.
安装数据库程序建议做成在网站根目录下执行,脚本也放那,这样可以同时读取脚本和web.config文件(读取当前目录文件).
创建好数据库后还要改web.config文件,用xml来操作,这样网站就和数据库对接了.
补个坑,创建安装项目的时候默认启动条件会选本机的最高版本,在没有安装相应版本的电脑安装会报错,我在这坑里趟了半天,差点怀疑人生,跟改IIS一样
右键安装项目,视图,启动条件,改.NET版本
end.
推荐阅读
-
web打包和IIS配置
-
Spring Boot 将第三方依赖和配置文件打包在jar外部并引用
-
整理 IIS7配置web.config
-
VS中利用ASP.net做网站,使用Gridview显示数据列表,用IIS发布后,在IE浏览器和360浏览器中看到样式不一样求高手指教!_html/css_WEB-ITnose
-
IIS环境下快速安装、配置和调试PHP520
-
IIS环境下快速安装、配置和调试PHP5.2.0_php基础
-
Parcel.js和Vue 2.x 极速零配置打包体验示例
-
VS中利用ASP.net做网站,使用Gridview显示数据列表,用IIS发布后,在IE浏览器和360浏览器中看到样式不一样求高手指教!_html/css_WEB-ITnose
-
Windows环境配置jenkins打包Android项目和vue项目
-
IIS环境下快速安装、配置和调试PHP5.2.0_php基础