ASP.NET MVC 3 RC Aregistration.registreAllareas () и динамически загруженные сборки
-
27-09-2019 - |
Вопрос
В настоящее время я экспериментирую с динамически загруженными областями с ASP.NET MVC 3 RC. Я видел, как это написано во многих местах, что это не в том, какие области предназначены для, а (по крайней мере, до MVC 2) невозможно, скажем здесь Например.
Но все равно! Должно быть возможно получить его на работу, верно? Я создал решение, добавил проект MVC 3, добавил область и некоторый контент. Все работает хорошо. Теперь я создал новый проект библиотеки класса (в том же решении), добавил ссылку на него из MVC-проекта и начал перемещаться по части, связанным с областью в библиотеку. Изменена вывод-каталог библиотечного проекта в область-папку MVC-проекта и убедился, что представления и их Web.config скопированы в выходную папку.
Прочитав так много о том, как вы не могли иметь внешние области, было немного удивительно, что это сработало. Нет проблем вообще не очень! Проблема начинается при удалении ссылки между проектами и вместо этого загружаю библиотеку в коде. (Перед звонком AreaRegistration.RegisterAllAreas()
.) Теперь это не работает. Вообще.
Я немного покинул в источнике для MVC 3, и проблема, кажется, с BuildManager.GetReferencedAssemblies()
который используется для получения собраний для поиска реализаций AreaRegistration
.
Теперь я не на 100% уверен в этом, но кажется, что этот метод смотрит только на сборки, которые присутствовали / упоминались при компиляции времени, может кто-то подтвердить, если это на самом деле так?
Я отладил это, и этот метод-звонок действительно не находит сборку, которую я загрузил только до вызова к нему. Это может быть из-за чего-то другого, что я пропустил, наверное .. Есть идеи?
Решение
То, как вещи работают немного сложны.
GetReferencedAssemblies
Включает в себя ссылочные сборки, не загруженные сборки. Это включает в себя:
- Все собрания, на которые ссылаются в вас Web.config (например,
System.Web.Mvc
) - Все унаследовано от root web.config, который включает в себя такие вещи, как
System
,System.Web
И другие, которые вам не нужно добавлять себя. (Вы можете взглянуть на список здесь:C:\Windows\Microsoft.Net\Framework\v4.0.30319\web.config
).
Это также содержит специальный*
предмет, который: - включает в себя все на вашем сайте
bin
папка
Так что теперь возьмите свое приложение V1 (все в одном приложении). Все работает, потому что код приложения компилируется в папку Bin, которая автоматически включается. Кроме того, все виды видов и т. Д. Находятся в самом приложении, поэтому они доступны.
Теперь в приложении V2 (другой проект с ссылкой PROJ-PROJ а также Пользовательская задача сборки, которая копирует вид на правильное местоположение в вашем основном приложении), все еще работает, по умолчанию по умолчанию ProJ-ProJ ссылки означает, что двоичный бинарный библиотека класса скопирован в папку Bin App. Так что по вышеуказанным правилам код города все еще загружается правильно. Тот факт, что вы установили выходной путь библиотеки, чтобы быть некоторого местоположения в папке ваших основных приложений, на самом деле не имеет значения - вы просто в конечном итоге с двумя копиями двоичных.
Сейчас в приложении V3 (NO PROJ-PROJ Ref, Assistance Library Library загружена вручную) Ваша библиотека сборка загружается слишком поздно. К тому времени, когда ваш код запускается набор ссылок с монтажами уже заблокирован и больше не может быть изменен.
Есть способ запустить код и добавить элементы в список зарегистрированных собраний: вы можете сделать это, используя AddReferencedAssembly
метод, который должен быть вызванным из PreApplicationStartMethodAttribute
метод.
Конечно, вам все еще нужно иметь дело с тем, как вы управляете файлами вашего просмотра. То, как вы в настоящее время настроили его, в значительной степени так же, как имеющие представления в основном приложении (поскольку они эффективно копируются в правильное местоположение).
Другие советы
1 - отделяйте свои области MVC в разные проекты MVC, которые будут скомпилированы в свои собственные отдельные сборки
2 - Добавьте это к классу AssocusInfo.cs, чтобы вызвать метод, когда приложение загружено
[assembly: PreApplicationStartMethod(typeof(PluginAreaBootstrapper), "Init")]
3 - вот что выглядит метод init, когда он вызывается во время нагрузки
public class PluginAreaBootstrapper
{
public static readonly List<Assembly> PluginAssemblies = new List<Assembly>();
public static List<string> PluginNames()
{
return PluginAssemblies.Select(
pluginAssembly => pluginAssembly.GetName().Name)
.ToList();
}
public static void Init()
{
var fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Areas");
foreach (var file in Directory.EnumerateFiles(fullPluginPath, "*Plugin*.dll"))
PluginAssemblies.Add(Assembly.LoadFile(file));
PluginAssemblies.ForEach(BuildManager.AddReferencedAssembly);
}
}
4 - Добавить пользовательский RazorviewEngine
public class PluginRazorViewEngine : RazorViewEngine
{
public PluginRazorViewEngine()
{
AreaMasterLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/{1}/{0}.vbhtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.vbhtml"
};
AreaPartialViewLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/{1}/{0}.vbhtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.vbhtml"
};
var areaViewAndPartialViewLocationFormats = new List<string>
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/{1}/{0}.vbhtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.vbhtml"
};
var partialViewLocationFormats = new List<string>
{
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml"
};
var masterLocationFormats = new List<string>
{
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml"
};
foreach (var plugin in PluginAreaBootstrapper.PluginNames())
{
masterLocationFormats.Add(
"~/Areas/" + plugin + "/Views/{1}/{0}.cshtml");
masterLocationFormats.Add(
"~/Areas/" + plugin + "/Views/{1}/{0}.vbhtml");
masterLocationFormats.Add(
"~/Areas/" + plugin + "/Views/Shared/{1}/{0}.cshtml");
masterLocationFormats.Add(
"~/Areas/" + plugin + "/Views/Shared/{1}/{0}.vbhtml");
partialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Views/{1}/{0}.cshtml");
partialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Views/{1}/{0}.vbhtml");
partialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Views/Shared/{0}.cshtml");
partialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Views/Shared/{0}.vbhtml");
areaViewAndPartialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Views/{1}/{0}.cshtml");
areaViewAndPartialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Views/{1}/{0}.vbhtml");
areaViewAndPartialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Areas/{2}/Views/{1}/{0}.cshtml");
areaViewAndPartialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Areas/{2}/Views/{1}/{0}.vbhtml");
areaViewAndPartialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Areas/{2}/Views/Shared/{0}.cshtml");
areaViewAndPartialViewLocationFormats.Add(
"~/Areas/" + plugin + "/Areas/{2}/Views/Shared/{0}.vbhtml");
}
ViewLocationFormats = partialViewLocationFormats.ToArray();
MasterLocationFormats = masterLocationFormats.ToArray();
PartialViewLocationFormats = partialViewLocationFormats.ToArray();
AreaPartialViewLocationFormats = areaViewAndPartialViewLocationFormats.ToArray();
AreaViewLocationFormats = areaViewAndPartialViewLocationFormats.ToArray();
}
}
5 - Зарегистрируйте свои области из разных проектов MVC (область)
namespace MvcApplication8.Web.MyPlugin1
{
public class MyPlugin1AreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "MyPlugin1"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"MyPlugin1_default",
"MyPlugin1/{controller}/{action}/{id}",
new {action = "Index", id = UrlParameter.Optional}
);
}
}
}
Sourcecode и дополнительные ссылки можно найти здесь:http://blog.longle.io/2012/03/29/building-a-composite-mvc3-Application-with-pluggable-areas.