2014-12-01 12 views
18

Ho un'applicazione MVC ASP.NET completamente funzionante (costituita da 5 assembly, .NET 4.5.1, ASP.NET MVC 5.2.2) che funziona correttamente in Visual Studio (che utilizza IISExpress).Self-host dell'applicazione ASP.NET MVC

Vorrei ora avere un'applicazione console che prende l'applicazione MVC e la ospita (self hosting).

Ho provato con Microsoft.Owin.Host.HttpListener e Nancy.Owin ma mentre ottengo 404 pagine le mie configurazioni mancano del mapping alla mia MVC-app.

ho avuto

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

e

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

Ma ovviamente la configurazione da utilizzare MyMvcApplication dall'applicazione MVC esecuzione è mancante. Come farlo? O come farlo da solo?

Le risposte che ho trovato sul web si riferiscono alle versioni precedenti e speravo di avere un modo più semplice oggi.

+2

Per quanto ho ricercato ora questo non sarà possibile prima ASP.NET 5 (vNext; MVC 6) e hosting mia applicazione con tutto regolare richiederà di migrare da ASP.NET MVC a Nancy (che potrebbe anche utilizzare il motore di template Razor). Corretta? – ZoolWay

+2

Come sopra, non è possibile "auto-ospitare" MVC, e Nancy è un framework di sviluppo web completamente diverso per MVC - non è un modo alternativo di ospitare MVC e non è possibile semplicemente combinarli insieme in questo modo. –

+0

La domanda quindi è se c'è qualcos'altro da ospitare autonomamente o se MVC5 richiede semplicemente l'hosting IIS senza alcuna soluzione alternativa. – ZoolWay

risposta

12

Poiché ASP.NET vNext non è ancora disponibile e la mia app utilizza MVC5, dovrei migrare completamente l'app MVC a Nancy o qualcosa di simile. MVC5 è troppo dipendente da IIS.

Per risolvere questo frattempo ho deciso per una soluzione intermedia come prestazioni non è un problema:

mia console applicazione crea un file di configurazione di IIS e lancia un espresso 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(); 

Se qualcuno vorrebbe , questo fa parte del frammento "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(); 

per arrestare il processo di IIS ordinario è necessario inviare WM_QUIT ad esso. Questo potrebbe essere utile per questo:

/// <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

Bene, perché non reindirizzare anche stdinput e inviare 'Q' per fermare iis con garbo. Di quanto tu possa aspettare HasExited e comunque interrompere il processo se ciò non riesce. –