[英]Dynamics CRM Online Object caching not caching correctly
我有一個要求,我們需要一個插件來從外部系統檢索會話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");
}
}
Daryl在這里對此進行了很大的解釋: https : //stackoverflow.com/a/35643860/7708157
基本上你不是每個CRM系統都有一個MemoryCache實例,你的代碼只是證明每個插件都有多個app域,所以即使存儲在這個插件中的靜態變量也可以有多個值,你不能依賴它們。 在MSDN上沒有可以解釋sanboxing如何工作的文檔(特別是在這種情況下的app域),但肯定使用靜態變量並不是一個好主意。當然,如果你在線處理,你不能確定是否只有單個前端服務器或其中許多服務器(這也會導致此類行為)
類級變量應限於配置信息。 不支持使用您正在執行的類級變量。 在CRM Online中,由於多個Web前端,可以通過插件類的不同實例在不同服務器上執行特定請求而不是另一個請求。 總的來說,假設CRM是無狀態的,除非持久化和檢索,否則在插件執行之間不應該假設是連續的。
根據SDK:
應該將插件的Execute方法編寫為無狀態,因為每次調用插件時都不會調用構造函數。 此外,多個系統線程可以同時執行插件。 所有每個調用狀態信息都存儲在上下文中,因此您不應使用全局變量或嘗試將任何數據存儲在成員變量中,以便在下一個插件調用期間使用,除非該數據是從提供給構造函數的配置參數中獲取的。
參考: https : //msdn.microsoft.com/en-us/library/gg328263.aspx
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.