Контроллер в отдельной сборке и маршрутизации
В том же решении есть приложение ASP.NET MVC4 Slick.App
и библиотека классов Awesome.Mvc.Lib
. Awesome.Mvc.Lib содержит один класс контроллера.
public class ShinnyController : Controller
{
[HttpGet]
public string Index()
{
return "Hello, from Awesome.Mvc.Lib";
}
}
Если я просто добавлю ссылку из Slick.App в Awesome.Mvc.Lib, запустите приложение и пункт brower на /shinny
, я действительно увижу ответ "Привет, от Awesome.Mvc.Lib".
Это то, чего я не ожидаю вообще. Все время я думал, что ASP.NET MVC уважает пространства имен, в которые помещаются контроллеры. Таким образом, контроллеры из других пространств имен не отображаются, по крайней мере, до того, как я не спросил.
Я попытался изменить учетную запись маршрута по умолчанию, чтобы использовать параметр namespaces.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new [] { "Slick.App.Controllers" }
);
Тем не менее, маршрут ShinnyController по-прежнему соответствует "/shinny".
У меня проблемы, это правильное поведение по умолчанию. Мой вопрос в том, как явным образом сказать, какие контроллеры выставлены, и предотвратить использование маршрута по умолчанию для соответствия контроллерам в отдельной библиотеке классов?
Ответы
Ответ 1
Список пространств имен на маршруте дает только приоритет для определенных пространств имен над другими, которые не указаны:
new [] {"Namespace1", "Namespace2"}
не дает более высокого приоритета Namespace1, как можно было бы ожидать, но просто отдавал приоритет обоим пространствам имен над другими.
Это означает, что пространства имен в списке сначала ищутся для контроллеров, а затем, если совпадение не найдено, используются остальные доступные контроллеры с этим именем.
Вы можете запретить использование не-приоритетных контроллеров, выполнив следующие действия:
var myRoute = routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new [] { "Slick.App.Controllers" }
);
myRoute.DataTokens["UseNamespaceFallback"] = false;
Ответ 2
Вы можете наследовать от DefaultControllerFactory следующим образом:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)
{
var type = base.GetControllerType(requestContext, controllerName);
if (type != null && IsIngored(type))
{
return null;
}
return type;
}
public static bool IsIngored(Type type)
{
return type.Assembly.GetCustomAttributes(typeof(IgnoreAssemblyAttribute), false).Any()
|| type.GetCustomAttributes(typeof(IgnoreControllerAttribute), false).Any();
}
}
Затем некоторые изменения в Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
}
И вот ты! Любой тип, отмеченный знаком IgnoreControllerAttribute, не будет виден. Вы можете даже скрыть всю сборку.
Если вам нужно какое-то поведение, основанное на конфигурации, не имеет большого значения внести все необходимые изменения;)