以编程方式启动和停止IIS Express

Mik*_*ike 56 c# com iis com-interop iis-express

我正在尝试在C#中构建一个小应用程序,它应该启动/停止IIS Express工作进程.为此,我想使用MSDN上记录的官方"IIS Express API":http://msdn.microsoft.com/en-us/library/gg418415.aspx

据我所知,API仅(仅)基于COM接口.为了使用这个COM接口,我通过Add Reference - > COM - >"IIS Installed Versions Manager Interface"在VS2010中添加了对COM库的引用:

到目前为止一切都很好,但下一步是什么?有一个IIISExprProcessUtility可用的接口,包括启动/停止IIS进程的两个"方法".我是否必须编写一个实现此接口的类?

public class test : IISVersionManagerLibrary.IIISExprProcessUtility
{
    public string ConstructCommandLine(string bstrSite, string bstrApplication, string bstrApplicationPool, string bstrConfigPath)
    {
        throw new NotImplementedException();
    }

    public uint GetRunningProcessForSite(string bstrSite, string bstrApplication, string bstrApplicationPool, string bstrConfigPath)
    {
        throw new NotImplementedException();
    }

    public void StopProcess(uint dwPid)
    {
        throw new NotImplementedException();
    }
} 
Run Code Online (Sandbox Code Playgroud)

如您所见,我不是一名专业开发人员.有人能指出我正确的方向.任何帮助是极大的赞赏.

更新1: 根据建议,我尝试了下面的代码,但遗憾的是它不起作用:

替代文字 好的,它可以实例化但我看不到如何使用这个对象...

替代文字

替代文字

IISVersionManagerLibrary.IIISExpressProcessUtility test3 = (IISVersionManagerLibrary.IIISExpressProcessUtility) Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("5A081F08-E4FA-45CC-A8EA-5C8A7B51727C")));

Exception: Retrieving the COM class factory for component with CLSID {5A081F08-E4FA-45CC-A8EA-5C8A7B51727C} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
Run Code Online (Sandbox Code Playgroud)

Har*_*wok 59

我试图做类似的事情.我得出结论,微软提供的COM库是不完整的.我不使用它,因为该文档提到"注意:本主题是预发布文档,在将来的版本中可能会有所变化".

所以,我决定看看IISExpressTray.exe正在做什么.它似乎在做类似的事情.

我反汇编IISExpressTray.dll,发现列出所有IISexpress进程并停止IISexpress进程没有魔力.

它不会调用该COM库.它不会从注册表中查找任何内容.

所以,我最终的解决方案非常简单.要启动IIS express进程,我只需使用Process.Start()并传入我需要的所有参数.

为了停止IIS表达过程,我使用反射器从IISExpressTray.dll复制了代码.我看到它只是向目标IISExpress进程发送WM_QUIT消息.

这是我编写的用于启动和停止IIS表达过程的类.希望这可以帮助别人.

class IISExpress
{
    internal class NativeMethods
    {
        // Methods
        [DllImport("user32.dll", SetLastError = true)]
        internal static extern IntPtr GetTopWindow(IntPtr hWnd);
        [DllImport("user32.dll", SetLastError = true)]
        internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
        [DllImport("user32.dll", SetLastError = true)]
        internal static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId);
        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    }

    public static void SendStopMessageToProcess(int PID)
    {
        try
        {
            for (IntPtr ptr = NativeMethods.GetTopWindow(IntPtr.Zero); ptr != IntPtr.Zero; ptr = NativeMethods.GetWindow(ptr, 2))
            {
                uint num;
                NativeMethods.GetWindowThreadProcessId(ptr, out num);
                if (PID == num)
                {
                    HandleRef hWnd = new HandleRef(null, ptr);
                    NativeMethods.PostMessage(hWnd, 0x12, IntPtr.Zero, IntPtr.Zero);
                    return;
                }
            }
        }
        catch (ArgumentException)
        {
        }
    }

    const string IIS_EXPRESS = @"C:\Program Files\IIS Express\iisexpress.exe";
    const string CONFIG = "config";
    const string SITE = "site";
    const string APP_POOL = "apppool";

    Process process;

    IISExpress(string config, string site, string apppool)
    {
        Config = config;
        Site = site;
        AppPool = apppool;

        StringBuilder arguments = new StringBuilder();
        if (!string.IsNullOrEmpty(Config))
            arguments.AppendFormat("/{0}:{1} ", CONFIG, Config);

        if (!string.IsNullOrEmpty(Site))
            arguments.AppendFormat("/{0}:{1} ", SITE, Site);

        if (!string.IsNullOrEmpty(AppPool))
            arguments.AppendFormat("/{0}:{1} ", APP_POOL, AppPool);

        process = Process.Start(new ProcessStartInfo()
        {
            FileName = IIS_EXPRESS,
            Arguments = arguments.ToString(),
            RedirectStandardOutput = true,
            UseShellExecute = false
        });
    }

    public string Config { get; protected set; }
    public string Site { get; protected set; }
    public string AppPool { get; protected set; }

    public static IISExpress Start(string config, string site, string apppool)
    {
        return new IISExpress(config, site, apppool);
    }

    public void Stop()
    {
        SendStopMessageToProcess(process.Id);
        process.Close();
    }
}
Run Code Online (Sandbox Code Playgroud)

我不需要列出所有现有的IIS express进程.如果你需要它,从我在反射器中看到的,IISExpressTray.dll所做的就是调用Process.GetProcessByName("iisexpress", ".")

要使用我提供的类,这是我用来测试它的示例程序.

class Program
{

    static void Main(string[] args)
    {
        Console.Out.WriteLine("Launching IIS Express...");
        IISExpress iis1 = IISExpress.Start(
            @"C:\Users\Administrator\Documents\IISExpress\config\applicationhost.config",
            @"WebSite1(1)",
            @"Clr4IntegratedAppPool");

        IISExpress iis2 = IISExpress.Start(
            @"C:\Users\Administrator\Documents\IISExpress\config\applicationhost2.config",
            @"WebSite1(1)",
            @"Clr4IntegratedAppPool");

        Console.Out.WriteLine("Press ENTER to kill");
        Console.In.ReadLine();

        iis1.Stop();
        iis2.Stop();
    }
}
Run Code Online (Sandbox Code Playgroud)

这可能不是您问题的答案,但我认为在您的问题中有趣的人可能会发现我的工作很有用.随意改进代码.您可能希望增强一些地方.

  1. 您可以修复我的代码以从注册表中读取,而不是对iisexpress.exe位置进行硬编码.
  2. 我没有包含iisexpress.exe支持的所有参数
  3. 我没有做错误处理.因此,如果IISExpress进程由于某些原因(例如使用端口)而无法启动,我不知道.我认为解决它的最简单方法是监视StandardError流并在从StandardError流中获取任何内容时抛出异常

  • 好的,我已经尝试过了,效果很好.再次感谢 :-) (3认同)
  • 哇!非常感谢您的详细解答!我想只要MSDN上没有完整/正确的COM文档,这似乎是完美的解决方案.我一回到PC就试试吧. (2认同)

Seo*_*ong 13

虽然为时已晚,但我会回答这个问题.

IISVersionManagerLibrary.IISVersionManager mgr = new IISVersionManagerLibrary.IISVersionManagerClass();
IISVersionManagerLibrary.IIISVersion ver = mgr.GetVersionObject("7.5", IISVersionManagerLibrary.IIS_PRODUCT_TYPE.IIS_PRODUCT_EXPRESS);

object obj1 = ver.GetPropertyValue("expressProcessHelper");

IISVersionManagerLibrary.IIISExpressProcessUtility util = obj1 as IISVersionManagerLibrary.IIISExpressProcessUtility;
Run Code Online (Sandbox Code Playgroud)

而已.然后,您可以在util对象上调用StopProcess方法.

但是,您必须得到Microsoft的通知.

"Version Manager API(IIS Express); http://msdn.microsoft.com/en-us/library/gg418429(v=VS.90).aspx

注意:IIS Version Manager API支持IIS Express基础结构,不应在代码中直接使用. "

  • 谢谢!这段代码对我来说运行良好,但我想我对接下来要做什么有点迷茫。我怎样才能弄清楚它在哪个端口上运行?我如何使用它来启动我正在开发的网站? (2认同)
  • 永远不会太迟! (2认同)

Mha*_*lin 7

此实现适用于以编程方式启动/停止IIS Express,可以在测试中使用.

public class IisExpress : IDisposable
{
    private Boolean _isDisposed;

    private Process _process;

    public void Dispose()
    {
        Dispose(true);
    }

    public void Start(String directoryPath, Int32 port)
    {
        var iisExpressPath = DetermineIisExpressPath();
        var arguments = String.Format(
            CultureInfo.InvariantCulture, "/path:\"{0}\" /port:{1}", directoryPath, port);

        var info = new ProcessStartInfo(iisExpressPath)
                                    {
                                        WindowStyle = ProcessWindowStyle.Normal,
                                        ErrorDialog = true,
                                        LoadUserProfile = true,
                                        CreateNoWindow = false,
                                        UseShellExecute = false,
                                        Arguments = arguments
                                    };

        var startThread = new Thread(() => StartIisExpress(info))
                                 {
                                     IsBackground = true
                                 };

        startThread.Start();
    }

    protected virtual void Dispose(Boolean disposing)
    {
        if (_isDisposed)
        {
            return;
        }

        if (disposing)
        {
            if (_process.HasExited == false)
            {
                _process.Kill();
            }

            _process.Dispose();
        }

        _isDisposed = true;
    }

    private static String DetermineIisExpressPath()
    {
        String iisExpressPath;

        iisExpressPath = Environment.GetFolderPath(Environment.Is64BitOperatingSystem 
            ? Environment.SpecialFolder.ProgramFilesX86
            : Environment.SpecialFolder.ProgramFiles);

        iisExpressPath = Path.Combine(iisExpressPath, @"IIS Express\iisexpress.exe");

        return iisExpressPath;
    }

    private void StartIisExpress(ProcessStartInfo info)
    {
        try
        {
            _process = Process.Start(info);

            _process.WaitForExit();
        }
        catch (Exception)
        {
            Dispose();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这很棒!我发现了一个更完整的实现[这里](https://github.com/roryprimrose/Headless/blob/9caacee22acf9b24a6880dff695fb1cfb552f5fe/Headless.IntegrationTests/IisExpress.cs). (3认同)