Dynamics CRM Online 对象缓存未正确缓存

noo*_*bie 4 c# dynamics-crm dynamics-crm-2011 dynamics-crm-online dynamics-crm-2013

我有一个要求,我们需要一个插件来从外部系统检索会话 ID 并将其缓存一段时间。我使用实体上的字段来测试会话是否确实被缓存。当我刷新 CRM 表单几次时,从输出来看,同一密钥似乎有四个版本(在任何时候都是一致的)。我尝试清除缓存并再次测试,但结果仍然相同。

任何帮助表示感谢,提前致谢。

每次刷新页面时的输出:

20170511_125342:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0

20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0

20170511_125410:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0

20170511_125342:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0

20170511_125437:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0

20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0

20170511_125358:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0

20170511_125437:1:55a4f7e6-a1d7-e611-8100-c4346bc582c0

为了实现这一点,我实现了以下代码:

public class SessionPlugin : IPlugin
{
    public static readonly ObjectCache Cache = MemoryCache.Default;
    private static readonly string _sessionField = "new_sessionid";
    #endregion

    public void Execute(IServiceProvider serviceProvider)
    {
        var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

        try
        {
            if (context.MessageName.ToLower() != "retrieve" && context.Stage != 40)
                return;

            var userId = context.InitiatingUserId.ToString();

            // Use the userid as key for the cache
            var sessionId = CacheSessionId(userId, GetSessionId(userId));
            sessionId = $"{sessionId}:{Cache.Select(kvp => kvp.Key == userId).ToList().Count}:{userId}";

            // Assign session id to entity
            var entity = (Entity)context.OutputParameters["BusinessEntity"];

            if (entity.Contains(_sessionField))
                entity[_sessionField] = sessionId;
            else
                entity.Attributes.Add(new KeyValuePair<string, object>(_sessionField, sessionId));
        }
        catch (Exception e)
        {
            throw new InvalidPluginExecutionException(e.Message);
        }
    }

    private string CacheSessionId(string key, string sessionId)
    {
        // If value is in cache, return it
        if (Cache.Contains(key))
            return Cache.Get(key).ToString();

        var cacheItemPolicy = new CacheItemPolicy()
        {
            AbsoluteExpiration = ObjectCache.InfiniteAbsoluteExpiration,
            Priority = CacheItemPriority.Default
        };

        Cache.Add(key, sessionId, cacheItemPolicy);

        return sessionId;
    }

    private string GetSessionId(string user)
    {
        // this will be replaced with the actual call to the external service for the session id
        return DateTime.Now.ToString("yyyyMMdd_hhmmss");
    }
}
Run Code Online (Sandbox Code Playgroud)

Paw*_*cki 6

达里尔在这里对此进行了很好的解释:https ://stackoverflow.com/a/35643860/7708157

基本上,每个 CRM 系统都没有一个 MemoryCache 实例,您的代码只是证明每个插件都有多个应用程序域,因此即使存储在此类插件中的静态变量也可以有多个值,这是您不能依赖的。MSDN 上没有文档可以解释沙箱是如何工作的(尤其是在这种情况下的应用程序域),但使用静态变量肯定不是一个好主意。当然,如果您正在在线处理,您无法确定是否只有单个前端服务器或多个前端服务器(这也会导致这种行为)