lith 1 rok temu
rodzic
commit
60258d9d55

+ 7 - 6
dotnet/Library/Sers/Sers.Core/Sers.Core/CL/CommunicationManage/CommunicationManageServer.cs

@@ -18,7 +18,8 @@ namespace Sers.Core.CL.CommunicationManage
     {
 
         #region static CurConn
-        static AsyncCache<IOrganizeConnection> curConn = new AsyncCache<IOrganizeConnection>();
+        //static AsyncCache<IOrganizeConnection> curConn = new AsyncCache<IOrganizeConnection>();
+        static System.Threading.AsyncLocal<IOrganizeConnection> curConn = new System.Threading.AsyncLocal<IOrganizeConnection>();
 
         /// <summary>
         /// 当前连接
@@ -62,7 +63,7 @@ namespace Sers.Core.CL.CommunicationManage
 
 
         #endregion
-        
+
 
         #region Start       
 
@@ -132,7 +133,7 @@ namespace Sers.Core.CL.CommunicationManage
             {
                 List<IOrganizeServer> organizeList = new List<IOrganizeServer>();
 
-   
+
                 #region (x.1) get configs
                 var configs = Appsettings.json.GetByPath<JObject[]>("Sers.CL.Server");
                 if (configs == null) return null;
@@ -147,7 +148,7 @@ namespace Sers.Core.CL.CommunicationManage
                     }
                 }
                 #endregion
-                 
+
 
                 //(x.2) BeforeBuildOrganize
                 try
@@ -197,8 +198,8 @@ namespace Sers.Core.CL.CommunicationManage
         #region Stop       
         public void Stop()
         {
-            if (organizeList == null) return;       
- 
+            if (organizeList == null) return;
+
             foreach (var organize in organizeList)
             {
                 try

+ 4 - 31
dotnet/Library/Sers/Sers.Core/Sers.Core/Module/Rpc/RpcContext.cs

@@ -1,17 +1,16 @@
 using System;
+
 using Sers.Core.Module.Message;
+
 using Vit.Core.Util.Threading.Cache;
 
 namespace Sers.Core.Module.Rpc
 {
-    public class RpcContext : IDisposable
+    public class RpcContext : AsyncCacheScope<RpcContext>
     {
 
         #region static
-
-        static AsyncCache<RpcContext> CurrentRpcContext_AsyncCache = new AsyncCache<RpcContext>();
-
-        public static RpcContext Current => CurrentRpcContext_AsyncCache.Value;
+        public static RpcContext Current => Instance;
 
         public static RpcContextData RpcData => Current?.rpcData;
 
@@ -24,31 +23,5 @@ namespace Sers.Core.Module.Rpc
 
         public RpcContextData rpcData;
 
-
-
-        #region 构造函数 和 Dispose
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
-        public RpcContext()
-        {
-            //lock (CurrentRpcContext_AsyncCache)
-            //{
-            CurrentRpcContext_AsyncCache.Value = this;
-            //}
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
-        public virtual void Dispose()
-        {
-            //lock (CurrentRpcContext_AsyncCache)
-            //{
-            if (CurrentRpcContext_AsyncCache.Value == this)
-            {
-                CurrentRpcContext_AsyncCache.Value = null;
-            }
-            //}
-        }
-        #endregion
-
     }
 }

+ 65 - 0
dotnet/Library/Vit/Vit.Core/Test/Vit.Core.Util.Threading.MsTest/Cache/AsyncCacheDisposable_Test.cs

@@ -0,0 +1,65 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Vit.Core.Util.Threading.Cache;
+
+namespace Vit.Core.Util.Threading.MsTest.Cache
+{
+    [TestClass]
+    public class AsyncCacheDisposable_Test : AsyncCache_BaseTest
+    {
+
+        AsyncCache<string> asyncCache = new AsyncCache<string>();
+
+        public override void RunTest(string name)
+        {
+            using var scope = asyncCache.NewScope();
+
+            //set
+            asyncCache.Value = name;
+
+            Thread.Sleep(10);
+
+            //get
+            var actual = asyncCache.Value;
+            Assert.AreEqual(name, actual);
+        }
+
+        public override async Task RunTestAsync(string name)
+        {
+            using var scope = asyncCache.NewScope();
+
+            //set
+            await Set(name);
+
+            await Task.Delay(8);
+
+            //get
+            var actual = await Get();
+
+            Assert.AreEqual(name, actual);
+        }
+
+        async Task Set(string name)
+        {
+            asyncCache.Value = name;
+            await Task.Delay(1);
+        }
+
+        async Task<string> Get()
+        {
+            var name = asyncCache.Value;
+            await Task.Delay(1);
+            return name;
+        }
+
+
+    }
+
+     
+}

+ 67 - 0
dotnet/Library/Vit/Vit.Core/Test/Vit.Core.Util.Threading.MsTest/Cache/AsyncCacheScope_Test.cs

@@ -0,0 +1,67 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Vit.Core.Util.Threading.Cache;
+
+namespace Vit.Core.Util.Threading.MsTest.Cache
+{
+    [TestClass]
+    public class AsyncCacheScope_Test : AsyncCache_BaseTest
+    {
+        class CacheScope : AsyncCacheScope<CacheScope>
+        {
+            public string name;
+        }
+
+        public override void RunTest(string name)
+        {
+            using var scope = new CacheScope();
+
+            //set
+            CacheScope.Instance.name = name;
+
+            Thread.Sleep(10);
+
+            //get
+            var actual = CacheScope.Instance.name;
+            Assert.AreEqual(name, actual);
+        }
+
+        public override async Task RunTestAsync(string name)
+        {
+            using var scope = new CacheScope();
+
+            //set
+            await Set(name);
+
+            await Task.Delay(8);
+
+            //get
+            var actual = await Get();
+
+            Assert.AreEqual(name, actual);
+        }
+
+        async Task Set(string name)
+        {
+            CacheScope.Instance.name = name;
+            await Task.Delay(1);
+        }
+
+        async Task<string> Get()
+        {
+            var name = CacheScope.Instance.name;
+            await Task.Delay(1);
+            return name;
+        }
+
+
+    }
+
+     
+}

+ 164 - 0
dotnet/Library/Vit/Vit.Core/Test/Vit.Core.Util.Threading.MsTest/Cache/AsyncCache_BaseTest.cs

@@ -0,0 +1,164 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Vit.Core.Util.Threading.Cache;
+
+namespace Vit.Core.Util.Threading.MsTest.Cache
+{
+ 
+    public abstract class AsyncCache_BaseTest
+    {
+        public abstract void RunTest(string name);
+        public abstract Task RunTestAsync(string name);
+
+        #region Task
+        [TestMethod]
+        public void Test_Task()
+        {
+            int threadCount = 0;
+            int testCount = 0;
+
+            var tasks = Enumerable.Range(0, 10).Select(number => Task.Run(() =>
+                {
+                    Interlocked.Increment(ref threadCount);
+                    for (var i = 0; i < 100; i++)
+                    {
+                        Interlocked.Increment(ref testCount);
+                        var name = $"{number}_{i}_{System.Guid.NewGuid()}";
+                        RunTest(name);
+                    }
+                })
+            ).ToArray();
+
+            Task.WaitAll(tasks);
+        }
+
+        [TestMethod]
+        public void Test_TaskAsync()
+        {
+            int threadCount = 0;
+            int testCount = 0;
+
+            var tasks = Enumerable.Range(0, 10).Select(number => Task.Run(async () =>
+                {
+                    Interlocked.Increment(ref threadCount);
+                    for (var i = 0; i < 100; i++)
+                    {
+                        Interlocked.Increment(ref testCount);
+                        var name = $"{number}_{i}_{System.Guid.NewGuid()}";
+                        await RunTestAsync(name);
+                    }
+                })
+            ).ToArray();
+
+            Task.WaitAll(tasks);
+        }
+        #endregion
+
+
+
+        #region Thread
+        [TestMethod]
+        public void Test_Thread()
+        {
+            int threadCount = 0;
+            int testCount = 0;
+
+            Thread_ForEach(Enumerable.Range(0, 100), number =>
+            {
+                Interlocked.Increment(ref threadCount);
+                for (var i = 0; i < 100; i++)
+                {
+                    Interlocked.Increment(ref testCount);
+                    var name = $"{number}_{i}_{System.Guid.NewGuid()}";
+                    RunTest(name);
+                }
+            });
+        }
+
+        [TestMethod]
+        public void Test_ThreadAsync()
+        {
+            int threadCount = 0;
+            int testCount = 0;
+
+            Thread_ForEach(Enumerable.Range(0, 100), number =>
+            {
+                Interlocked.Increment(ref threadCount);
+                for (var i = 0; i < 100; i++)
+                {
+                    Interlocked.Increment(ref testCount);
+                    var name = $"{number}_{i}_{System.Guid.NewGuid()}";
+                    RunTestAsync(name).Wait();
+                }
+            });
+        }
+
+        void Thread_ForEach<T>(IEnumerable<T> source, Action<T> action, int msSleep = 10)
+        {
+            var threads = source.Select(i =>
+            {
+                var thread = new Thread(new ThreadStart(() => action(i)));
+                thread.Start();
+                return thread;
+            }).ToList();
+
+            while (true)
+            {
+                threads = threads.Where(t => t.IsAlive).ToList();
+                if (!threads.Any()) return;
+                Thread.Sleep(msSleep);
+            }
+        }
+        #endregion
+
+
+        #region Parallel
+        [TestMethod]
+        public void Test_Parallel()
+        {
+            int threadCount = 0;
+            int testCount = 0;
+
+            Parallel.ForEach(Enumerable.Range(0, 10)
+                //, new ParallelOptions { MaxDegreeOfParallelism = 1 }
+                , number =>
+                {
+                    Interlocked.Increment(ref threadCount);
+                    for (var i = 0; i < 100; i++)
+                    {
+                        Interlocked.Increment(ref testCount);
+                        var name = $"{number}_{i}_{System.Guid.NewGuid()}";
+                        RunTest(name);
+                    }
+                });
+        }
+
+        [TestMethod]
+        public void Test_ParallelAsync()
+        {
+            int threadCount = 0;
+            int testCount = 0;
+
+            Parallel.ForEach(Enumerable.Range(0, 10)
+                //, new ParallelOptions { MaxDegreeOfParallelism = 1 }
+                , number =>
+                {
+                    Interlocked.Increment(ref threadCount);
+                    for (var i = 0; i < 100; i++)
+                    {
+                        Interlocked.Increment(ref testCount);
+                        var name = $"{number}_{i}_{System.Guid.NewGuid()}";
+                        RunTestAsync(name).Wait();
+                    }
+                });
+        }
+
+        #endregion
+    }
+}

+ 66 - 0
dotnet/Library/Vit/Vit.Core/Test/Vit.Core.Util.Threading.MsTest/Cache/AsyncCache_Test.cs

@@ -0,0 +1,66 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Threading;
+using System.Threading.Tasks;
+
+using Vit.Core.Util.Threading.Cache;
+
+namespace Vit.Core.Util.Threading.MsTest.Cache
+{
+    [TestClass]
+    public class AsyncCache_Test : AsyncCache_BaseTest
+    {
+
+        AsyncCache<string> asyncCache = new AsyncCache<string>();
+
+        public override void RunTest(string name)
+        {
+            asyncCache.CreateScope();
+
+            //set
+            asyncCache.Value = name;
+
+            Thread.Sleep(10);
+
+            //get
+            var actual = asyncCache.Value;
+            Assert.AreEqual(name, actual);
+
+            asyncCache.DisposeScope();
+        }
+
+        public override async Task RunTestAsync(string name)
+        {
+            asyncCache.CreateScope();
+
+            //set
+            await Set(name);
+
+            await Task.Delay(8);
+
+            //get
+            var actual = await Get();
+
+            Assert.AreEqual(name, actual);
+
+            asyncCache.DisposeScope();
+        }
+
+        async Task Set(string name)
+        {
+            asyncCache.Value = name;
+            await Task.Delay(1);
+        }
+
+        async Task<string> Get()
+        {
+            var name = asyncCache.Value;
+            await Task.Delay(1);
+            return name;
+        }
+
+
+    }
+
+     
+}

+ 57 - 0
dotnet/Library/Vit/Vit.Core/Test/Vit.Core.Util.Threading.MsTest/Cache/AsyncLocal_Test.cs

@@ -0,0 +1,57 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Vit.Core.Util.Threading.MsTest.Cache
+{
+    [TestClass]
+    public class AsyncLocal_Test : AsyncCache_BaseTest
+    {
+
+        readonly System.Threading.AsyncLocal<string> AsyncLocal = new System.Threading.AsyncLocal<string>();
+
+        public override void RunTest(string name)
+        {
+            //set
+            AsyncLocal.Value = name;
+
+            Thread.Sleep(10);
+
+            //get
+            var actual = AsyncLocal.Value;
+            Assert.AreEqual(name, actual);
+        }
+
+        public override async Task RunTestAsync(string name)
+        {
+            //set
+            //await Set(name);
+            AsyncLocal.Value = name;
+
+            await Task.Delay(8);
+
+            //get
+            var actual = await Get();
+
+            Assert.AreEqual(name, actual);
+        }
+
+        async Task Set(string name)
+        {
+            AsyncLocal.Value = name;
+            await Task.Delay(1);
+        }
+
+        async Task<string> Get()
+        {
+            var name = AsyncLocal.Value;
+            await Task.Delay(1);
+            return name;
+        }
+
+
+    }
+
+     
+}

+ 64 - 19
dotnet/Library/Vit/Vit.Core/Vit.Core/Util/Threading/Cache/AsyncCache.cs

@@ -1,8 +1,8 @@
-#region << 版本注释 - v1 >>
+#region << 版本注释 - v2 >>
 /*
  * ========================================================================
- * 版本:v1
- * 时间:2021-03-19
+ * 版本:v2
+ * 时间:2023-10-23
  * 作者:Lith
  * 邮箱:serset@yeah.net
  * 
@@ -12,41 +12,86 @@
 
 
 using System;
-using System.Collections.Generic;
-using System.Text;
- 
 
 namespace Vit.Core.Util.Threading.Cache
 {
+    public abstract class AsyncCacheScope<ScopeType> : IDisposable
+        where ScopeType : AsyncCacheScope<ScopeType>
+    {
+        public AsyncCacheScope()
+        {
+            Instance_AsyncCache.CreateScope(this as ScopeType);
+        }
+        public virtual void Dispose()
+        {
+            Instance_AsyncCache.DisposeScope();
+        }
+
+        static AsyncCache<ScopeType> Instance_AsyncCache = new AsyncCache<ScopeType>();
+
+        public static ScopeType Instance => Instance_AsyncCache.Value;
+    }
+
+
     /// <summary>
     /// 切换线程时依然可以传递数据。(若切换线程不传递则可使用System.Threading.ThreadLocal ,或者使用[ThreadStatic]特性)
     /// 多包裹一层的原因是 子异步任务结束时会还原子异步任务对AsyncLocal做的更改(即子异步任务对AsyncLocal做的更改不会保留到子异步任务结束后的父异步任务中)
-    /// 参见https://blog.csdn.net/kkfd1002/article/details/80102244
+    /// 参见 https://blog.csdn.net/kkfd1002/article/details/80102244
     /// </summary>
-    public class AsyncCache<T>
+    public class AsyncCache<DataType>
     {
 
-        readonly System.Threading.AsyncLocal<CachedData> _AsyncLocal = new System.Threading.AsyncLocal<CachedData>();
+        readonly System.Threading.AsyncLocal<DataWrap> _AsyncLocal = new System.Threading.AsyncLocal<DataWrap>();
+
+        class DataWrap
+        {
+            internal DataType data;
+        }
+        public void CreateScope( )
+        {
+            _AsyncLocal.Value = new DataWrap();
+        }
+        public void CreateScope(DataType value)
+        {
+            _AsyncLocal.Value = new DataWrap { data = value };
+        }
+
+        public IDisposable NewScope()
+        {
+            _AsyncLocal.Value = new DataWrap();
+            return new Disposable(DisposeScope);
+        }
+        public IDisposable NewScope(DataType value)
+        {
+            _AsyncLocal.Value = new DataWrap { data = value };
+            return new Disposable(DisposeScope);
+        }
+
 
-        class CachedData
+        public void DisposeScope()
         {
-            public T Cache;
+            _AsyncLocal.Value = null;
         }
-        public T Value
+        public bool SetValue(DataType value)
+        {
+            var dataWrap = _AsyncLocal.Value;
+            if (dataWrap == null) return false;
+            dataWrap.data = value;
+            return true;
+        }
+        public DataType Value
         {
             get
             {
-                if (null == _AsyncLocal.Value)
-                    return default(T);
-                return _AsyncLocal.Value.Cache;
+                var dataWrap = _AsyncLocal.Value;
+                if (dataWrap == null) return default;
+                return dataWrap.data;
             }
             set
             {
-                var asyncLocal = _AsyncLocal.Value;
-                if (null == asyncLocal) asyncLocal = _AsyncLocal.Value = new CachedData();
-                asyncLocal.Cache = value;
+                SetValue(value);
             }
         }
     }
-   
+
 }

+ 0 - 49
dotnet/Library/Vit/Vit.Core/Vit.Core/Util/Threading/Cache/AsyncCacheHelper.cs

@@ -1,49 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-
-
-namespace Vit.Core.Util.Threading.Cache
-{
-    public class AsyncCacheHelper
-    {
-        static  AsyncCache<ConcurrentDictionary<string,object>> _AsyncCache = new AsyncCache<ConcurrentDictionary<string, object>>();
-        static ConcurrentDictionary<string, object> dic
-        {
-            get
-            {
-                return _AsyncCache.Value ?? (_AsyncCache.Value = new ConcurrentDictionary<string, object>());                
-            }             
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
-        public static void Set(string key,Object value)
-        {
-            dic[key] = value;
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
-        public static Object Get(string key)
-        {
-            if (dic.TryGetValue(key, out var value))
-            {
-                return value;
-            }
-            return null;
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
-        public static T Get<T>(string key)
-        {
-            try
-            {
-                if (dic.TryGetValue(key, out var value))
-                {
-                    return (T)value;
-                }
-            }
-            catch { }           
-            return default(T);
-        }
-
-    }
-}

+ 20 - 19
dotnet/ServiceCenter/Sers.ServiceCenter/Sers.Gover/Base/GoverApiCenterService.cs

@@ -33,7 +33,7 @@ namespace Sers.Gover.Base
         public static readonly GoverApiCenterService Instance = LoadFromFile();
         static GoverApiCenterService LoadFromFile()
         {
-            var mng=new GoverApiCenterService();
+            var mng = new GoverApiCenterService();
 
             Persistence_ApiDesc.ApiDesc_LoadAllFromJsonFile(mng.apiStationMng);
             Persistence_Counter.LoadCounterFromJsonFile(mng.apiStationMng);
@@ -42,11 +42,11 @@ namespace Sers.Gover.Base
         }
         public static void SaveToFile()
         {
-            Persistence_Counter.SaveCounterToJsonFile(Instance.apiStationMng); 
+            Persistence_Counter.SaveCounterToJsonFile(Instance.apiStationMng);
         }
         #endregion
 
- 
+
 
 
 
@@ -67,7 +67,7 @@ namespace Sers.Gover.Base
             apiStationMng.Init(this);
         }
 
-        
+
 
         internal readonly ApiLoadBalancingMng apiLoadBalancingMng;
 
@@ -93,7 +93,7 @@ namespace Sers.Gover.Base
         public IEnumerable<SsApiDesc> ApiDesc_GetActive()
         {
             return apiLoadBalancingMng.GetAllApiDesc();
-        
+
         }
 
         public IEnumerable<SsApiDesc> ApiDesc_GetAll()
@@ -138,7 +138,7 @@ namespace Sers.Gover.Base
                 #endregion
 
 
-                #region (x.1)route 判空               
+                #region (x.1)route 判空
                 if (string.IsNullOrWhiteSpace(rpcData.route))
                 {
                     //返回api 不存在
@@ -148,7 +148,7 @@ namespace Sers.Gover.Base
                 #endregion
 
 
-                #region (x.2) 服务限流 BeforeLoadBalancing               
+                #region (x.2) 服务限流 BeforeLoadBalancing
                 var error = rateLimitMng.BeforeLoadBalancing(rpcData, requestMessage);
                 if (null != error)
                 {
@@ -157,7 +157,7 @@ namespace Sers.Gover.Base
                 }
                 #endregion
 
-                #region (x.3) 负载均衡,获取对应服务端                
+                #region (x.3) 负载均衡,获取对应服务端
                 var apiNode = apiLoadBalancingMng.GetCurApiNodeByLoadBalancing(rpcData, out var routeType);
 
                 if (null == apiNode)
@@ -231,14 +231,15 @@ namespace Sers.Gover.Base
 
 
                 //(x.x.2) 修正 requestMessage
-                if (requestMessage.rpcContextData_OriData.Count <= 0) {
+                if (requestMessage.rpcContextData_OriData.Count <= 0)
+                {
                     requestMessage.RpcContextData_OriData_Set(rpcData);
                 }
-                #endregion             
+                #endregion
 
 
                 #region (x.8)服务调用
-                apiNode.CallApiAsync(rpcData, requestMessage, sender,callback);                
+                apiNode.CallApiAsync(rpcData, requestMessage, sender, callback);
                 #endregion
 
             }
@@ -247,7 +248,7 @@ namespace Sers.Gover.Base
                 Logger.Error(ex);
 
                 ApiSysError.LogSysError(rpcData, requestMessage, ex.ToSsError());
- 
+
                 SendReply(SsError.Err_SysErr);
                 return;
             }
@@ -259,7 +260,7 @@ namespace Sers.Gover.Base
                 callback(sender, new ApiMessage().InitAsApiReplyMessageByError(error).Package());
             }
 
-          
+
 
         }
         #endregion
@@ -290,9 +291,9 @@ namespace Sers.Gover.Base
         }
 
 
-        public override void ServiceStation_Remove(IOrganizeConnection  conn)
+        public override void ServiceStation_Remove(IOrganizeConnection conn)
         {
-            string connKey = ""+ conn.GetHashCode();
+            string connKey = "" + conn.GetHashCode();
             var serviceStation = serviceStationMng.ServiceStation_Remove(connKey);
             if (serviceStation != null)
             {
@@ -307,7 +308,7 @@ namespace Sers.Gover.Base
             if (serviceStation != null)
             {
                 Logger.Info("[ApiCenterService]Pause serviceStation", new { stationName = serviceStation?.serviceStationInfo?.serviceStationName });
-            } 
+            }
             return serviceStation != null;
         }
 
@@ -318,7 +319,7 @@ namespace Sers.Gover.Base
             {
                 Logger.Info("[ApiCenterService]Start serviceStation", new { stationName = serviceStation?.serviceStationInfo?.serviceStationName });
             }
-            return serviceStation != null; 
+            return serviceStation != null;
         }
 
         public bool ServiceStation_Stop(string connKey)
@@ -367,9 +368,9 @@ namespace Sers.Gover.Base
         /// 在调用api前调用onScope,若onScope返回的结果(onDispose)不为空,则在api调用结束前调用onDispose
         /// </summary>
         /// <param name="apiScopeEvent"></param>
-        public void AddApiScopeEvent(Func<RpcContextData, ApiMessage, Action<Object, Vit.Core.Util.Pipelines.ByteData>> apiScopeEvent) 
+        public void AddApiScopeEvent(Func<RpcContextData, ApiMessage, Action<Object, Vit.Core.Util.Pipelines.ByteData>> apiScopeEvent)
         {
-            if (apiScopeEventList == null) apiScopeEventList=new List<Func<RpcContextData, ApiMessage, Action<Object, Vit.Core.Util.Pipelines.ByteData>>>();
+            if (apiScopeEventList == null) apiScopeEventList = new List<Func<RpcContextData, ApiMessage, Action<Object, Vit.Core.Util.Pipelines.ByteData>>>();
 
             apiScopeEventList.Add(apiScopeEvent);
         }