ASP.NET MVC 3 RC AreaRegistration.RegisterAllAreas () und dynamisch geladen Baugruppen
-
27-09-2019 - |
Frage
Ich bin derzeit mit dynamisch belasteten Bereichen mit ASP.NET MVC 3 RC experimentieren. Ich habe es in vielen Orten geschrieben gesehen, dass dies nicht, welche Bereiche bestimmt sind für und (zumindest Pre-MVC 2) nicht möglich, sagt hier zum Beispiel.
Aber immer noch! Es sollte möglich sein, sie zur Arbeit zu kommen, nicht wahr? Ich habe eine Lösung geschaffen, ein MVC 3-Projekt, fügte eine Fläche und einige Inhalte hinzugefügt. Alle gut funktioniert. Jetzt habe ich ein neues Klassenbibliotheksprojekt (in der gleichen Lösung), einen Verweis auf mich aus dem MVC-Projekt hinzugefügt, und begann, in die Bibliothek über die flächenbezogenen Teile bewegen. Geändert, um die Ausgabe-Verzeichnis des Bibliothek-Projekt in den Bereich-Ordner des MVC-Projekt, und sorgte dafür, dass die Ansichten und ihre web.config kopiert werden an den Ausgabeordner.
Nach der Lektüre so viel darüber, wie Sie keine externen Bereiche haben könnten, es war ein wenig überraschend, dass dies funktioniert. Kein Problem bei allen wirklich! Das Problem beginnt, wenn ich den Bezug zwischen den Projekten entfernen und stattdessen die Bibliothek in Code laden. (Vor AreaRegistration.RegisterAllAreas()
Aufruf.) Nun ist es nicht funktioniert. Bei allen.
Ich habe Stocher schon ein wenig in der Quelle für MVC 3, und das Problem scheint mit BuildManager.GetReferencedAssemblies()
die die Baugruppen Look für Implementierungen von AreaRegistration
zu bekommen verwendet wird.
Nun, ich bin nicht 100% sicher darüber, aber es scheint, als ob diese Methode bei Baugruppen sieht nur die zum Zeitpunkt der Kompilierung, kann jemand bestätigen present / verwiesen waren, wenn dies in der Tat so?
Ich habe durch diese debuggt, und dieser Methode-Aufruf ist in der Tat nicht die Baugruppe mich vor dem Aufruf geladen, nur um es zu finden. Es könnte wegen etwas anderes sein, dass ich vielleicht .. Irgendwelche Ideen verpasst haben?
Lösung
Die Art und Weise der Dinge Arbeit ist ein wenig kompliziert.
GetReferencedAssemblies
enthält referenzierten Assemblys, nicht geladen Baugruppen. Dazu gehören:
- alle referenzierten Assemblys in Ihrer Anwendung web.config (wie
System.Web.Mvc
) - alles von der Wurzel web.config geerbt, die Dinge wie
System
,System.Web
und andere beinhaltet, dass Sie nicht selbst hinzufügen müssen. (Sie können in der Liste einen Blick hier:C:\Windows\Microsoft.Net\Framework\v4.0.30319\web.config
).
Es enthält auch einen speziellen*
Artikel, die : - enthält alles, was in
bin
Ihrer Website Ordner
So, jetzt die App v1 (alles in einer einzigen App) nehmen. Alles funktioniert, weil der Anwendungscode in den Papierkorb-Ordner erstellt wird, die automatisch aufgenommen wird. Auch alle Bereichsansichten usw. sind in der Anwendung selbst, so dass sie zugänglich sind.
Jetzt in app v2 (anderes Projekt mit einer proj-to-proj Referenz und eine benutzerdefinierte Build-Aufgabe, die Kopien, die Ansichten an die richtigen Stelle in der Haupt app) alles noch funktioniert, weil standardmäßig eine proj-to-proj Referenzen bedeuten, dass die Klassenbibliothek binär zu Ihren App Binärordner kopiert wird. So durch die oben genannten Regeln, wird der Ortsvorwahl noch richtig geladen. Die Tatsache, dass Sie die Bibliothek des Ausgabepfad festgelegt haben einig Standorte innerhalb Ihrer App-Bereiche werden Ordner nicht wirklich einen Unterschied machen -. Sie nur mit zwei Kopien der binären am Ende
Jetzt in app v3 (keine proj-proj ref, Bereich Bibliothek Assembly geladen manuell) Ihre Bibliothek wird Baugruppe zu spät geladen. Mit der Zeit läuft Ihr Code den Satz von referenzierten Baugruppen bereits gesperrt und kann nicht mehr geändert werden kann.
Es gibt einen Weg, um Code auszuführen, und fügen Sie Elemente in der Liste der registrierten Baugruppen: Sie können es tun, um die AddReferencedAssembly
Methode, die em <> muss aufgerufen wird, von einem PreApplicationStartMethodAttribute
Methode .
Natürlich müssen Sie noch behandeln, wie Sie die Ansicht Dateien verwalten. Die Art und Weise Sie derzeit haben es eingerichtet ist so ziemlich das gleiche wie die Ansichten in der Hauptanwendung, die (da sie effektiv in die richtige Stelle kopiert werden).
Andere Tipps
1 - Seperate Sie Mvc Bereiche in differ Mvc Projekte in ihre eigenen separaten Baugruppen erstellt werden
2 - Fügen Sie diese auf Ihrem AssemblyInfo.cs Klasse, eine Methode aufrufen, wenn die Anwendung geladen wird
[assembly: PreApplicationStartMethod(typeof(PluginAreaBootstrapper), "Init")]
3 - Hier ist, was die Init-Methode aussieht, wenn es während der Belastung
aufgerufen werdenpublic 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 - Fügen Sie eine benutzerdefinierte 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 - Registrieren Sie Ihre Bereiche von Ihrer verschiedenen Mvc (Region) Projekte
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 und weitere Referenzen finden Sie finden Sie hier: http://blog.longle.io/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas