如何将ASP.NET MVC项目部署到IIS并后台自动运行无需浏览器启动
实现ASP.NET MVC人脸比对项目IIS部署及开机自动后台运行
我来帮你搞定这个需求,要实现项目开机自动后台运行,咱们需要完成IIS部署和后台任务自动触发两个核心步骤,下面一步步来:
第一步:把项目部署到IIS服务器
发布ASP.NET MVC项目
- 在Visual Studio里右键项目,选择「发布」,目标选「IIS、FTP等」,可以先发布到本地文件夹,再把文件复制到IIS服务器对应的目录,也可以直接配置远程发布到IIS。
- 确保发布包包含所有依赖项:比如加密工具类
Rijndael128EncryptorDAO、读取用的文本文件(CapImgLoaction.txt、location1.txt等),以及项目的配置文件。
在IIS中创建并配置网站
- 打开IIS管理器,右键「网站」→「添加网站」,填写网站名称,选择物理路径为你发布的项目文件夹,设置访问端口(比如8080)。
- 应用程序池要选对应版本的.NET Framework(比如你的项目用的是.NET 4.7.2,就选对应版本的池),并把池的启动模式设为「AlwaysRunning」,防止站点闲置回收。
- 测试访问:在浏览器输入
http://localhost:8080/FaceCompare,确认页面能正常加载。
第二步:实现开机自动后台运行(无需手动点击启动)
你的项目目前需要手动点击「Start」按钮触发FaceCompare接口,要实现后台自动运行,这里给你两种实用方案:
方案1:用Windows任务计划程序定时调用接口(无需改代码)
这是最省心的方式,不用动项目代码:
- 打开「Windows任务计划程序」,点击「创建基本任务」,设置任务名称比如「人脸比对自动执行」。
- 触发器选择「计算机启动时」,或者按你需要的频率(比如每分钟执行一次)设置重复触发。
- 操作选择「启动程序」,程序选
powershell,参数填:Invoke-WebRequest -Uri "http://localhost:8080/FaceCompare/FaceCompare" -Method Post - 最后设置任务的执行账户为有权限访问IIS和读取项目文件的账户,确保任务能正常执行。
方案2:修改项目代码,内置后台定时任务
如果不想依赖外部任务,可以把比对逻辑改成内置后台服务:
- 先把业务逻辑抽离成独立服务类,避免和控制器耦合:
public class FaceComparisonService { private readonly HttpServerUtilityBase _serverUtility; public FaceComparisonService(HttpServerUtilityBase serverUtility) { _serverUtility = serverUtility; } // 核心比对逻辑 public void RunComparison() { var inList = GetMatchInList(); var outList = GetMatchOutList(); // 这里可以添加比对后的业务处理,比如结果存储、日志记录等 } // 原FaceMatchInList方法迁移过来 public List<FaceCompareModel> GetMatchInList() { string[] filePaths = null; DateTime foldertime = DateTime.Now; string folderdatelocation = foldertime.ToString("yyyy-MM-dd"); string path = _serverUtility.MapPath("~/FolderLocation/CapImgLoaction.txt"); string FolderLocation; string myString; using (StreamReader reader = System.IO.File.OpenText(path)) { FolderLocation = reader.ReadToEnd(); string location1path = _serverUtility.MapPath("~/FolderLocation/location1.txt"); string location1; string location1String; using (StreamReader location1reader = System.IO.File.OpenText(location1path)) { location1 = location1reader.ReadToEnd(); location1String = location1.Replace("\r\n", string.Empty); } string location2path = _serverUtility.MapPath("~/FolderLocation/location2.txt"); string location2; string location2String; using (StreamReader location2reader = System.IO.File.OpenText(location2path)) { location2 = location2reader.ReadToEnd(); location2String = location2.Replace("\r\n", string.Empty); } Rijndael128EncryptorDAO rnDAO = new Rijndael128EncryptorDAO(); string decrypt = rnDAO.AES_decrypt(FolderLocation, location1String, location2String); myString = decrypt.Replace("\r\n", string.Empty); } string INIPAddressPath = _serverUtility.MapPath("~/FolderLocation/INCameraIPAddress.txt"); string INCameraIPAddress; string INCameraIPAddressmyString; using (StreamReader reader = System.IO.File.OpenText(INIPAddressPath)) { INCameraIPAddress = reader.ReadToEnd(); string location1path = _serverUtility.MapPath("~/FolderLocation/location1.txt"); string location1; string location1String; using (StreamReader location1reader = System.IO.File.OpenText(location1path)) { location1 = location1reader.ReadToEnd(); location1String = location1.Replace("\r\n", string.Empty); } string location2path = _serverUtility.MapPath("~/FolderLocation/location2.txt"); string location2; string location2String; using (StreamReader location2reader = System.IO.File.OpenText(location2path)) { location2 = location2reader.ReadToEnd(); location2String = location2.Replace("\r\n", string.Empty); } Rijndael128EncryptorDAO rnDAO = new Rijndael128EncryptorDAO(); string decrypt = rnDAO.AES_decrypt(INCameraIPAddress, location1String, location2String); INCameraIPAddressmyString = decrypt.Replace("\r\n", string.Empty); } try { filePaths = Directory.GetFiles(myString + "\\" + folderdatelocation + "\\" + INCameraIPAddressmyString + "\\" + "CompOk", "*_SRC.JPG*"); } catch (Exception ex) { // 建议添加异常日志,方便排查问题 // Logger.Error("读取图片路径失败", ex); } // 补充返回逻辑,根据实际业务返回数据 return new List<FaceCompareModel>(); } // 原FaceMatchOutList方法迁移过来 public List<FaceCompareModel> GetMatchOutList() { // 你的业务逻辑实现 return new List<FaceCompareModel>(); } }
- 在项目启动时初始化定时任务,修改
Global.asax:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); // 初始化定时任务,比如每分钟执行一次比对 var timer = new System.Timers.Timer(60000); timer.Elapsed += (sender, e) => { var comparisonService = new FaceComparisonService(Server); comparisonService.RunComparison(); }; timer.AutoReset = true; timer.Start(); }
- 这样部署后,只要IIS站点启动,后台任务就会自动运行,开机后IIS会自动拉起站点,无需手动操作。
关键注意事项
- 确保项目中读取的文本文件路径正确,部署后
Server.MapPath指向的是IIS站点的物理路径,要保证这些文件存在且权限配置正确(给IIS应用程序池账户读取权限)。 - 如果用任务计划,要测试命令是否能正常调用接口,避免权限不足的问题。
- 建议给业务逻辑添加异常捕获和日志记录,方便后续排查问题。
附上你提供的代码格式化版本,方便参考:
控制器代码
namespace FaceCompare.Controllers { public class FaceCompareController : Controller { // GET: FaceCompare public ActionResult Index() { var inlist = FaceMatchInList(); var outlist = FaceMatchOutList(); return View(); } [HttpPost] public ActionResult FaceCompare() { var inlist = FaceMatchInList(); var outlist = FaceMatchOutList(); return View(); } public List<FaceCompareModel> FaceMatchInList() { string[] filePaths = null; DateTime foldertime = DateTime.Now; string folderdatelocation = foldertime.ToString("yyyy-MM-dd"); string path = Server.MapPath("~/FolderLocation/CapImgLoaction.txt"); string FolderLocation; string myString; using (StreamReader reader = System.IO.File.OpenText(path)) { FolderLocation = reader.ReadToEnd(); string location1path = Server.MapPath("~/FolderLocation/location1.txt"); string location1; string location1String; using (StreamReader location1reader = System.IO.File.OpenText(location1path)) { location1 = location1reader.ReadToEnd(); location1String = location1.Replace("\r\n", string.Empty); } string location2path = Server.MapPath("~/FolderLocation/location2.txt"); string location2; string location2String; using (StreamReader location2reader = System.IO.File.OpenText(location2path)) { location2 = location2reader.ReadToEnd(); location2String = location2.Replace("\r\n", string.Empty); } Rijndael128EncryptorDAO rnDAO = new Rijndael128EncryptorDAO(); string decrypt = rnDAO.AES_decrypt(FolderLocation, location1String, location2String); myString = decrypt.Replace("\r\n", string.Empty); } string INIPAddressPath = Server.MapPath("~/FolderLocation/INCameraIPAddress.txt"); string INCameraIPAddress; string INCameraIPAddressmyString; using (StreamReader reader = System.IO.File.OpenText(INIPAddressPath)) { INCameraIPAddress = reader.ReadToEnd(); string location1path = Server.MapPath("~/FolderLocation/location1.txt"); string location1; string location1String; using (StreamReader location1reader = System.IO.File.OpenText(location1path)) { location1 = location1reader.ReadToEnd(); location1String = location1.Replace("\r\n", string.Empty); } string location2path = Server.MapPath("~/FolderLocation/location2.txt"); string location2; string location2String; using (StreamReader location2reader = System.IO.File.OpenText(location2path)) { location2 = location2reader.ReadToEnd(); location2String = location2.Replace("\r\n", string.Empty); } Rijndael128EncryptorDAO rnDAO = new Rijndael128EncryptorDAO(); string decrypt = rnDAO.AES_decrypt(INCameraIPAddress, location1String, location2String); INCameraIPAddressmyString = decrypt.Replace("\r\n", string.Empty); } try { filePaths = Directory.GetFiles(myString + "\\" + folderdatelocation + "\\" + INCameraIPAddressmyString + "\\" + "CompOk", "*_SRC.JPG*"); } catch (Exception ex) { // 建议添加异常处理 } // 需补充返回List<FaceCompareModel>的逻辑 return new List<FaceCompareModel>(); } public List<FaceCompareModel> FaceMatchOutList() { // 补充业务逻辑 return new List<FaceCompareModel>(); } } }
视图代码
@using (Html.BeginForm("FaceCompare", "FaceCompare", FormMethod.Post, new { onsubmit = "showLoader(this);" })) { <div class="form-group"> <div class="col-md-4"> </div> <div class="col-md-4 col-lg-4 col-sm-4"> <h2 class="text-center">Image To Compare</h2> <table border="1" width=100%> <thead> <tr> <th class="text-center">Sl. no.</th> <th class="text-center">Name</th> <th class="text-center">Images</th> </tr> </thead> <tbody> </tbody> </table> <div class="text-center" style="margin-top:10px; margin-bottom:10px;"> <input type="submit" value="Start" /> </div> </div> <div class="col-md-4"> </div> </div> }
内容的提问来源于stack exchange,提问作者Inversemaha




