c# unitycontainer Wie Registrieren eines Controllers in ASP.NET MVC, wenn sich die Controller-Klasse in einer anderen Assembly befindet?




unitycontainer unity (4)

Meine Erfahrung mit Controllern ist, dass das einfach funktioniert. Kopieren Sie die Assembly in das Verzeichnis bin (oder fügen Sie einen Verweis zur Assembly hinzu, der dort für Sie kopiert wird).

Ich habe es nicht mit Ansichten versucht

Mein Ziel ist es, asp.net mvc Controller registery zu ändern, so dass ich Controller und Ansichten in einer separaten (untergeordneten) Assembly erstellen und einfach die View-Dateien und die DLLs in die Host-MVC-Anwendung kopieren kann und die neuen Controller effektiv "Plugged In" sind "zur Host-App.

Natürlich brauche ich eine Art IoC-Muster, aber ich bin ratlos.

Mein Gedanke war, eine untergeordnete Assembly mit system.web.mvc zu referenzieren und dann einfach Controller-Klassen zu erstellen, die von Controller geerbt haben:

Separate Montage:

using System.Web;
using System.Web.Mvc;

namespace ChildApp
{
    public class ChildController : Controller
    {
        ActionResult Index()
        {
            return View();
        }
    }
}

Alles schön und gut. Aber dann habe ich nachgesehen, wie ich die Controller-Registrierung der Host-Anwendung geändert habe, um meinen neuen Kind-Controller zur Laufzeit zu laden, und ich war verwirrt. Vielleicht, weil ich ein tieferes Verständnis von C # brauche.

Wie auch immer, ich dachte, ich CustomControllerFactory eine CustomControllerFactory Klasse erstellen. Also begann ich eine Klasse zu schreiben, die die GetControllerInstance() Methode überschreiben würde. Während ich tippte, tauchte die Intelligenz auf:

Host-MVC-Anwendung:

public class CustomControllerFactory : DefaultControllerFactory 
{
    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        return base.GetControllerInstance(requestContext, controllerType);
    }
}

Jetzt bin ich ratlos. Ich weiß nicht, was das ist. Ursprünglich wollte ich eine "Controller Loader" -Klasse wie einen Service Locator schreiben:

Host-MVC-Anwendung:

public class ControllerLoader
{
    public static IList<IController> Load(string folder)
    {
        IList<IController> controllers = new List<IController>();

        // Get files in folder
        string[] files = Directory.GetFiles(folder, "*.plug.dll");
        foreach(string file in files)
        {
            Assembly assembly = Assembly.LoadFile(file);
            var types = assembly.GetExportedTypes();
            foreach (Type type in types)
            {
                if (type.GetInterfaces().Contains(typeof(IController)))
                {
                    object instance = Activator.CreateInstance(type);
                    controllers.Add(instance as IController);
                }
            }
        }
        return controllers;
    }
}

Und dann plante ich, meine Liste von Controllern zu verwenden, um sie in der Controller-Fabrik zu registrieren. Aber wie? Ich fühle mich, als wäre ich am Rande, es herauszufinden. Ich denke, es ist alles auf diese Frage: Wie return base.GetControllerInstance(requestContext, controllerType); ich in return base.GetControllerInstance(requestContext, controllerType); ? Oder sollte ich überhaupt einen anderen Ansatz verwenden?


Verweisen Sie die andere Assembly aus dem ASP.NET MVC-Stammprojekt. Wenn sich die Controller in einem anderen Namespace befinden, müssen Sie die Routen in global.asax wie folgt ändern:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        namespaces: new[] { typeof(HomeController).Namespace }
    );

}

Beachten Sie das zusätzliche namespaces Argument für die MapRoute Methode.


Ihr anderes Projekt sollte wie ein Bereich eingerichtet werden und Sie erhalten das gewünschte Ergebnis. Die Flächenregistrierungsklasse bringt Ihr Flächenprojekt in den Mix. Dann können Sie die DLL einfach in eine laufende App einfügen und sie wird ausgeführt, ohne die gesamte App zu erstellen und erneut zu implementieren.

Am einfachsten ist es, wenn Sie Ihrer Lösung ein neues mvc-Projekt hinzufügen und Visual Studio das neue Projekt in / areas / mynewprog / erstellen lassen. Löschen Sie alle nicht benötigten Dateien und fügen Sie eine Bereichsregistrierungsklasse hinzu, um sie zu verkabeln.

Erstellen Sie das Projekt, nehmen Sie es in die DLL und legen Sie es in Ihr laufendes Bin-Verzeichnis ab.

Sie müssen dann nur mit den Ansichten und Sachen fertig werden, entweder kompilieren sie in die DLL oder kopieren sie auf den Server in den Bereichen / mynewproj / Ordner.


Erstellen Sie ein separates Modul wie in der Plugin Projektstruktur dargestellt

Beachten Sie, dass einige Dateien aus dem Projekt ausgeschlossen wurden.

Die Datei MessagingController.cs lautet wie folgt:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MessagingModule.Controllers
{
    public class MessagingController : Controller
    {
        //
        // GET: /Messaging/

        public ActionResult Index()
        {
          var appName = Session["appName"]; // Get some value from another module
            return Content("Yep Messaging module @"+ appName);
        }

    }
}

Die MessagingAreaRegistration-Datei ist wie folgt:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace MessagingModule
{
  public class MessagingAreaRegistration : AreaRegistration
  {
    public override string AreaName
    {
      get
      {
        return "Messaging";
      }
    }

    public override void RegisterArea( AreaRegistrationContext context )
    {
      context.MapRoute(
          "Messaging_default",
          "Messaging/{controller}/{action}/{id}",
          new { action = "Index", id = UrlParameter.Optional }
        //new[] { "MessagingModule.Controllers" }
      );
    }

  }
}

Der relevante Abschnitt der Datei Global.asax.cs lautet wie folgt:

[Laden Sie das externe Plugin (Controller, API-Controller-Bibliothek) in die aktuelle App-Domäne. Danach übernimmt asp.net mvc den Rest für Sie (Bereichsregistrierung und Controller-Erkennung) [3]

   using System;
   using System.Collections.Generic;
   using System.Linq;
   using System.Web;
   using System.Web.Http;
   using System.Web.Mvc;
   using System.Web.Optimization;
   using System.Web.Routing;
   using System.Reflection;
   using System.Web.Configuration;
   using System.Text.RegularExpressions;

   namespace mvcapp
   {
     // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
     // visit http://go.microsoft.com/?LinkId=9394801

     public class MvcApplication : System.Web.HttpApplication
     {
       protected void Application_Start()
       {
         var domain = AppDomain.CurrentDomain;

         domain.Load("MessagingModule, Version=1.0.0.0, Culture=neutral,   PublicKeyToken=null");






inversion-of-control