如何在TeamCity内启动和停止IIS Express?

如何在TeamCity内启动和停止IIS Express?,teamcity,iis-express,Teamcity,Iis Express,我很可能在做一些奇怪的事情,但我不确定。我正在尝试在安装了IIS Express的windows xp计算机上配置TeamCity生成代理。我想创建一个启动IIS Express的生成步骤,然后创建另一个停止它的生成步骤 我可以创建一个命令行生成步骤,以使用类似于以下命令的命令启动IIS Express实例: "C:\Program Files\IIS Express\iisexpress.exe" /path:%1\src\Web /port:80 /systray:false 这将启动服务

我很可能在做一些奇怪的事情,但我不确定。我正在尝试在安装了IIS Express的windows xp计算机上配置TeamCity生成代理。我想创建一个启动IIS Express的生成步骤,然后创建另一个停止它的生成步骤

我可以创建一个命令行生成步骤,以使用类似于以下命令的命令启动IIS Express实例:

"C:\Program Files\IIS Express\iisexpress.exe" /path:%1\src\Web /port:80 /systray:false
这将启动服务器,但我的日志显示“输入'Q'以停止IIS Express”,该步骤将等待。我不想让构建步骤等待。我希望构建进入下一步


有人对此有什么想法吗?

编写一个简单的包装器可执行文件或批处理文件,该文件采用与iisexpress.exe完全相同的参数,该包装器可以使用给定的命令行参数启动iisexpress.exe并立即返回。

编写一个简单的包装器可执行文件或批处理文件,该文件采用与iisexpress.exe完全相同的参数该包装器可以使用给定的命令行参数启动iisexpress.exe并立即返回。

答案比编写简单的批处理文件更复杂,因为在大多数情况下,您需要等待IIS express启动,然后执行某些功能,然后再次停止IIS express进程

最后一个阶段对于避免启动具有多个版本的重复站点非常重要,这将导致错误和误导性结果。我们还需要仔细管理流程,以便“按Q退出”提示不会阻止我们的应用程序继续并执行其核心功能

下面是我为C#中的一个控制台应用程序编写的一些代码,它可以运行Phantom.JS,而且它还可以优雅地处理我们遇到错误的场景

using System;
using System.Diagnostics;
using System.Threading.Tasks;

internal class Program
{
    private static int Main(string[] args)
    {
        string iisExpressPath = args[0];
        string websitePath = args[1];
        string websitePort = args[2];
        string phantomJSPath = args[3];
        string jsControllerPath = args[4];

        var startIisTask = StartIis(iisExpressPath, websitePath, websitePort);

        Process iisexpress;
        try
        {
            iisexpress = startIisTask.Result;
        }
        catch (Exception)
        {
            Console.Write("An error occurred while starting IIS express");
            return -1;
        }

        if (iisexpress != null)
        {
            var phantomJS = new Process();
            phantomJS.StartInfo.FileName = phantomJSPath;
            phantomJS.StartInfo.Arguments = jsControllerPath;

            phantomJS.StartInfo.UseShellExecute = false;
            phantomJS.StartInfo.RedirectStandardOutput = true;

            var tcs = new TaskCompletionSource<bool>();

            phantomJS.Start();

            Task.Run(
                () =>
                {
                    string str;
                    while ((str = phantomJS.StandardOutput.ReadLine()) != null)
                    {
                        if (str == "Unable to load the address!")
                        {
                            tcs.SetException(new ArgumentException(str));
                            return;
                        }

                        Console.WriteLine(str);
                    }

                    tcs.SetResult(true);
                });

            try
            {
                var complete = tcs.Task.Result;
            }
            catch (Exception)
            {
                phantomJS.Kill();
                iisexpress.Kill();
                return -1;
            }

            iisexpress.Kill();
            return 0;
        }

        Console.Write("An error occurred while starting IIS express");
        return -1;
    }

    private static Task<Process> StartIis(string iisExpressPath, string websitePath, string websitePort)
    {
        var tcs = new TaskCompletionSource<Process>();

        var iisexpress = new Process();
        iisexpress.StartInfo.FileName = iisExpressPath;
        iisexpress.StartInfo.Arguments = string.Format("/path:{0} /port:{1}", websitePath, websitePort);
        iisexpress.StartInfo.RedirectStandardOutput = true;
        iisexpress.StartInfo.UseShellExecute = false;
        iisexpress.EnableRaisingEvents = true;

        // Implicit capture is ok here as we are capturing an object we need later.
        iisexpress.Exited += IisexpressOnExited(tcs);

        iisexpress.Start();

        Task.Run(
            () =>
            {
                string str;
                while ((str = iisexpress.StandardOutput.ReadLine()) != null)
                {
                    if (str.Contains("IIS Express is running"))
                    {
                        iisexpress.Exited -= IisexpressOnExited(tcs);
                        tcs.SetResult(iisexpress);
                    }
                }
            });

        return tcs.Task;
    }

    private static EventHandler IisexpressOnExited(TaskCompletionSource<Process> tcs)
    {
        return (sender, args) => tcs.TrySetCanceled();
    }
}
使用系统;
使用系统诊断;
使用System.Threading.Tasks;
内部课程计划
{
私有静态int Main(字符串[]args)
{
字符串iisExpressPath=args[0];
字符串websitePath=args[1];
字符串websitePort=args[2];
字符串phantomJSPath=args[3];
字符串jsControllerPath=args[4];
var startIisTask=StartIis(iisExpressPath、websitePath、websitePort);
过程iisexpress;
尝试
{
iisexpress=起始任务结果;
}
捕获(例外)
{
Write(“启动IIS express时出错”);
返回-1;
}
如果(iisexpress!=null)
{
var phantomJS=新流程();
phantomJS.StartInfo.FileName=phantomJSPath;
phantomJS.StartInfo.Arguments=jsControllerPath;
phantomJS.StartInfo.UseShellExecute=false;
phantomJS.StartInfo.RedirectStandardOutput=true;
var tcs=new TaskCompletionSource();
phantomJS.Start();
任务。运行(
() =>
{
字符串str;
而((str=phantomJS.StandardOutput.ReadLine())!=null)
{
如果(str==“无法加载地址!”)
{
SetException(新参数异常(str));
返回;
}
控制台写入线(str);
}
tcs.SetResult(真);
});
尝试
{
var complete=tcs.Task.Result;
}
捕获(例外)
{
phantomJS.Kill();
iisexpress.Kill();
返回-1;
}
iisexpress.Kill();
返回0;
}
Write(“启动IIS express时出错”);
返回-1;
}
私有静态任务开始(字符串iisExpressPath、字符串websitePath、字符串websitePort)
{
var tcs=new TaskCompletionSource();
var iisexpress=新流程();
iisexpress.StartInfo.FileName=iisExpressPath;
iisexpress.StartInfo.Arguments=string.Format(“/path:{0}/port:{1}”,websitePath,websitePort);
iisexpress.StartInfo.RedirectStandardOutput=true;
iisexpress.StartInfo.UseShellExecute=false;
iisexpress.EnableRaisingEvents=true;
//隐式捕获在这里是可以的,因为我们稍后将捕获需要的对象。
iisexpress.Exited+=IISExpressonexitted(tcs);
iisexpress.Start();
任务。运行(
() =>
{
字符串str;
而((str=iisexpress.StandardOutput.ReadLine())!=null)
{
如果(str.Contains(“IIS Express正在运行”))
{
iisexpress.Exited-=iisexpress退出(tcs);
设置结果(iisexpress);
}
}
});
返回tcs.Task;
}
私有静态事件处理程序IisexpressOnExited(TaskCompletionSource tcs)
{
return(sender,args)=>tcs.trysetconceled();
}
}
该应用程序还将通过管道将phantom.js的输出传输到它自己的控制台,以便您可以使用它运行客户端单元测试,但也可以轻松地适应可能需要托管的任何构建步骤


如果您想了解更多信息,请参阅我关于如何使用IIS express从TeamCity内部运行Jasmine单元测试的帖子:

答案比编写简单的批处理文件更复杂,因为在大多数情况下,您需要等待IIS express启动,然后执行一些功能,然后再次停止IIS express进程

最后一个阶段对于避免启动具有多个版本的重复站点非常重要,这将导致错误和误导性结果。我们还需要仔细管理流程,以便“按Q退出”提示不会阻止我们的应用程序继续并执行其核心功能

这是一些鳕鱼