web-dev-qa-db-fra.com

Comment enregistrer un contrôleur dans ASP.NET MVC lorsque la classe de contrôleur est dans un autre assemblage?

Mon objectif est de modifier le registre des contrôleurs asp.net mvc afin de pouvoir créer des contrôleurs et des vues dans un assembly (enfant) distinct. "à l'application hôte.

De toute évidence, j'aurai besoin d'une sorte de modèle IoC, mais je suis perdu.

Je pensais avoir un assemblage enfant avec system.web.mvc référencé, puis commencer à créer des classes de contrôleur héritées de Controller:

Assemblée séparée:

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

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

Yay tout va bien et dandy. Mais ensuite, j'ai envisagé de modifier le registre des contrôleurs de l'application hôte pour charger mon nouveau contrôleur enfant au moment de l'exécution, et j'ai été dérouté. Peut-être parce que j'ai besoin d'une compréhension plus profonde de C #.

Quoi qu'il en soit, je pensais avoir besoin de créer une classe CustomControllerFactory. J'ai donc commencé à écrire une classe qui remplacerait la méthode GetControllerInstance(). En tapant, intellisence a fait apparaître ceci:

Application hôte MVC:

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

Maintenant, à ce stade, je suis perdue. Je ne sais pas ce que ça fait. À l'origine, j'allais écrire une classe "Controller Loader" comme un localisateur de service comme celui-ci:

Application hôte MVC:

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

Et puis, je prévoyais d’utiliser ma liste de contrôleurs pour les enregistrer dans l’usine de contrôleurs. Mais comment? Je sens que je suis sur le point de le comprendre. Je suppose que tout se résume à cette question: comment puis-je accrocher dans return base.GetControllerInstance(requestContext, controllerType);? Ou devrais-je utiliser une approche totalement différente?

26
quakkels

Référencez l'autre assembly à partir du projet ASP.NET MVC 'root'. Si les contrôleurs se trouvent dans un autre espace de noms, vous devez modifier les itinéraires dans global.asax, comme suit:

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

}

Notez l'argument namespaces supplémentaire de la méthode MapRoute.

26
Mark Seemann

Votre autre projet doit être configuré comme une zone et vous obtiendrez le résultat souhaité. La classe d'enregistrement de zone apportera votre projet de région dans le mix. Ensuite, vous pouvez simplement déposer la dll dans une application en cours d’exécution et celle-ci sera exécutée sans créer l’application entière ni la redéployer.

Le moyen le plus simple consiste à ajouter un nouveau projet MVC à votre solution et à ce que Visual Studio crée le nouveau projet dans/areas/mynewprog /. Supprimez tous les fichiers dont vous n'avez pas besoin et ajoutez une classe d'enregistrement de zone pour le connecter.

Construisez le projet, récupérez sa dll et déposez-le dans le répertoire bin de votre site Web en cours d'exécution. ..

Il vous suffit ensuite de gérer les vues et leurs éléments, soit les compiler dans la dll, soit les copier sur le serveur dans le dossier areas/mynewproj /.

3
JBeckton

Créez un module séparé comme indiqué dans la structure du projet de plug-in:

 Plugin Project structure

Notez que certains fichiers ont été exclus du projet.

Le fichier MessagingController.cs est le suivant:

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

    }
}

Le fichier MessagingAreaRegistration est comme indiqué:

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

  }
}

La potion pertinente du fichier Global.asax.cs est la suivante:

[Chargez le plug-in externe (contrôleurs, bibliothèque de contrôleurs d'api) dans le domaine d'application actuel. Après cela, asp.net mvc fait le reste pour vous (enregistrement de zone et découverte des contrôleurs) [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");
1
RorvikSam

mon expérience avec les contrôleurs est que cela fonctionne. Copiez l’Assemblée dans le répertoire bin (ou ajoutez une référence à l’Assemblée et elle y sera copiée pour vous)

Je n'ai pas essayé avec des vues

0
pm100