Dan*_*fer 12 c# asp.net-mvc mef razor
我正在尝试创建一个框架,允许将控制器和视图动态导入MVC应用程序.到目前为止它是如何工作的:
BuildManager.AddReferencedAssembly.到目前为止,除了使用强类型模型的视图外,一切都有效.使用动态模型的视图工作正常,但是当我使用指定模型类型时@model,我得到一个YSOD,其中显示"未找到视图'索引'或其主要".
调试我的ViewEngine实现时,我可以看到:
this.VirtualPathProvider.FileExists(String.Format(this.ViewLocationFormats[2], viewName, controllerContext.RouteData.GetRequiredString("controller")))while返回true
this.FileExists(controllerContext, String.Format(this.ViewLocationFormats[2], viewName, controllerContext.RouteData.GetRequiredString("controller"))) 返回false.
在Reflector中,RazorViewEngine的实现FileExists()最终结束了这样做:
return (BuildManager.GetObjectFactory(virtualPath, false) != null);
Run Code Online (Sandbox Code Playgroud)
但是,我无法BuildManager.GetObjectFactory()从Reflector 查看,因为它隐藏在某种程度上.
我怀疑它与模型类型是从MEF加载的类型这一事实有关,但由于我已经引用了MEF从BuildManager发现的程序集,所以我没有引导.任何人都可以更深入地了解可能发生的事情吗?
更新: 事实证明我在.NET 4之前使用过时版本的Reflector.我现在可以看到GetObjectFactory(),但我似乎找不到任何有用的东西.我已经尝试将其添加到我的FindView()重载中:
try {var path = String.Format(this.ViewLocationFormats [2],viewName,controllerContext.RouteData.GetRequiredString("controller")); var objFactory = System.Web.Compilation.BuildManager.GetObjectFactory(virtualPath:path,throwIfNotFound:true); } catch {}
不幸的是,objFactory最终为null,并且不会抛出任何异常.处理编译错误的所有位都是私有方法或类型的一部分,因此我无法调试其中任何一个,但它甚至看起来他们最终会抛出异常,这似乎并没有发生.看起来我又陷入了死胡同.救命!
更新2
我发现在调用FindView()时,如果我调用AppDomain.CurrentDomain.GetAssemblies(),则包含模型类型所在的程序集.但是,我无法使用加载类型Type.GetType().
更新3
这就是我所看到的:

更新4
这是ViewEngine实现:
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Hosting;
using System.Web.Compilation;
namespace Site.Admin.Portal
{
public class ModuleViewEngine : RazorViewEngine
{
private static readonly String[] viewLocationFormats = new String[]
{
"~/Views/{0}/{{1}}/{{0}}.aspx",
"~/Views/{0}/{{1}}/{{0}}.ascx",
"~/Views/{0}/{{1}}/{{0}}.cshtml",
"~/Views/{0}/Shared/{{0}}.aspx",
"~/Views/{0}/Shared/{{0}}.ascx",
"~/Views/{0}/Shared/{{0}}.cshtml"
};
public ModuleViewEngine(IModule module)
{
this.Module = module;
var formats = viewLocationFormats.Select(f => String.Format(f, module.Name)).ToArray();
this.ViewLocationFormats = formats;
this.PartialViewLocationFormats = formats;
this.AreaViewLocationFormats = formats;
this.AreaPartialViewLocationFormats = formats;
this.AreaMasterLocationFormats = formats;
}
public IModule Module { get; private set; }
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, String partialViewName, Boolean useCache)
{
var moduleName = controllerContext.RouteData.GetRequiredString("module");
if (moduleName.Equals(this.Module.Name, StringComparison.InvariantCultureIgnoreCase))
{
return base.FindPartialView(controllerContext, partialViewName, useCache);
}
else return new ViewEngineResult(new String[0]);
}
public override ViewEngineResult FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache)
{
var moduleName = controllerContext.RouteData.GetRequiredString("module");
if (moduleName.Equals(this.Module.Name, StringComparison.InvariantCultureIgnoreCase))
{
var baseResult = base.FindView(controllerContext, viewName, masterName, useCache);
return baseResult;
}
else return new ViewEngineResult(new String[0]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Bra*_*son 10
基于Update 2,我猜你所拥有的是一个显式加载的程序集副本(也就是说,它是通过除Load之外的其他方法加载的,比如LoadFrom).显式加载的程序集被放在一个特殊的位置,因为它们不允许满足隐式类型要求.Fusion(装配加载程序)的规则可能非常晦涩难懂.
我同意Matthew的评估,为了使这个工作,你的DLL将必须在/ bin中,否则它永远不能满足隐式类型要求.
导入的库不在/bin目录中,因此在尝试解析引用时不会进行探测.我发现了一篇我在MVC + MEF文章(第2部分)中发表的作品.基本上,您需要将扩展所在的目录添加到AppDomain的探测路径中.
基本上我在构建容器的地方:
/// <summary>
/// Creates the composition container.
/// </summary>
/// <returns></returns>
protected virtual CompositionContainer CreateCompositionContainer()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(MapPath("~/bin")));
var config = CompositionConfigurationSection.GetInstance();
if (config != null && config.Catalogs != null) {
config.Catalogs
.Cast<CatalogConfigurationElement>()
.ForEach(c =>
{
if (!string.IsNullOrEmpty(c.Path)) {
string path = c.Path;
if (path.StartsWith("~"))
path = MapPath(path);
foreach (var directoryCatalog in GetDirectoryCatalogs(path)) {
// Register our path for probing.
RegisterPath(directoryCatalog.FullPath);
// Add the catalog.
catalog.Catalogs.Add(directoryCatalog);
}
}
});
}
var provider = new DynamicInstantiationExportProvider();
var container = new CompositionContainer(catalog, provider);
provider.SourceProvider = container;
return container;
}
Run Code Online (Sandbox Code Playgroud)
我在当前域中注册目录的所有目录:
/// <summary>
/// Registers the specified path for probing.
/// </summary>
/// <param name="path">The probable path.</param>
private void RegisterPath(string path)
{
AppDomain.CurrentDomain.AppendPrivatePath(path);
}
Run Code Online (Sandbox Code Playgroud)
我相信同样适用于MVC3.
更新:如果我错了,请纠正我,但我不相信每次请求都会实例化一次ViewEngines,您创建一个向MVC注册的实例.因此,只有一个IModule实例与ViewEngine一起使用,所以如果路径不匹配,IModule.Name那么它将无法找到?那有意义吗?
| 归档时间: |
|
| 查看次数: |
4411 次 |
| 最近记录: |