[英]JQuery concurrency issue with a Dictionary in WCF Custom Endpoint Behavior
我將盡力解釋這一點。 如果我對此不滿意,則將其刪除並繼續。 也許你們可以給我一些想法。
這是一個網絡應用程序。 (C#4.0(服務器)和JQuery 1.6.1 Client)
在客戶端,我們設置了一堆文本框,當觸發.focusout事件時,將觸發AJAX調用,將數據發送到WCF服務。
在服務器端,我們已經創建了一個自定義的端點行為,因為我們已經設置了一些安全措施,因此在進行這些AJAX調用時可以獲取用戶信息(這對我們來說很好,所以我不尋求設置幫助。)
問題出在我對JQuery產生創意時,例如是否要告訴一堆盒子立即更新(即使它是2個文本框!)。
$(".blahblahClass").focusout(); //fires a bunch of AJAX calls
BOOM 。 我在下面的JsonAuthCallContextInitializer中得到一個System.IndexOutOfRangeException(假設是線程錯誤),在這里,它試圖在我的CallContextInitializer的BeforeInvoke()
中添加此字典的鍵:
_PrincipalMap[key] = Thread.CurrentPrincipal;
值得一提的是,我正在AfterInvoke()
同一本詞典中刪除密鑰
好的..作為字典,這可能不是線程安全的。 所以我加了一些lock
。 (您將在下面的代碼中看到)
我讀了ReaderWriterLockSlim
因為我讀到lock
存在一些並發問題,而ReaderWriterLock也存在一些問題。
因此,我使用默認的LockRecursionPolicy添加了鎖(它們在下面的代碼中)(這意味着我只是將ReaderWriterLockSlim
構造函數留為空白)。
當我再次運行該應用程序時,我將得到一個LockRecursionException(在此模式下保持的寫鎖可能無法獲取讀鎖)
不幸的是,拋出LockRecursionPolicy.SupportsRecursion
到ReaderWriterLockSlim
構造函數使異常消失了,不幸的是,並不是我網頁中的所有文本框都更新了。
讓我煩惱的是(我今天將要嘗試)使字典本身具有線程安全性。 這樣的事情: 實現線程安全字典的最佳方法是什么?
但我不相信它將解決這里的問題。
更新:所以我嘗試了其他幾件事。 我決定使用ConcurrentDictionary,甚至決定到底是什么,並在AfterInvoke()中擺脫了.Remove。 沒有骰子。 它基本上可以抑制錯誤,並且.html頁面上只有一個文本框將被更新,或者如果您有多個要更新的文本框,則可以在BeforeInvoke()中破壞
僅供參考,靜態字典是故意的
有什么建議嗎? (以下適用的行為代碼)
public class JsonAuthEndpointBehavior : IEndpointBehavior
{
private string _key;
public JsonAuthEndpointBehavior(string key)
{
if (key == null) throw new ArgumentNullException("key");
_key = key;
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
var jsonAuthCallContextInitializer = new JsonAuthCallContextInitializer(_key);
foreach (var operation in endpointDispatcher.DispatchRuntime.Operations)
{
operation.CallContextInitializers.Add(jsonAuthCallContextInitializer);
}
}
protected void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
// Do nothing
}
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
// Do nothing
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
// Do nothing
}
public void Validate(ServiceEndpoint endpoint)
{
// Do nothing
}
}
public class JsonAuthCallContextInitializer : ICallContextInitializer
{
private readonly string _key;
private static readonly Dictionary<int, IPrincipal> _PrincipalMap = new Dictionary<int, IPrincipal>();
private readonly ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
public JsonAuthCallContextInitializer(string key)
{
if (key == null) throw new ArgumentNullException("key");
_key = key;
}
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
if (WebOperationContext.Current == null)
throw new NotSupportedException("JSON Authentication call context initializer requires HTTP");
if (Thread.CurrentPrincipal != null)
{
var key = Thread.CurrentThread.ManagedThreadId;
cacheLock.EnterReadLock();
try
{
//LockRecursionException here
_PrincipalMap[key] = Thread.CurrentPrincipal;
}
finally
{
cacheLock.ExitReadLock();
}
}
Thread.CurrentPrincipal = new ClaimsPrincipal(new[]
{
new ClaimsIdentity((from c in x.Claims select new Claim(blahblah.ToString())).ToArray())
});
return null;
}
public void AfterInvoke(object correlationState)
{
var key = Thread.CurrentThread.ManagedThreadId;
cacheLock.EnterReadLock();
try
{
if (!_PrincipalMap.ContainsKey(key)) return;
Thread.CurrentPrincipal = _PrincipalMap[key];
}
finally
{
cacheLock.ExitReadLock();
}
cacheLock.EnterWriteLock();
try
{
_PrincipalMap.Remove(key);
}
catch (Exception)
{
cacheLock.ExitWriteLock();
}
}
}
好吧,我閱讀了一些文檔,但不確定是否是問題所在,但看起來這里有問題:
cacheLock.EnterReadLock();
try
{
//LockRecursionException here
_PrincipalMap[key] = Thread.CurrentPrincipal;
}
finally
{
cacheLock.ExitReadLock();
}
由於您要在字典中添加/更改值,因此它應該是cacheLock.EnterWriteLock和cacheLock.ExitWriteLock。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.