如果没有一些关于我正在尝试做的事情的背景,这是一个很难问的问题。 我正在处理现有的多租户 ASP.NET MVC 3 应用程序(数据应用程序的典型表单),但现在必须为租户提供将自定义字段添加到任何页面的功能。 所有租户都有一组固定的页面,但他们可以在其中一个页面上的任意位置添加字段。 例如,在包含用于输入地址的字段的用户配置文件页面上,租户可能希望在"国家/地区"字段之前添加"县"字段。
每个租户的自定义字段的配置存储在数据库中,该数据库包含描述字段是什么(文本框、选择等)以及应呈现位置的信息,例如路由和应插入字段的 id。
由于这是一个现有的应用程序,我有一些限制,并希望将所有现有的.cshtml视图保留为所有租户的默认/基础。 为了将特定于租户的字段添加到页面,我创建了一个自定义 VirtualPathProvider,该提供程序:
- 从标准视图目录加载 .cshtm 文件中定义的标准视图
- 从数据库加载视图的自定义字段定义(特定于发出请求的租户)
- 为每个自定义字段创建 Razor 标记,并将其插入到步骤 1 中的加载视图中
- 返回现在同时具有基代码和租户特定代码的组合视图
该设计适用于视图的第一个请求,但是,来自任何租户的后续请求仅返回第一个版本。 我很确定这里发生的事情是 ASP.NET 运行时正在编译和缓存视图,因此对视图的下一个请求刚刚从缓存中出来。
所以最后的问题。 如何覆盖编译和缓存,以便可以包含类似租户 id 的内容,以便每个租户缓存一次每个视图?
我发现你可以覆盖VirtualPathProviders的GetCacheKey方法来实现你自己的密钥模式。 在我的情况下,将租户的密钥添加到缓存密钥的末尾,如下所示:
public override string GetCacheKey(string virtualPath)
{
var tenantKey = getTenantKey();
if (VirtualPathHelper.SupportsCustomFields(virtualPath))
{
return string.Join("_", virtualPath, tenantKey);
}
return base.GetCacheKey(virtualPath);
}
在"ASP.NET Internet 临时文件"目录中,该视图的文件名为:_views_home_index.cshtml_a7c1a66a-ebe4-4ca2-8dc4-7a22b460f368.compile
请求视图的每个租户现在都将获得自己的版本。