Asp.Net Core MVC 中的 IViewLocationExpander.PopulateValues() 是啥

Posted

技术标签:

【中文标题】Asp.Net Core MVC 中的 IViewLocationExpander.PopulateValues() 是啥【英文标题】:What is IViewLocationExpander.PopulateValues() for in Asp.Net Core MVCAsp.Net Core MVC 中的 IViewLocationExpander.PopulateValues() 是什么 【发布时间】:2016-04-22 20:19:17 【问题描述】:

我正在使用 ASP.NET MVC CORE。我已经实现了自己的 ViewLocationExpander,这样我就可以按照我想要的方式构建我的项目,并将我的视图放置在我喜欢的地方。

这是通过实现一个继承自IViewLocationExpander的类来完成的,大部分工作发生在以下方法中:

ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)

一切都很顺利,但接口定义了第二个方法,我不知道如何正确实现:

PopulateValues(ViewLocationExpanderContext context)

我在整个互联网上阅读过有关此接口的文章,但除了模糊地说明它如何帮助缓存之外,没有人真正提供有关此方法的确切用途的大量信息。

如果有人能解释框架如何使用此方法以及我如何适当地使用它来帮助缓存(如果这确实是它的用途),我将不胜感激。

【问题讨论】:

【参考方案1】:

也许直接从GitHub MVC issue 获取的以下附加信息可以回答您的问题:

缓存在其查找中包含Values 字典。除非PopulateValues() 方法向ViewLocationExpanderContext.Values 添加不同的信息,否则ExpandViewLocations() 方法将在每个原始文件名中调用一次,即从那时起缓存初始信息。

最重要的是,OP 提出的特定示例可以帮助更好地理解,至少这就是发生在我身上的事情:

他的项目在两个不同的目录下有同名的视图 树(比如FooBar) 根据当前操作上下文提取的一些数据,要定位的视图应位于这些树中的任意一棵树下

如果PopulateValues() 中没有任何代码,视图引擎将要求一次 定位视图,然后使用视图“标准”数据(例如ControllerNameActionNameArea 等.) 以缓存找到视图的实际位置。

因此,在 OP 情况下,一旦缓存了视图位置(例如,来自Foo 目录树),每次需要同名视图时,它将始终来自该树,将无法检测是否另一棵 Bar 树上的那棵应该已经被捡起来了。

OP 的唯一方法是通过向 Values 字典添加特定的、独特的视图详细信息来自定义 PopulateValues():在当前场景中,这些是从当前操作上下文中提取的信息。

这些附加信息有两个用途:ExpandViewLocations() 可能会在调用时使用它们以确定正确的位置,而视图引擎将在找到后使用它们来缓存视图位置。

十二月。 2021年更新

官方doc page更具描述性。来自备注部分:

单独的 IViewLocationExpander 分两步调用: (1) PopulateValues(ViewLocationExpanderContext) 被调用并且每个扩展器添加它稍后将作为ExpandViewLocations(ViewLocationExpanderContext, IEnumerable&lt;String&gt;) 的一部分使用的值。填充的值用于确定缓存键 - 如果所有值与上次调用 PopulateValues(ViewLocationExpanderContext) 时相同,则将缓存结果用作视图位置。 (2) 如果在缓存中没有找到结果,或者在缓存位置没有找到视图,则调用ExpandViewLocations(ViewLocationExpanderContext, IEnumerable&lt;String&gt;) 来确定视图的所有潜在路径。

【讨论】:

谢谢!这正是我 6 个多月以来一直想学习的信息!这些信息需要更好地在网络上公布。干得好! 感谢您,因为我也有机会弄清楚这一点。顺便说一句,我同意需要改进那部分文档 更新:我实际上注意到官方doc page 现在更具描述性:填充的值用于确定缓存键 - 如果所有值与上次相同的话 PopulateValues(ViewLocationExpanderContext)被调用,缓存的结果被用作视图位置。 建立一个多租户网站,就在这里救了我的培根。 趁着这个评论更新doc page的链接(今天上面那个已经坏了)【参考方案2】:

基本上,该方法可以将值填充到 context.Values 中,这些值稍后将用于确定是否应使用缓存列表或是否将调用 ExpandViewLocations....

【讨论】:

你能再解释一下吗?当您说“稍后将用于确定是否应使用缓存列表”时,它是如何工作的?我需要在context.Values[key] 中使用什么键才能使用缓存值?该值需要采用什么格式?【参考方案3】:

没有弄乱它,无法给你一个具体的答案,但请查看 ASP.NET MVC GitHub 存储库上的 IViewLocationExpander.PopulateValues(ViewLocationExpanderContext context)

public interface IViewLocationExpander

    /// <summary>
    /// Invoked by a <see cref="RazorViewEngine"/> to determine the values that would be consumed by this instance
    /// of <see cref="IViewLocationExpander"/>. The calculated values are used to determine if the view location
    /// has changed since the last time it was located.
    /// </summary>
    /// <param name="context">The <see cref="ViewLocationExpanderContext"/> for the current view location
    /// expansion operation.</param>
    void PopulateValues(ViewLocationExpanderContext context);

    // ...other method declarations omitted for brevity

可读性格式:

“由RazorViewEngine 调用以确定IViewLocationExpander 的此实例将使用的值。计算的值用于确定视图位置自上次定位以来是否已更改。

参数:

context:当前视图位置扩展操作的ViewLocationExpanderContext。"

我查看了一些实现此接口的类 - 一些声明了该方法但将其留空,另一些则实现了它。

NonMainPageViewLocationExpander.cs:

public void PopulateValues(ViewLocationExpanderContext context)


LanguageViewLocationExpander.cs:

private const string ValueKey = "language";

public void PopulateValues(ViewLocationExpanderContext context)

    if (context == null)
    
        throw new ArgumentNullException(nameof(context));
    

    // Using CurrentUICulture so it loads the locale specific resources for the views.
#if NET451
    context.Values[ValueKey] = Thread.CurrentThread.CurrentUICulture.Name;
#else
    context.Values[ValueKey] = CultureInfo.CurrentUICulture.Name;
#endif

文章"View Location Expander in ASP.NET Core and MVC 6" 提供了一个示例。以下是解释的摘录:

您可以根据需要添加任意数量的视图位置扩展器。 IViewLocationExpander 接口有 2 个方法,PopulateValuesExpandViewLocationsPopulateValues 方法允许您添加以后可以由 ExpandViewLocations 方法使用的值。您在PopulateValues 方法中输入的值将用于查找缓存键。 ExpandViewLocations 方法只会在没有缓存键的缓存结果或框架无法在缓存结果中找到视图时调用。在ExpandViewLocations 方法中,您可以返回动态视图位置。现在您可以在Startup.cs 文件中注册此视图位置扩展器,

services.Configure<RazorViewEngineOptions>(options =>

    options.ViewLocationExpanders.Add(new MyViewLocationExpander());
);

【讨论】:

这很有帮助,但我仍然不明白如果我已实施 ExpandViewLocations 以提供自定义位置来搜索视图,我应该在 PopulateValues 中实施什么。想法? 我还没有弄乱它,无法给你一个明确的答案。但是,我为您提供了实现和不实现该方法的类的示例,并附上了一篇 weblogs.asp.net 文章的摘录。我认为将所有信息放在一起可以让您(粗略地)了解事情的运作方式。 我感谢您提供的信息以及因此的支持,但最终我需要有人回答这部分:如果有人能解释框架如何使用此方法以及我如何能如果确实是这样,请适当地使用它来帮助缓存。 我认为这在“您在PopulateValues 方法中输入的值将用于查找缓存键。ExpandViewLocations 方法将仅在没有缓存结果的情况下调用缓存关键或当框架无法从附加的摘录中找到缓存结果中的视图时——更详尽的示例会很有用。 它确实无法找到答案,但是在广泛研究了您引用的文章和代码示例之后,仍然不清楚如何利用 PopulateValues 来帮助框架使用缓存值而不是需要再次致电ExpandViewLocations

以上是关于Asp.Net Core MVC 中的 IViewLocationExpander.PopulateValues() 是啥的主要内容,如果未能解决你的问题,请参考以下文章

Asp.Net Core MVC 中的 IViewLocationExpander.PopulateValues() 是啥

我想更改 ASP.NET Core 5 MVC 中的路径

[十] ASP.NET Core MVC 中的路由

数据存储到 ASP.NET Core 5 MVC 中的关联表

EF Core 中的 ASP.NET Core 5 MVC 和 Identity - 基于资源的授权

等效于 ASP.NET Core MVC 中的“@section”?