我目前正在尝试使用ASP.NET MVC 3 RC动态加载区域。我已经看到它写在很多地方,这不是那些区域的目的,并且(至少在MVC 2之前)不可能,例如here。
但是还是!它应该可以让它工作,对吧?我创建了一个解决方案,添加了一个MVC 3项目,添加了一个区域和一些内容。一切都运作良好。现在我创建了一个新的类库项目(在同一个解决方案中),从MVC项目添加了对它的引用,并开始将与区域相关的部分移动到库中。将库项目的输出目录更改为MVC项目的area-folder,并确保将Views及其web.config复制到output-folder。
在阅读了很多关于你如何不能拥有外部区域之后,这有点令人惊讶。真的没问题!当我删除项目之间的引用,而不是在代码中加载库时,问题就开始了。 (在致电AreaRegistration.RegisterAllAreas()
之前。)现在它不起作用。完全没有。
我一直在寻找MVC 3的源代码,问题似乎是BuildManager.GetReferencedAssemblies()
,它用于让程序集查找AreaRegistration
的实现。
现在,我不是百分之百确定这一点,但似乎这个方法只查看在编译时存在/引用的程序集,有人可以确认这是否实际上是这样的吗?
我已经通过调试了,而且方法调用确实没有找到我在调用之前加载的程序集。可能是因为我可能错过的其他东西......有什么想法吗?
答案 0 :(得分:20)
事情的运作方式有点复杂。
GetReferencedAssemblies
包含引用的程序集,而不是已加载的程序集。这包括:
System.Web.Mvc
)System
,System.Web
等内容,以及您不必自行添加的内容。 (您可以在此处查看列表:C:\Windows\Microsoft.Net\Framework\v4.0.30319\web.config
)。 *
项,:bin
文件夹所以现在拿你的应用程序v1(一切都在一个应用程序中)。一切正常,因为应用程序代码被编译到自动包含的bin文件夹中。此外,所有区域视图等都在应用程序本身中,因此可以访问它们。
现在在app v2中(不同项目的proj-to-proj引用和自定义构建任务将视图复制到主应用程序中的正确位置)一切仍然有效,因为默认情况下proj-to-proj引用意味着类库二进制文件被复制到应用程序的bin文件夹中。因此,通过上述规则,区域代码仍然可以正确加载。您将库的输出路径设置为主应用程序的“区域”文件夹中的某个位置这一事实实际上没有什么区别 - 您最终会得到两个二进制副本。
现在在app v3(没有proj-proj ref,手动加载区域库程序集)你的库程序集加载得太晚了。在代码运行时,已引用的程序集已被锁定,无法再更改。
有一种方法可以运行代码并将项目添加到已注册程序集的列表中:您可以使用AddReferencedAssembly
方法执行此操作,该方法必须从PreApplicationStartMethodAttribute
method调用
当然,您仍然需要处理如何管理视图文件。您当前设置它的方式与在主应用程序中拥有视图几乎相同(因为它们有效地被复制到正确的位置)。
答案 1 :(得分:6)
1 - 将你的Mvc区域分成不同的Mvc项目,编译成他们自己的单独组件
2 - 将其添加到AssemblyInfo.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}
);
}
}
}
可以在此处找到源代码和其他参考资料: http://blog.longle.io/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas