如何检查 ViewComponent 视图是不是存在?

Posted

技术标签:

【中文标题】如何检查 ViewComponent 视图是不是存在?【英文标题】:How to check whether ViewComponent View exists?如何检查 ViewComponent 视图是否存在? 【发布时间】:2021-09-23 06:29:15 【问题描述】:

有没有办法在尝试渲染之前检查 ViewComponent 的 View 是否真的存在?

我知道有 FindViewGetView 方法可用于搜索视图,例如控制器,我正在为 ViewComponents 寻找类似的东西。

ViewComponent 内部,有一个 ViewEngine,但是当我尝试使用它时...

ViewEngine.FindView(ViewContext, "SomeView", false);

... 结果的 SearchedLocations 不是在寻找 ViewComponents:

[0]: "/Views/Home/SomeView.en-US.cshtml"
[1]: "/Views/Home/SomeView.en.cshtml"
[2]: "/Views/Home/SomeView.cshtml"
[3]: "/Views/Shared/SomeView.en-US.cshtml"
[4]: "/Views/Shared/SomeView.en.cshtml"
[5]: "/Views/Shared/SomeView.cshtml"
[6]: "/Pages/Shared/SomeView.en-US.cshtml"
[7]: "/Pages/Shared/SomeView.en.cshtml"
[8]: "/Pages/Shared/SomeView.cshtml"

注意: 问这个问题是因为 try-catch 块没有捕捉到缺少视图时发生的异常,例如...

public IViewComponentResult Invoke()
      
    try
    
        return View();
    
    catch (Exception e)
    
        return Content(string.Empty);
    

...由于缺少视图文件,会导致未处理的异常。

【问题讨论】:

【参考方案1】:

如您所见hereViewComponentResult.ViewComponent 方法使用在类顶部声明的硬编码值构建所需视图的路径。 所以在内部,对ViewEngine.FindView 的调用是通过将所需视图的相对路径作为视图名称传递的,即Components/ComponentName/ViewName。然后,视图引擎使用您在示例中看到的路径作为基础搜索此路径。

要回答你的问题,你应该编辑你的代码来做同样的事情,所以它应该是

ViewEngine.FindView(ViewContext, "Components/ViewComponentName/SomeView", false);

Example 用于放置在/Views/Shared/Components/Navigation/Default.cshtml 中的视图。

【讨论】:

你说的是真的,但是......我一直在使用上面的代码和 View("SomeView") 并检查路径 Components/ViewComponentName/ 路径,因为 ViewComponents 检查默认值路径也是如此。对我来说奇怪的是 ViewEngine.FindView 根本不检查该路径。 此外,由于我已经扩展了视图引擎的视图搜索路径(将一些视图文件存储在实际项目之外)并且渲染这些视图没有问题,我正在寻找类似的FindView 的解决方案。如果没有其他方法可以像上面显示的那样定义路径,我想我必须对每个 ViewComponent 进行硬编码。 您是否尝试过使用services.Configure<RazorViewEngineOptions>(...来配置引擎的搜索路径行为? 我做到了,而且效果很好。就像我说的,我使用 View("SomeView") 为 ViewComponent 渲染视图没有问题,因为我已经扩展了搜索引擎的搜索路径。对我来说唯一的问题是 ViewEngine.FindView 似乎忽略了该配置,因此我必须在路径中使用“Components/ViewComponentName/”。这不是一个大问题,但它不是动态的,我必须用硬编码的字符串来包装它。 对不起,我不明白你已经这样做了。无论如何,我认为鉴于这种情况,至少对路径的Components/ 部分进行硬编码是不可避免的,因为 AspNetCore 自己会这样做。但是为了避免每次都写组件的名称,我认为您可以创建一个继承自 ViewComponentBaseViewComponent 类,并在创建新的 ViewComponent 时将其子类化。在那里,您可以创建一个方便的方法,该方法自动构建到 Components/Component Name/ 文件夹的路径并使用构建的路径调用 ViewEngine.FindView【参考方案2】:

您可以将IViewComponentSelector 注入您的控制器以检查组件是否存在:

控制器:

private readonly IViewComponentSelector _selector;
        public HomeController(IViewComponentSelector selector)
        
            _selector = selector;
        
public IActionResult Index()
        
            if (_selector.SelectComponent("CheckBox1") != null)
            
                return Ok("exist");
            
            else 
            
                return Ok("Not Found");
            
        

结果(ViewComponent 名称为 CheckBox):

【讨论】:

以上是关于如何检查 ViewComponent 视图是不是存在?的主要内容,如果未能解决你的问题,请参考以下文章

在视图上自动更新 ViewComponent

[Asp.Net Core]视图组件扩展定制

[Asp.Net Core]视图组件扩展定制

.NET CORE 从控制器调用 ViewComponent

MVC+EFCore 完整教程18 -- 升级分布视图至 View Component

将 Viewcomponent 与 Rspec 集成