在我的MVC 4 Controller中,我想重写View()方法
ViewResult View(string viewName, string masterName, object model) {}
Run Code Online (Sandbox Code Playgroud)
这样我就可以操纵由action方法渲染的视图。为此,我希望能够获取视图文件的物理路径。我尝试了以下方法:
string viewName = this.ControllerContext.RouteData.Route
.GetVirtualPath(this.ControllerContext.RequestContext, null)
.VirtualPath;
Run Code Online (Sandbox Code Playgroud)
例如,当我真正希望它返回的内容是这样时,它可能返回“ / Errors / MissingParameters”:
"~/Views/Errors/MissingParameters"
Run Code Online (Sandbox Code Playgroud)
或者,甚至更好:
"~/Views/Errors/MissingParameters.cshtml"
Run Code Online (Sandbox Code Playgroud)
为了增加复杂性,我还需要它来应对Areas,因此,如果我在名为“ Surveys”的Area中运行了相同的示例,则希望它返回类似以下内容的内容:
"~/Areas/Surveys/Views/Errors/MissingParameters"
Run Code Online (Sandbox Code Playgroud)
我要这样做的原因是我正在尝试使用视图进行全球化,因此我可能有两个视图:
"~/Views/Errors/MissingParameters.cshtml" // default view (en-GB)
"~/Views/Errors/MissingParameters_de-DE.cshtml" // German view (de-DE)
Run Code Online (Sandbox Code Playgroud)
并且我希望能够在引用该语言/文化之前检查该视图是否存在。
任何建议将不胜感激。
谢谢。
编辑:这部分将无法工作或难以实施
您宁愿使用动作过滤器,该过滤器将让您Result
在执行之前进行操作。
特别是您需要一个结果过滤器。实现IResultFilter.onResultExecuting方法,并在那里更改结果。特别是在实现此方法时:
void OnResultExecuting(ResultExecutingContext filterContext)
Run Code Online (Sandbox Code Playgroud)
您可以访问ResultExecutingContext.Result属性。此属性将包含您的视图。如果将其强制转换为System.Web.Mvc.ViewResultBase,则可以访问,ViewName
并且可以对其进行更改。
如果您从未实现过过滤器,那么这是一个很好的实验主题。在这种情况下,它实现了另一种过滤器,但它是相同的。
作为对OP注释的回答,完全正常的ViewName
是缺少它,并且View
仍然为null。ViewName
不会是空的只有该视图返回与名称,像这样的情况:return View("Index");
。而且,那ViewName
将是公正的,而不是观点的全部路径。因此,这不是解决方案。因此,要使该解决方案有效,您必须处理路径数据,控制器上下文等才能找到视图。(有关此内容,请参见下文。)
编辑:解决方案,注册自定义视图引擎
当MVC必须渲染视图时,它会从路由数据,控制器上下文,视图名称(如上所述,可以为空)和适用的约定中获取信息。
特别是,在MVC中,有一组注册的视图引擎,它们需要找到调用该FindView()
方法的视图。如果找到了视图引擎,则视图引擎将返回ViewEngineResult
具有找到的视图的,或未成功找到该视图的路径列表。
因此,要修改模板路径,您可以覆盖此功能:让原始类找到视图,如果找到,则修改路径。
要显示您需要执行以下步骤:
这是继承的视图引擎的代码:
public class CustomRazorViewEngine : FixedRazorViewEngine
{
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
ViewEngineResult result
= base.FindView(controllerContext, viewName, masterName, useCache);
if (result.View != null)
{
// Modify here !!
}
return result;
}
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
ViewEngineResult result
= base.FindPartialView(controllerContext, partialViewName, useCache);
if (result.View != null)
{
// Modify here !!
}
return result;
}
static readonly PropertyInfo ViewPathProp
= typeof(RazorView).GetProperty("ViewPath");
public void SetViewPath(RazorView view, string path)
{
ViewPathProp.SetValue(view, path);
}
}
Run Code Online (Sandbox Code Playgroud)
注意1:在阅读位置,// Modify here !!
您可以修改的path属性result.View
。投放到RazorView
:(result.View as RazorView).ViewPath
。由于ViewPath
设置器受到保护,因此您需要使用Reflection进行设置:您可以SetViewPath
为此使用方法。
注意2:如您所见,我不是继承RazorViewEngine
而是FixedRazorViewEngine
。如果您在MSDN中寻找此类,则不会得到任何结果,但是,如果您查看已注册的视图引擎列表的原始内容,则会找到该类。我认为这取决于项目中已安装的软件包,并且它解决了MVC4中的错误。如果您不在Microsoft.Web.Mvc
名称空间中查找它,则继承原始RazorViewEngined
注意3:找到视图后,视图引擎将使用来执行该视图ViewEngineResult
,因此,如果您对其进行更改,它将使用新的视图路径来执行
最后,您需要在global.asax
应用程序启动事件中更改已注册引擎的列表,如下所示:
protected void Application_Start()
{
// Original content:
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Added content:
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomRazorViewEngine());
}
Run Code Online (Sandbox Code Playgroud)
注意:如果您ViewEngineConfig
在App_Start
文件夹中创建了一个类,并调用了该类的静态方法,就像使用所有其他配置一样,这样做会更干净。