我有一个MVC应用程序,它使用从父对象类型继承的动态业务对象。例如,基类Client
可能有两个名为Vendor
和ServiceProvider
的子类,这些子类都由同一个控制器处理。我有一个部分视图,我在查看客户端的详细信息_Aside.cshtml
时加载到页面的右侧。当我加载客户端时,我首先尝试寻找一个特定的Aside,然后我加载了一个通用的。下面是代码的样子。
@try
{
@Html.Partial("_" + Model.Type.TypeName + "Aside")
}
catch (InvalidOperationException ex)
{
@Html.Partial("_Aside")
}
TypeName属性中包含“Vendor”或“ServiceProvider”一词。
现在这个工作正常,但问题是我只希望它在找不到视图时进行故障转移,当部分视图抛出实际的InvalidOperationException
时它也会失败 - 通常是一个结果它可能会打电话的儿童行动)。我考虑过对Exception.Message
进行检查,但这似乎有些过时。有没有其他方法可以在不必检查Message
属性的情况下获得所需结果,或者这是我此时唯一的选择?
ex.Message = "The partial view '_ServiceProviderAside' was not found or no view
engine supports the searched locations. The following locations were
searched: (... etc)"
更新:根据杰克的回答,这是我目前在项目中使用的扩展方法的类,以及Chao的建议。
//For ASP.NET MVC
public static class ViewExtensionMethods
{
public static bool PartialExists(this HtmlHelper helper, string viewName)
{
if (string.IsNullOrEmpty(viewName)) throw new ArgumentNullException(viewName, "View name cannot be empty");
var view = ViewEngines.Engines.FindPartialView(helper.ViewContext, viewName);
return view.View != null;
}
public static bool PartialExists(this ControllerContext controllerContext, string viewName)
{
if (string.IsNullOrEmpty(viewName)) throw new ArgumentNullException(viewName, "View name cannot be empty");
var view = ViewEngines.Engines.FindPartialView(controllerContext, viewName);
return view.View != null;
}
public static MvcHtmlString OptionalPartial(this HtmlHelper helper, string viewName)
{
return PartialExists(helper, viewName) ? helper.Partial(viewName) : HtmlString.Empty;
}
public static MvcHtmlString OptionalPartial(this HtmlHelper helper, string viewName, string fallbackViewName)
{
return OptionalPartial(helper, viewName, fallbackViewName, null);
}
public static MvcHtmlString OptionalPartial(this HtmlHelper helper, string viewName, object model)
{
return PartialExists(helper, viewName) ? helper.Partial(viewName, model) : MvcHtmlString.Empty;
}
public static MvcHtmlString OptionalPartial(this HtmlHelper helper, string viewName, string fallbackViewName, object model)
{
return helper.Partial(PartialExists(helper, viewName) ? viewName : fallbackViewName, model);
}
public static void RenderOptionalPartial(this HtmlHelper helper, string viewName)
{
if (PartialExists(helper, viewName))
{
helper.RenderPartial(viewName);
}
}
public static void RenderOptionalPartial(this HtmlHelper helper, string viewName, string fallbackViewName)
{
helper.RenderPartial(PartialExists(helper, viewName) ? viewName : fallbackViewName);
}
}
更新:如果您正在使用ASP.NET Core MVC,请为这三种方法交换PartialExists()
方法,并更改HtmlHelper
的所有用法其他方法中IHtmlHelper
。如果您不使用ASP.NET Core
//For ASP.NET Core MVC
public static class ViewExtensionMethods
{
public static bool PartialExists(this IHtmlHelper helper, string viewName)
{
var viewEngine = helper.ViewContext.HttpContext.RequestServices.GetService<ICompositeViewEngine>();
if (string.IsNullOrEmpty(viewName)) throw new ArgumentNullException(viewName, "View name cannot be empty");
var view = viewEngine.FindView(helper.ViewContext, viewName, false);
return view.View != null;
}
public static bool PartialExists(this ControllerContext controllerContext, string viewName)
{
var viewEngine = controllerContext.HttpContext.RequestServices.GetService<ICompositeViewEngine>();
if (string.IsNullOrEmpty(viewName)) throw new ArgumentNullException(viewName, "View name cannot be empty");
var view = viewEngine.FindView(controllerContext, viewName, false);
return view.View != null;
}
public static bool PartialExists(this ViewContext viewContext, string viewName)
{
var viewEngine = viewContext.HttpContext.RequestServices.GetService<ICompositeViewEngine>();
if (string.IsNullOrEmpty(viewName)) throw new ArgumentNullException(viewName, "View name cannot be empty");
var view = viewEngine.FindView(viewContext, viewName, false);
return view.View != null;
}
}
在我看来......
@Html.OptionalPartial("_" + Model.Type.TypeName + "Aside", "_Aside")
//or
@Html.OptionalPartial("_" + Model.Type.TypeName + "Aside", "_Aside", Model.AsideViewModel)
答案 0 :(得分:5)
在尝试解决嵌套部分的问题时遇到了这个答案,因为我想在中间视图中包含样式和脚本。我最终决定最简单的方法是templatename_scripts
和templatename_styles
的惯例。
所以,只是在这里添加各种选项就是我在此基础上使用的。
public static class OptionalPartialExtensions
{
public static MvcHtmlString OptionalPartial(this HtmlHelper helper, string viewName)
{
return PartialExists(helper, viewName) ? helper.Partial(viewName) : MvcHtmlString.Empty;
}
public static MvcHtmlString OptionalPartial(this HtmlHelper helper, string viewName, string fallbackViewName)
{
return helper.Partial(PartialExists(helper, viewName) ? viewName : fallbackViewName);
}
public static void RenderOptionalPartial(this HtmlHelper helper, string viewName)
{
if (PartialExists(helper, viewName))
{
helper.RenderPartial(viewName);
}
}
public static void RenderOptionalPartial(this HtmlHelper helper, string viewName, string fallbackViewName)
{
helper.RenderPartial(PartialExists(helper, viewName) ? viewName : fallbackViewName);
}
public static bool PartialExists(this HtmlHelper helper, string viewName)
{
if (string.IsNullOrEmpty(viewName))
{
throw new ArgumentNullException(viewName, "View name cannot be empty");
}
var view = ViewEngines.Engines.FindPartialView(helper.ViewContext, viewName);
return view.View != null;
}
}
这将我最常见的用例带入扩展方法,有助于保持视图更清晰,添加RenderPartials是为了完整性。
答案 1 :(得分:3)
我有类似的要求。我希望保持视图标记更清晰,同时避免生成动态视图名称两次。这就是我提出的(修改后与您的示例匹配):
助手扩展:
public static string FindPartial(this HtmlHelper html, string typeName)
{
// If you wanted to keep it in the view, you could move this concatenation out:
string viewName = "_" + typeName + "Aside";
ViewEngineResult result = ViewEngines.Engines.FindPartialView(html.ViewContext, viewName);
if (result.View != null)
return viewName;
return "_Aside";
}
查看:
@Html.Partial(Html.FindPartial(Model.Type.TypeName))
或访问部分内的模型:
@Html.Partial(Html.FindPartial(Model.Type.TypeName), Model)
答案 2 :(得分:1)
您可以尝试使用FindPartialView方法检查视图是否存在。沿着这些方向的东西可能有效(未经测试):
public bool DoesViewExist(string name)
{
string viewName = "_" + Model.Type.TypeName + "Aside";
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName , null);
return (viewResult.View != null);
}
答案 3 :(得分:0)
错误修复以处理null viewName或null fallbackViewName(替换OP中的相应代码):
public static MvcHtmlString OptionalPartial(this HtmlHelper helper, string viewName, string fallbackViewName, object model)
{
string partialToRender = null;
if (viewName != null && PartialExists(helper, viewName))
{
partialToRender = viewName;
}
else if (fallbackViewName != null && PartialExists(helper, fallbackViewName))
{
partialToRender = fallbackViewName;
}
if (partialToRender != null)
{
return helper.Partial(partialToRender, model);
}
else
{
return MvcHtmlString.Empty;
}
}
我已经编辑了OP的代码(它结合了多个答案的代码),但我的编辑正在等待同行评审。