未找到部分视图时故障转移到备用视图?

Nic*_*cht 5 asp.net-mvc partial-views viewengine razor

我有一个MVC应用程序,它使用从父对象类型继承的动态业务对象.例如,基类Client可能有两个子类调用VendorServiceProvider,而这些都是由同一个控制器来处理.我有一个部分视图,我在查看客户端的详细信息时加载到页面的右侧_Aside.cshtml.当我加载客户端时,我首先尝试寻找一个特定的Aside,然后我加载了一个通用的.下面是代码的样子.

@try
{
    @Html.Partial("_" + Model.Type.TypeName + "Aside")
}
catch (InvalidOperationException ex)
{
    @Html.Partial("_Aside")
}
Run Code Online (Sandbox Code Playgroud)

TypeName属性中包含"Vendor"或"ServiceProvider".

现在这个工作正常,但问题是我只希望它在未找到视图时进行故障转移,当InvalidOperationException部分视图实际抛出时(通常是它可能调用的子操作的结果),它也会失败.我想过要检查,Exception.Message但这看起来有点hackish.有没有其他方法我可以得到所需的结果,而无需检查Message属性或这是我唯一的选择吗?

ex.Message = "The partial view '_ServiceProviderAside' was not found or no view
              engine supports the searched locations. The following locations were
              searched: (... etc)"
Run Code Online (Sandbox Code Playgroud)

更新:这是根据杰克的回答,我目前在我的项目中使用扩展方法的类,以及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);
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:如果您正在使用ASP.NET Core MVC,请交换PartialExists()这三种方法的方法,并在其他方法中更改HtmlHelperfor的所有用法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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在我看来...

@Html.OptionalPartial("_" + Model.Type.TypeName + "Aside", "_Aside")
//or
@Html.OptionalPartial("_" + Model.Type.TypeName + "Aside", "_Aside", Model.AsideViewModel)
Run Code Online (Sandbox Code Playgroud)

Cha*_*hao 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这将我最常见的用例带入扩展方法,有助于保持视图更清晰,添加RenderPartials是为了完整性.


小智 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);
 }
Run Code Online (Sandbox Code Playgroud)

有关 ASP MVC 3 的 FindPartialView 方法的信息