Asp.net mvc 4 在渲染视图路径之前,从MVC控制器修改视图路径
在我的MVC4控制器中,我想重写View()方法 这样我就可以操纵由action方法呈现的视图。为此,我希望能够获得视图文件的物理路径。我尝试了以下方法:Asp.net mvc 4 在渲染视图路径之前,从MVC控制器修改视图路径,asp.net-mvc-4,Asp.net Mvc 4,在我的MVC4控制器中,我想重写View()方法 这样我就可以操纵由action方法呈现的视图。为此,我希望能够获得视图文件的物理路径。我尝试了以下方法: string viewName = this.ControllerContext.RouteData.Route .GetVirtualPath(this.ControllerContext.RequestContext, null) .VirtualPath; 例如,当我真正希望它返回的内容如下时,它可能会返回“/Errors
string viewName = this.ControllerContext.RouteData.Route
.GetVirtualPath(this.ControllerContext.RequestContext, null)
.VirtualPath;
例如,当我真正希望它返回的内容如下时,它可能会返回“/Errors/MissingParameters”:
"~/Views/Errors/MissingParameters"
"~/Areas/Surveys/Views/Errors/MissingParameters"
或者,更好的是:
"~/Views/Errors/MissingParameters.cshtml"
更复杂的是,我还需要它来处理区域,因此如果我在一个名为“Surveys”的区域中运行相同的示例,我希望它返回如下内容:
"~/Views/Errors/MissingParameters"
"~/Areas/Surveys/Views/Errors/MissingParameters"
我想这样做的原因是我正在尝试使用视图进行全球化,因此我可能有两种视图:
"~/Views/Errors/MissingParameters.cshtml" // default view (en-GB)
"~/Views/Errors/MissingParameters_de-DE.cshtml" // German view (de-DE)
我希望在引用它之前能够检查当前语言/文化的视图是否存在
任何建议都将不胜感激
谢谢。答案是从中复制的
如果您不介意将代码绑定到正在使用的特定视图引擎,您可以查看ViewContext.view属性并将其强制转换为WebFormView
var viewPath=((WebFormView)ViewContext.View).viewPath代码>
我相信这将在最后为您提供视图名称
编辑:哈克德是绝对正确的;为了使事情更整洁,我将逻辑封装在一个扩展方法中,如下所示:
public static class IViewExtensions {
public static string GetWebFormViewName(this IView view) {
if (view is WebFormView) {
string viewUrl = ((WebFormView)view).ViewPath;
string viewFileName = viewUrl.Substring(viewUrl.LastIndexOf('/'));
string viewFileNameWithoutExtension = Path.GetFileNameWithoutExtension(viewFileName);
return (viewFileNameWithoutExtension);
} else {
throw (new InvalidOperationException("This view is not a WebFormView"));
}
}
}
这似乎正是我想要的
另一个解决方案
((System.Web.Mvc.RazorView)htmlHelper.ViewContext.View).ViewPath
net mvc答案是从中复制的
如果您不介意将代码绑定到正在使用的特定视图引擎,您可以查看ViewContext.view属性并将其强制转换为WebFormView
var viewPath=((WebFormView)ViewContext.View).viewPath代码>
我相信这将在最后为您提供视图名称
编辑:哈克德是绝对正确的;为了使事情更整洁,我将逻辑封装在一个扩展方法中,如下所示:
public static class IViewExtensions {
public static string GetWebFormViewName(this IView view) {
if (view is WebFormView) {
string viewUrl = ((WebFormView)view).ViewPath;
string viewFileName = viewUrl.Substring(viewUrl.LastIndexOf('/'));
string viewFileNameWithoutExtension = Path.GetFileNameWithoutExtension(viewFileName);
return (viewFileNameWithoutExtension);
} else {
throw (new InvalidOperationException("This view is not a WebFormView"));
}
}
}
这似乎正是我想要的
另一个解决方案
((System.Web.Mvc.RazorView)htmlHelper.ViewContext.View).ViewPath
net mvc编辑:此部分不起作用或很难实现
您更希望使用一个操作过滤器,它可以让您在执行之前操纵结果
尤其需要一个结果过滤器。实现该方法,并在那里更改结果。尤其是在实现此方法时:
void OnResultExecuting(ResultExecutingContext filterContext)
您可以访问。此属性将包含您的视图。如果您将其强制转换为,您将有权访问视图名
,并且可以对其进行更改
如果您从未实现过筛选器,则这是一个。在本例中,它实现了另一种过滤器,但它是一样的
作为对OP注释的回答,ViewName
缺失,而View
仍然为空,这是非常正常的<代码>视图名称
只有在返回带有名称的视图时才会为空,如下所示:返回视图(“索引”)代码>。而且,ViewName
只是视图的一条路径,而不是视图的整个路径。所以这不是一个解决方案。因此,要使此解决方案起作用,您必须处理路由数据、控制器上下文等以找到视图。(更多信息请参见下文。)
编辑:解决方案,注册自定义视图引擎
当MVC必须呈现视图时,它从路由数据、控制器上下文、视图名称(如上所述,视图名称可以为空)以及应用的约定中获取信息
特别是,在MVC中,有一组注册的视图引擎,需要它们来查找调用那里的FindView()
方法的视图。视图引擎将返回一个ViewEngineResult
,其中包含找到的视图(如果找到了),或者返回一个查找视图失败的路径列表
因此,要修改模板路径,可以重写此功能:让原始类找到视图,如果找到,则修改路径
要做到这一点,您需要采取以下步骤:
继承您正在使用的视图引擎(我的sampel代码继承Razor视图引擎)
注册您的vie引擎,以便在原始视图引擎之前查询它(在我的示例代码中,我只需清除注册引擎列表,然后注册我的。原始列表包括razor和web表单视图引擎)
以下是继承视图引擎的代码:
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);
}
}
注1:此处阅读//此处修改
您可以修改结果的路径属性。查看
。将其转换为RazorView
:(result.View为RazorView)。ViewPath
。由于ViewPath
setter受到保护,您需要使用反射进行设置:您可以使用SetViewPath
方法进行设置
注2:如您所见,我不是继承了RazorViewEngine
,而是继承了FixedRazorViewEngine
。如果在MSDN中查找该类,则不会得到结果,但如果查看“已注册视图引擎”列表的原始内容,则会找到该类。我认为这取决于项目中安装的软件包,我认为它解决了MVC4中的一个bug。如果未在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());
}
注意:如果您在App\u Start
文件夹中创建了一个ViewEngineConfig
类,并调用该类的一个静态方法,就像对所有其他配置所做的那样,那么它会更干净。编辑:此部分不起作用或很难实现。
你会喜欢的
context.MapRoute(
name: "AreaName_default",
url: "{controller}/{action}/{id}",
namespaces: new[] { "SolutionName.AreaName.Controllers" }
);
return View("~/Areas/AreaName/Views/ControllerName/ViewName.cshtml", model);
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
string areaName = AreaNameAreaRegistration.PropoertyName;
if (filterContext.Result.GetType() == typeof(ViewResult) || filterContext.Result.GetType() == typeof(PartialViewResult))
{
dynamic viewResult = filterContext.Result;
string viewname = string.IsNullOrEmpty(viewResult.ViewName) ? Convert.ToString(filterContext.RouteData.Values["action"]) : viewResult.ViewName;
string folder = Convert.ToString(filterContext.RouteData.Values["controller"]);
string lateralHireAreaViewPath = $"~/Areas/{areaName}/Views/";
string extension = viewname.Contains(".cshtml") ? "" : ".cshtml";
viewResult.ViewName = string.Concat(lateralHireAreaViewPath, folder, "/", viewname, extension);
ViewEngineResult result = ViewEngines.Engines.FindView(filterContext.Controller.ControllerContext, viewResult.ViewName, null);
if (result.View == null)
{
//searched in shared folder
lateralHireAreaViewPath = string.Concat(lateralHireAreaViewPath, "Shared/");
viewResult.ViewName = string.Concat(lateralHireAreaViewPath, "/", viewname, extension);
}
}
}