Проблема параллелизма JQuery со словарем в пользовательском поведении конечной точки WCF - PullRequest
2 голосов
/ 28 июля 2011

Я постараюсь объяснить это как можно лучше.Если я упаду на это, тогда я удалю это и продолжу.Может быть, вы, ребята, можете дать мне несколько идей.

Это веб-приложение.(C # 4.0 (сервер) и JQuery 1.6.1 Client)

На стороне клиента у нас настроено несколько текстовых полей, в которых при запуске события .focusout запускается вызов AJAX, отправляющий данныеСлужба WCF.

На стороне сервера мы создали настраиваемое поведение конечной точки, поскольку у нас есть некоторые настроенные средства безопасности, чтобы мы могли получать информацию о пользователях при выполнении этих вызовов AJAX (это прекрасно работает для наспоэтому я не ищу помощи по настройке.)

Проблема возникает, когда я проявляю творческий подход в JQuery, например, если я хочу сказать сразу несколько коробок для обновления (даже если это 2 текстовых поля!)

$(".blahblahClass").focusout(); //fires a bunch of AJAX calls

БУМ .Я получаю System.IndexOutOfRangeException (предполагается, что это ошибка многопоточности) в моем JsonAuthCallContextInitializer ниже, здесь он пытается добавить ключ к этому словарю в BeforeInvoke() моего CallContextInitializer:

_PrincipalMap[key] = Thread.CurrentPrincipal;

Еговажно упомянуть, что я удаляю ключ из этого самого словаря в AfterInvoke()

ok .. будучи словарем, это, вероятно, не является потокобезопасным.поэтому я добавил lock с.(что вы увидите в коде ниже)

Я выбрал ReaderWriterLockSlim, когда прочитал, что lock имел некоторые проблемы с параллелизмом, а ReaderWriterLock также имел некоторые проблемы.

Поэтому я добавил блокировки (они в коде ниже), используя стандартную LockRecursionPolicy (это означает, что я просто оставил конструктор ReaderWriterLockSlim пустым).

Когда я снова запустил приложение, Я получил бы LockRecursionException (блокировка чтения не может быть получена с блокировкой записи, удерживаемой в этом режиме)

бросив LockRecursionPolicy.SupportsRecursion в конструктор ReaderWriterLockSlim исключение исключено, к сожалению, не всетекстовые поля в моем обновлении веб-страницы ..

Сверху моей головы (что я буду пытаться сегодня), возможно, сделать словарь сам потокобезопасным.Примерно так: Каков наилучший способ реализации многопоточного словаря?

, но я не уверен, что это решит проблему здесь.

Обновление: так что яЯ пробовал пару других вещей.Я решил использовать ConcurrentDictionary и даже решил, что за чертовщина, и избавился от .Remove в AfterInvoke ().Нет кости.В основном это либо подавляет ошибку, и обновляется только одно текстовое поле на странице .html, либо перебивает функцию BeforeInvoke (), если у вас есть несколько текстовых полей, которые обновляют

FYI, статический словарь является преднамеренным

Предложения?(применимый код поведения ниже)

        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();
               }
         }
    }

1 Ответ

0 голосов
/ 28 июля 2011

Ну, я перечитал немного документации, и я не уверен, что это проблема, но похоже, что у вас есть проблема здесь:

            cacheLock.EnterReadLock();
            try
            {
                //LockRecursionException here
                _PrincipalMap[key] = Thread.CurrentPrincipal;
            }
            finally
            {
                cacheLock.ExitReadLock();
            }

Это должны быть cacheLock.EnterWriteLock и cacheLock.ExitWriteLock, так как вы добавляете / меняете значение в словаре.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...