Как зарегистрировать контроллер в ASP.NET MVC, когда класс контроллера находится в другой сборке?
Моя цель - изменить регистр контроллера asp.net mvc, чтобы я мог создавать контроллеры и представления в отдельной (дочерней) сборке и просто копировать файлы View и DLL в приложение MVC хоста и эффективно использовать новые контроллеры "Подключено" к хост-приложению.
Очевидно, мне понадобится какой-то шаблон IoC, но я в недоумении.
Моя мысль заключалась в том, чтобы иметь дочернюю сборку с ссылкой на system.web.mvc, а затем просто начать создавать классы контроллера, унаследованные от Controller
:
Отдельная сборка:
using System.Web;
using System.Web.Mvc;
namespace ChildApp
{
public class ChildController : Controller
{
ActionResult Index()
{
return View();
}
}
}
Все прекрасное и денди. Но затем я изучил модификацию реестра контроллера приложения хоста для загрузки моего нового дочернего контроллера во время выполнения, и я запутался. Возможно, потому, что мне нужно более глубокое понимание С#.
Во всяком случае, мне показалось, что мне нужно создать класс CustomControllerFactory
. Поэтому я начал писать класс, который заменил бы метод GetControllerInstance()
. Когда я печатал, intellisence выскочил это:
Host MVC Application:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return base.GetControllerInstance(requestContext, controllerType);
}
}
Теперь, в этот момент я не понимаю. Я не знаю, что это делает. Первоначально я собирался написать класс "Контроллер-загрузчик", например, "Локатор сервисов":
Host MVC Application:
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;
}
}
И затем я планировал использовать список контроллеров для регистрации их в контроллере factory. Но как? Я чувствую, что нахожусь на грани выяснения этого. Я думаю, все это сводится к этому вопросу: как мне подключиться к return base.GetControllerInstance(requestContext, controllerType);
? Или, должен ли я использовать другой подход вообще?
Ответы
Ответ 1
Ссылка на другую сборку из проекта "root" ASP.NET MVC. Если контроллеры находятся в другом пространстве имен, вам нужно будет изменить маршруты в global.asax, например:
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 }
);
}
Обратите внимание на дополнительный аргумент namespaces
на метод MapRoute
.
Ответ 2
Ваш другой проект должен быть настроен как область, и вы получите желаемый результат. Класс регистрации области приведет ваш проект в проект. Затем вы можете просто выбросить dll в запущенное приложение, и оно будет работать без создания всего приложения и повторного развертывания.
Самый простой способ сделать это - добавить новый проект mvc в ваше решение и создать Visual Studio в новом проекте внутри /areas/mynewprog/. Удалите все файлы, которые вам не нужны, и добавьте класс регистрации области, чтобы подключить его.
Создайте проект, возьмите его dll и поместите в свой текущий каталог bin bin и его..
Вам просто нужно иметь дело с представлениями и т.д., либо скомпилировать их в dll, либо скопировать их на сервер в области/mynewproj/folder.
Ответ 3
Мой опыт работы с контроллерами заключается в том, что это работает. Скопируйте сборку в каталог bin (или добавьте ссылку на сборку, и она будет скопирована для вас)
Я не пробовал с просмотрами
Ответ 4
Создайте отдельный модуль, как показано
Структура проекта плагина
Обратите внимание, что некоторые файлы, исключенные из проекта.
Файл MessagingController.cs выглядит следующим образом:
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);
}
}
}
Файл MessagingAreaRegistration выглядит так:
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" }
);
}
}
}
Соответствующее зелье файла Global.asax.cs выглядит следующим образом:
[Загрузите внешний плагин (контроллеры, библиотеку контроллеров api) в текущий домен приложения. После этого asp.net mvc сделает все остальное для вас (регистрация области и обнаружение контроллеров) [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");