Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WCF自定义端点行为中JQuery与字典的并发性问题_C#_Jquery_Wcf_Dictionary - Fatal编程技术网

C# WCF自定义端点行为中JQuery与字典的并发性问题

C# WCF自定义端点行为中JQuery与字典的并发性问题,c#,jquery,wcf,dictionary,C#,Jquery,Wcf,Dictionary,我会尽力解释的。如果我在这个问题上失败了,那么我将删除这个并继续前进。也许你们能给我一些想法 这是一个网络应用程序。C 4.0服务器和JQuery 1.6.1客户端 在客户端,我们设置了一组文本框,当触发.focusout事件时,会触发一个AJAX调用,将数据发送到WCF服务 在服务器端,我们创建了一个自定义端点行为,因为我们已经设置了一些安全功能,这样我们可以在这些AJAX调用完成时获取用户信息。这对我们来说很好,所以我不需要安装帮助 当我在JQuery中发挥创意时,问题就来了,比如如果我想告

我会尽力解释的。如果我在这个问题上失败了,那么我将删除这个并继续前进。也许你们能给我一些想法

这是一个网络应用程序。C 4.0服务器和JQuery 1.6.1客户端

在客户端,我们设置了一组文本框,当触发.focusout事件时,会触发一个AJAX调用,将数据发送到WCF服务

在服务器端,我们创建了一个自定义端点行为,因为我们已经设置了一些安全功能,这样我们可以在这些AJAX调用完成时获取用户信息。这对我们来说很好,所以我不需要安装帮助

当我在JQuery中发挥创意时,问题就来了,比如如果我想告诉一堆框立即更新,即使它们是两个文本框

$(".blahblahClass").focusout(); //fires a bunch of AJAX calls
轰。我在下面的JsonAuthCallContextInitializer中得到一个System.IndexOutOfRangeException,假设它是一个线程错误,在这里,它试图在CallContextInitializer的BeforeInvoke中向该字典添加一个键:

_PrincipalMap[key] = Thread.CurrentPrincipal;
重要的是要提到,我正在从同一个字典中删除一个键

好的。。作为一本字典,这可能不是线程安全的。所以我加了一些锁。您将在下面的代码中看到

        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();
               }
         }
    }
我选择ReaderWriterLockSlim,因为我读到锁有一些并发性问题,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,因为您正在添加/更改字典中的值。

好吧,我阅读了一些文档,我不确定这是否是问题所在,但看起来您在这里遇到了问题:

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

它应该是cacheLock.EnterWriteLock和cacheLock.ExitWriteLock,因为您正在添加/更改字典中的值。

非常好。唉,它没有解决问题。我将它们更改为WriteLock/ExitWriteLock,并得到以下结果:在此模式下不允许递归写入锁获取。将LockRecursionPolicy更改为.SupportsRecursion会给我带来与以前相同的问题,不是所有的文本框都会更新。是的,我认为你的问题比这要深刻得多。很好。唉,它没有解决问题。我将它们更改为WriteLock/ExitWriteLock,并得到以下结果:在此模式下不允许递归写入锁获取。将LockRecursionPolicy更改为.SupportsRecursion会给我带来与以前相同的问题,并不是所有的文本框都会更新。是的,我觉得你的问题要深得多。