簡體   English   中英

WCF自定義端點行為中的字典的JQuery並發問題

[英]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.SupportsRecursionReaderWriterLockSlim構造函數使異常消失了,不幸的是,並不是我網頁中的所有文本框都更新了。

讓我煩惱的是(我今天將要嘗試)使字典本身具有線程安全性。 這樣的事情: 實現線程安全字典的最佳方法是什么?

但我不相信它將解決這里的問題。

更新:所以我嘗試了其他幾件事。 我決定使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM