IMemoryCache保证的唯一新密钥.NET-Core

Gui*_*uid 5 c# asp.net-mvc caching .net-core

我正在尝试使用Microsoft.Extensions.Caching.Memory.IMemoryCache接口/类。

我需要向缓存中添加一个新项目,并确保我不覆盖已保存的其他任何内容。目前,所有密钥都是自动生成并随机分配的(不是顺序的)。

如何针对我当前的缓存项目测试随机密钥的唯一性?

或者,如何获得保证的唯一密钥?可以将自动生成的密钥用于以后的检索是可以的。

https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/memory有一些示例,但是对于我生成的用于测试唯一性的每个密钥使用.TryGetValue(对象密钥,对象出值)似乎是过度杀伤,并且在考虑多线程环境时,这可能是一个问题。

博客https://wildermuth.com/2016/04/14/Using-Cache-in-ASP-NET-Core-1-0-RC1将相同的TryGetValue(key,out value)模式用于故意的Keys。

我希望不必将生成的密钥列表保留在其他位置,即另一个列表分隔的列表,因为这会使我回到在列表变旧时修剪列表的问题。

另外,在这种特定情况下,我将密钥作为url-querystring参数传递,因此与url兼容的字符串将是超级。提前致谢。

Nig*_*888 4

正如您已经发现的那样,使用 GUID 作为缓存键并不是一个好的解决方案。主要问题是,生成 GUID 后,无法可靠地将其重新生成为相同的密钥,以便从缓存中获取数据。


通常,当我创建缓存时,键基于被缓存的实体或缓存它的方法。但也可以基于值的组合来制作缓存,这些值一起使值变得唯一。

使用实体的示例

public class Employee
{
    int Id { get; set; }
    string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

要从实体获取键,除了实体的主键之外,我们只需使用常量值。

private const string KEY_PREFIX = "Employee_";
private object syncLock = new object();

// innerEmployeeRetriever and cache are populated through the constructor
public Employee GetEmployee(int id)
{
    string key = KEY_PREFIX + id.ToString();

    // Get the employee from the cache
    var employee = cache[key];
    if (employee == null)
    {
        lock (syncLock)
        {
            // Double-check that another thread didn't beat us
            // to populating the cache
            var employee = cache[key];
            if (employee == null)
            {
                employee = innerEmployeeRetriever.GetEmployee(id);
                cache[key] = employee;
            }
        }
    }
    return employee;
}
Run Code Online (Sandbox Code Playgroud)

使用方法名称的示例

private object syncLock = new object();

// innerEmployeeRetriever and cache are populated through the constructor
public Employee GetEmployeeList()
{
    string key = "GetEmployeeList";

    // Get the employee from the cache
    var employees = cache[key];
    if (employees == null)
    {
        lock (syncLock)
        {
            // Double-check that another thread didn't beat us
            // to populating the cache
            var employees = cache[key];
            if (employees == null)
            {
                employees = innerEmployeeRetriever.GetEmployeeList();
                cache[key] = employees;
            }
        }
    }
    return employees;
}
Run Code Online (Sandbox Code Playgroud)

使用值组合的示例

您还可以从多个不同的值构建键,这些值的组合使实体独一无二。如果您没有可使用的主键或者您想要单独缓存多个不同的上下文,这会很有帮助。这个例子取自MvcSiteMapProvider

protected string GetCacheKey(string memberName)
{
    // NOTE: We must include IsReadOnly in the request cache key 
    // because we may have a different 
    // result when the sitemap is being constructed than when 
    // it is being read by the presentation layer.
    return "__MVCSITEMAPNODE_" + this.SiteMap.CacheKey + "_" + this.Key 
        + "_" + memberName + "_" + this.IsReadOnly.ToString() + "_";
}
Run Code Online (Sandbox Code Playgroud)

在本例中,我们根据节点所属父 SiteMap 的唯一键、节点的唯一键、方法或属性名称以及当前是否设置了只读标志来构建键。这些值的每个唯一集合都会产生一个单独的缓存键,为每个组合创建一个单独的缓存。

当然,为了使其正常工作,值之间应该有某种“安全”分隔符,以防止通过连接不同的值来创建相同的键。例如,"1" + "23"与 是相同的字符串"12" + "3",但您可以通过使用下划线、竖线字符、逗号或其他不在数据本身中的分隔符来分隔值("1" + "_" + "23"不是相同的字符串) ,以防止此类冲突作为"12" + "_" + "3")。


最重要的是,缓存键必须以某种方式表示缓存中的内容才能发挥作用。您的应用程序应该了解如何提供构成密钥的数据,以便在需要再次检索相同数据时可以重新创建密钥。