asp.net mvc hat Controller in ein separates Projekt eingebunden

107

Ich lerne gerade asp.net mvc und versuche herauszufinden, wie ich meine Controller in ein separates Projekt verschieben kann. Wenn ich zuvor asp.net-Webanwendungen entworfen habe, habe ich normalerweise ein Projekt für meine Modelle erstellt, ein anderes für meine Logik, und dann war da noch das Web.

Jetzt, da ich asp.net mvc lerne, hatte ich gehofft, einem ähnlichen Muster zu folgen und die Modelle und Controller jeweils in ihre eigenen Projekte zu integrieren und einfach die Ansichten / Skripte / CSS im Web zu belassen. Der Modellteil war einfach, aber ich verstehe nicht, wie ich meine Controller in einem separaten Projekt "finden" kann. Ich würde auch gerne wissen, ob dies ratsam ist. Vielen Dank!

Aaron Palmer
quelle

Antworten:

92

Zuallererst ist es sicherlich eine gute Idee, Ihr Modell in ein separates Projekt zu integrieren. Wie Sie festgestellt haben, ist dies trivial.

In Bezug auf Controller und Ansichten sehe ich keinen offensichtlichen Vorteil darin, sie für die meisten grundlegenden Projekte zu trennen, obwohl Sie dies möglicherweise in einer bestimmten Anwendung besonders tun müssen.

Wenn Sie sich dafür entscheiden, müssen Sie dem Framework mitteilen, wie Sie Ihre Controller finden. Der grundlegende Weg, dies zu tun, ist die Bereitstellung Ihrer eigenen ControllerFactory. Sie können sich den Quellcode für die DefaultControllerFactory ansehen, um eine Vorstellung davon zu erhalten, wie dies gemacht wird. Das Subtypisieren dieser Klasse und das Überschreiben der GetControllerType-Methode (string controllerName) kann ausreichen, um das zu erreichen, was Sie verlangen.

Nachdem Sie Ihre eigene benutzerdefinierte ControllerFactory erstellt haben, fügen Sie Application_Start in global.asax die folgende Zeile hinzu, um dem Framework mitzuteilen, wo es zu finden ist:

ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());

Update: Lesen Sie diesen Beitrag und die Beiträge, auf die er verweist, um weitere Informationen zu erhalten. Siehe auch Phil Haacks Kommentar zu diesem Beitrag über:

ControllerBuilder.Current.DefaultNamespaces.Add(
    "ExternalAssembly.Controllers");

... was keine vollständige Lösung ist, aber möglicherweise gut genug für einfache Fälle.

Craig Stuntz
quelle
2
Danke Craig! Genau das habe ich gesucht. Gibt es diese Informationen überhaupt im Web? Ich habe überall mit wenig Glück gegoogelt. StackOverflow kommt wieder durch!
Aaron Palmer
11
Ich bin damit einverstanden, dass Controller Benutzereingaben verarbeiten, das Modell bearbeiten und dann Daten an die Ansicht übergeben. Sie sind in der Regel sehr anwendungsspezifisch. Jede Logik, die nicht spezifisch für die App ist, ist in einer Bibliothek oder im Modell möglicherweise besser geeignet. Aber Controller sollten im Allgemeinen mit dem Webprojekt sein.
Haacked
2
Ich habe einen Fehlercontroller und Ansichten, die zwischen zwei Apps identisch sind. Für mich ist es sinnvoll, diese in einer einzigen Baugruppe zu haben, die beide Apps verwenden können.
Segeln Judo
3
Ist es nicht einfacher, die Controller zu testen und IoC zu verwenden, wenn sich die Controller in einem separaten Projekt befinden - das wäre der Hauptgrund
Samuel G
1
@Chev, ich glaube nicht, dass es dort einen Unterschied macht. Die Testbarkeit Ihrer Controller hat mehr damit zu tun, wie Sie sie codieren , nicht damit, wo sie leben.
Craig Stuntz
19

Es ist zwar sinnvoll, eine eigene ControllerFactory zu erstellen, aber ich fand es bequemer, alle meine Controller in jedem Projekt zu definieren, sie jedoch von Controllern in meinem freigegebenen Projekt abzuleiten:

namespace MyProject1.Controllers
{
   public class MyController : MySharedProject.Controllers.MyController
   {
      // nothing much to do here...
   }
}

namespace MySharedProject.Controllers
{
   public abstract class MyController : System.Web.Mvc.Controller
   {
      // all (or most) of my controller logic here...
   }
}

Dies hat den zusätzlichen Vorteil, dass Sie einen Platz haben, an dem Sie Ihre Controller-Logik platzieren können, die von Projekt zu Projekt unterschiedlich ist. Außerdem ist es für andere Entwickler einfacher, Ihre Controller-Logik schnell zu finden, da die Controller an der Standardposition vorhanden sind.

In Bezug darauf, ob dies ratsam ist, halte ich es für absolut sinnvoll. Ich habe eine gemeinsame Account Management-Logik erstellt, die ich zwischen Projekten teilen möchte, die ansonsten eine sehr unterschiedliche Geschäftslogik haben. Ich teile also mein Konto und meine Administrator-Controller, aber die anderen Controller sind spezifisch für ihre jeweiligen Projekte.

Dieser Typ
quelle
1
Dies funktionierte sehr gut, aber ich musste redundanten Code entfernen, um einen Routing-Fehler zu vermeiden
Ken Mc
Hallo, wie kann ich das Routing in dieser Art von Projekt verwalten? Ich möchte Verwendung Attribut Routing ...
محمد
Sie können das Attribut-Routing wie gewohnt verwenden.
ThisGuy
2
Ich bin mir nicht sicher, warum dies nicht mehr positive Stimmen hat ... viel eleganter als die akzeptierte Antwort, denke ich. Vielen Dank!
Jleach
Das funktioniert bei mir nicht. Können Sie sagen, ob es sich um .Net Core oder .Net Framework handelt?
Homayoun Behzadian
4
  • Fügen Sie die Klassenbibliothek für Ihr MVC-Projekt hinzu.
  • Fügen Sie in der Klasse den folgenden Code hinzu (Für Ihren Controller-Code)

    namespace ContactController
    {
    public class ContactController : Controller
    {
        public ActionResult Call()
        {
            ViewBag.Title = "Inside MyFirst Controller.";
            return View();
        }
    }

    }}

  • Fügen Sie im Ordner mvc project view den Ordner für Contact hinzu und erstellen Sie eine Call.cshtml-Datei. Ordner anzeigen

  • Fügen Sie die Klassenbibliotheksprojektreferenz zu Ihrem Haupt-MVC-Projekt hinzu.

Referenz

  • Abschließend wird der Namespace des Kontaktcontrollers in Route Config referenziert.

RouteConfig

Randy Mohan
quelle
3
Das ist etwas bedauerlich, dass Sie einen Namespace mit demselben Namen wie der Controller haben.
Mariusz Jamro
3

Mein Problem wurde behoben, nachdem ich die System.Web.MvcNuGet-Referenz aktualisiert hatte, sodass MvcWebsite und Class Library dieselbe System.Web.MvcVersion verwenden

Es müssen keine Standard-Namespaces hinzugefügt werden

Homayoun Behzadian
quelle
Das Problem war, dass MvcWebsite keine Ausnahme auslöste, während die aktuelle MVC-Assembly eine niedrigere Version als die referenzierte MVC-Assembly der Klassenbibliothek hat
Homayoun Behzadian
1

Die einfachste Form der Trennung, die ich verwende, besteht darin, die Ansichten "wie sie sind" im ursprünglichen MVC-Projekt beizubehalten, aber die Controller zu entfernen. Fügen Sie dann in einem neuen ClassLibrary-Projekt die Controller-Klassen hinzu und stellen Sie sicher, dass sie von Controller erben.

Die MVC-Routing-Engine leitet automatisch zu den Controllern in der ClassLibrary weiter, und die Controller erstellen automatisch die Ansichten aus dem ursprünglichen MVC-Projekt, sofern Ihre Referenzen und Verwendungen korrekt vorhanden sind.

Ich verwende diese Architektur, um ein HTML-Berichtsmodul zu implementieren, das getrennt von der Hauptlösung kompiliert und bereitgestellt werden kann. Endlich bin ich frei von SSRS!

Jamie
quelle