2014-12-01 11 views
18

Mam w pełni działającą aplikację ASP.NET MVC (składającą się z 5 złożeń, .NET 4.5.1, ASP.NET MVC 5.2.2), która działa dobrze w Visual Studio (który używa IISExpress).Self-host aplikacji ASP.NET MVC

Chciałbym teraz mieć aplikację konsolową, która pobiera aplikację MVC i hostuje ją (sam hosting).

Próbowałem z Microsoft.Owin.Host.HttpListener i Nancy.Owin, ale gdy dostaję 404 stron w mojej konfiguracji brakuje mapowania do mojej aplikacji MVC.

mam

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

i

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(); 
     } 
    } 

Ale oczywiście konfiguracja używać MyMvcApplication od uruchomionej aplikacji MVC brakuje. Jak to zrobić? Albo jak to zrobić w inny sposób?

Odpowiedzi znalezione w Internecie odnoszą się do starszych wersji i miałem nadzieję, że dziś będzie łatwiej.

+2

O ile mi zbadali teraz to nie będzie możliwe przed 5 (ASP.NET MVC vNext; 6) i gospodarzem mój wniosek z Nancy wymagać będzie migrować z ASP.NET MVC do Nancy (która może również używać silnika szablonów Razor). Poprawny? – ZoolWay

+2

Jak wyżej, nie możesz "samopodgrywać" MVC, a Nancy to zupełnie inna platforma do tworzenia stron internetowych dla MVC - nie jest to alternatywny sposób na hostowanie MVC i nie można tak po prostu złączyć ich w ten sposób. –

+0

Pytanie brzmi, czy jest coś jeszcze do hostowania tego samego lub czy MVC5 po prostu wymaga hostingu IIS bez żadnego obejścia. – ZoolWay

Odpowiedz

12

Ponieważ ASP.NET vNext nie jest jeszcze dostępny i moja aplikacja używa MVC5, musiałbym całkowicie zmigrować aplikację MVC do Nancy lub coś podobnego. MVC5 jest zbyt zależny od IIS.

Aby rozwiązać ten międzyczasie zdecydowałem się na rozwiązanie pośrednie, jak wydajność nie jest problemem:

Moja aplikacja konsoli tworzy plik konfiguracyjny IIS i uruchamia wyraźnych IIS:

 // 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(); 

Jeśli ktoś chciałby , jest to część fragmentu "stop":

 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(); 

Aby zatrzymać proces iis, należy wysłać do niego WM_QUIT. Może to być pomocne w tym:

/// <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); 
    } 
+0

Cóż, czemu nie przekierować stdinput i wysłać 'Q' by z wdziękiem zatrzymać iis. Następnie możesz poczekać na HasExited i nadal zatrzymać proces, jeśli to się nie powiedzie. –