Собственный хост приложения ASP.NET MVC

У меня есть полнофункциональное приложение ASP.NET MVC (состоящее из 5 сборок, .NET 4.5.1, ASP.NET MVC 5.2.2), которое отлично работает в Visual Studio (в котором используется IISExpress).

Теперь я хотел бы иметь консольное приложение, которое принимает приложение MVC и размещает его (самостоятельный хостинг).

Я пробовал с Microsoft.Owin.Host.HttpListener и Nancy.Owin, но пока я получаю 404 страницы, в моих конфигурациях отсутствует сопоставление с моим MVC-приложением.

я получил

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseNancy();
    }
}

и

    static void Main(string[] args)
    {
        StartOptions so = new StartOptions("http://localhost:9000/");
        using (WebApp.Start<Startup>(so))
        {
            Console.WriteLine("Press Enter to Exit");
            Console.ReadLine();
        }
    }

Но очевидно, что конфигурация для использования MyMvcApplication из работающего приложения MVC отсутствует. Как это сделать? Или как это сделать самостоятельно?

Ответы, которые я нашел в Интернете, относятся к более старым версиям, и я надеялся, что сегодня у меня будет более простой способ.


person ZoolWay    schedule 01.12.2014    source источник
comment
Насколько я понял сейчас, это будет невозможно до ASP.NET 5 (vNext; MVC 6), и для размещения моего приложения с Нэнси потребуется перейти с ASP.NET MVC на Нэнси (которая также может использовать механизм шаблонов Razor). Правильный?   -  person ZoolWay    schedule 01.12.2014
comment
Как и выше, вы не можете самостоятельно размещать MVC, а Nancy — это совершенно другая среда веб-разработки по сравнению с MVC — это не альтернативный способ размещения MVC, и вы не можете просто смешать их вместе.   -  person Steven Robbins    schedule 01.12.2014
comment
Тогда возникает вопрос, есть ли что-то еще для самостоятельного размещения, или MVC5 просто требует хостинга IIS без каких-либо обходных путей.   -  person ZoolWay    schedule 01.12.2014
comment
Последний в текущей версии.   -  person Steven Robbins    schedule 01.12.2014
comment
Приложения Нэнси можно размещать самостоятельно, и да, вы можете использовать Razor с Нэнси. Посетите сайт www.nancyfx.org, если хотите узнать больше о Нэнси.   -  person Christian Horsdal    schedule 03.12.2014


Ответы (1)


Поскольку ASP.NET vNext еще недоступен, а мое приложение использует MVC5, мне пришлось бы полностью перенести приложение MVC на Nancy или что-то подобное. MVC5 слишком зависит от IIS.

Чтобы решить эту проблему, я выбрал промежуточное решение, поскольку производительность не является проблемой:

Мое консольное приложение создает файл конфигурации IIS и запускает IIS Express:

        // start IIS
        bool systray = Debugger.IsAttached;
        ProcessStartInfo psi = new ProcessStartInfo(iisExecutable, String.Format("/config:\"{0}\" /site:Ecm2.Web /trace:info /systray:{1}", configFile, systray));
        psi.UseShellExecute = false;
        psi.RedirectStandardInput = false;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardError = true;
        psi.CreateNoWindow = true;

        if (this.iisProcess != null) throw new NotSupportedException("Multiple starts not supported");
        this.iisProcess = new Process();
        this.iisProcess.StartInfo = psi;
        this.iisProcess.ErrorDataReceived += OnErrorDataReceived;
        this.iisProcess.OutputDataReceived += OnOutputDataReceived;
        this.iisProcess.Start();
        this.iisProcess.BeginErrorReadLine();
        this.iisProcess.BeginOutputReadLine();

Если кому угодно, это часть "стопового" фрагмента:

        if (this.iisProcess == null) throw new Exception("Does not look like there was something started yet!");

        if (this.iisProcess.HasExited)
        {
            log.WarnFormat("IIS has already exited with code '{0}'", this.iisProcess.ExitCode);
            this.iisProcess.Close();
            return;
        }

        log.InfoFormat("Stopping IIS instance #{0}", this.instanceId);
        ProcessCommunication.SendStopMessageToProcess(this.iisProcess.Id);
        bool exited = this.iisProcess.WaitForExit(30000);
        if (!exited)
        {
            log.WarnFormat("Failed to stop IIS instance #{0} (PID {1}), killing it now", this.instanceId, this.iisProcess.Id);
            this.iisProcess.Kill();
        }

        this.iisProcess.Close();

Чтобы остановить процесс iis обычным способом, необходимо отправить ему команду WM_QUIT. Это может быть полезно для этого:

    /// <summary>
    /// Sends a WM_QUIT message to another process.
    /// </summary>
    /// <param name="pid">PID of the other process</param>
    public static void SendStopMessageToProcess(int pid)
    {
        log.DebugFormat("Sending stop message to PID #{0}", 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 ex)
        {
            log.Error(String.Format("Failed to send WM_QUIT to PID #{0}", pid), ex);
        }
    }

    /// <summary>
    /// Provides the native methods to post messages to other windows processes.
    /// </summary>
    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);
    }
person ZoolWay    schedule 03.12.2014
comment
Хорошо, почему бы также не перенаправить stdinput и не отправить Q, чтобы изящно остановить iis. Затем вы можете дождаться HasExited и остановить процесс, если это не удастся. - person Jürgen Steinblock; 10.08.2015