@@ -15,9 +15,13 @@ public class Handler
1515 {
1616 #region Members
1717
18- //private static Handler current;
19- private static ConcurrentDictionary < string , Handler > _sessionHandlers ;
20- private static string _defaultSessionId ;
18+ private static int _sessionHandlerMasterVersion = 1 ;
19+ [ ThreadStatic ]
20+ private static int _sessionHandlerLocalVersion = 0 ;
21+ private static ConcurrentDictionary < string , Handler > _sessionHandlersMaster ;
22+ [ ThreadStatic ]
23+ private static Dictionary < string , Handler > _sessionHandlersLocal ;
24+ private static volatile string _defaultSessionId ;
2125 #endregion
2226
2327 #region Constructors
@@ -26,8 +30,8 @@ static Handler()
2630 {
2731 //current = new Handler(Guid.NewGuid().ToString());
2832 _defaultSessionId = Guid . NewGuid ( ) . ToString ( ) ;
29- _sessionHandlers = new ConcurrentDictionary < string , Handler > ( ) ;
30- _sessionHandlers [ _defaultSessionId ] = new Handler ( _defaultSessionId ) ;
33+ _sessionHandlersMaster = new ConcurrentDictionary < string , Handler > ( ) ;
34+ _sessionHandlersMaster [ _defaultSessionId ] = new Handler ( _defaultSessionId ) ;
3135 }
3236
3337 private Handler ( string sessionId )
@@ -53,7 +57,17 @@ private Handler(string sessionId)
5357 /// <returns></returns>
5458 public static Handler GetSessionHandler ( string sessionId )
5559 {
56- return _sessionHandlers . GetOrAdd ( sessionId , new Handler ( sessionId ) ) ;
60+ if ( _sessionHandlerMasterVersion != _sessionHandlerLocalVersion )
61+ {
62+ _sessionHandlersLocal = new Dictionary < string , Handler > ( _sessionHandlersMaster ) ;
63+ _sessionHandlerLocalVersion = _sessionHandlerMasterVersion ;
64+ }
65+ if ( _sessionHandlersLocal . ContainsKey ( sessionId ) )
66+ {
67+ return _sessionHandlersLocal [ sessionId ] ;
68+ }
69+ Interlocked . Increment ( ref _sessionHandlerMasterVersion ) ;
70+ return _sessionHandlersMaster . GetOrAdd ( sessionId , new Handler ( sessionId ) ) ;
5771 }
5872
5973 /// <summary>
@@ -72,7 +86,8 @@ public static Handler GetSessionHandler()
7286 public static void DestroySession ( string sessionId )
7387 {
7488 Handler h ;
75- _sessionHandlers . TryRemove ( sessionId , out h ) ;
89+ _sessionHandlersMaster . TryRemove ( sessionId , out h ) ;
90+ Interlocked . Increment ( ref _sessionHandlerMasterVersion ) ;
7691 h . MetaData . Services . Clear ( ) ;
7792 }
7893 /// <summary>
@@ -93,36 +108,32 @@ public void Destroy()
93108 /// </summary>
94109 public string SessionId { get ; private set ; }
95110
96- private static ConcurrentDictionary < int , object > RpcContexts = new ConcurrentDictionary < int , object > ( ) ;
97- private static ConcurrentDictionary < int , JsonRpcException > RpcExceptions = new ConcurrentDictionary < int , JsonRpcException > ( ) ;
98-
99111 /// <summary>
100112 /// Provides access to a context specific to each JsonRpc method invocation.
101113 /// Warning: Must be called from within the execution context of the jsonRpc Method to return the context
102114 /// </summary>
103115 /// <returns></returns>
104116 public static object RpcContext ( )
105117 {
106- if ( Task . CurrentId == null )
107- return null ;
108-
109- if ( RpcContexts . ContainsKey ( Task . CurrentId . Value ) == false )
110- return null ;
111-
112- return RpcContexts [ Task . CurrentId . Value ] ;
118+ return __currentRpcContext ;
113119 }
114120
121+ [ ThreadStatic ]
122+ static JsonRpcException __currentRpcException ;
115123 /// <summary>
116124 /// Allows you to set the exception used in in the JsonRpc response.
117- /// Warning: Must be called from within the execution context of the jsonRpc method.
125+ /// Warning: Must be called from the same thread as the jsonRpc method.
118126 /// </summary>
119127 /// <param name="exception"></param>
120128 public static void RpcSetException ( JsonRpcException exception )
121129 {
122- if ( Task . CurrentId != null )
123- RpcExceptions [ Task . CurrentId . Value ] = exception ;
124- else
125- throw new InvalidOperationException ( "This method is only valid when used within the context of a method marked as a JsonRpcMethod, and that method must of been invoked by the JsonRpc Handler." ) ;
130+ __currentRpcException = exception ;
131+ }
132+ public static JsonRpcException RpcGetAndRemoveRpcException ( )
133+ {
134+ var ex = __currentRpcException ;
135+ __currentRpcException = null ;
136+ return ex ;
126137 }
127138
128139 private AustinHarris . JsonRpc . PreProcessHandler externalPreProcessingHandler ;
@@ -136,8 +147,6 @@ public static void RpcSetException(JsonRpcException exception)
136147 /// </summary>
137148 public SMD MetaData { get ; set ; }
138149
139- private const string THREAD_CALLBACK_SLOT_NAME = "Callback" ;
140-
141150 #region Public Methods
142151
143152 /// <summary>
@@ -184,7 +193,7 @@ public void SetPostProcessHandler(AustinHarris.JsonRpc.PostProcessHandler handle
184193 /// <param name="Rpc">JsonRpc Request to be processed</param>
185194 /// <param name="RpcContext">Optional context that will be available from within the jsonRpcMethod.</param>
186195 /// <returns></returns>
187- public JsonResponse Handle ( JsonRequest Rpc , Object RpcContext = null , Action < JsonResponse > callback = null )
196+ public JsonResponse Handle ( JsonRequest Rpc , Object RpcContext = null )
188197 {
189198 AddRpcContext ( RpcContext ) ;
190199
@@ -198,7 +207,7 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null, Action<Jso
198207 } ;
199208 //callback is called - if it is empty then nothing will be done
200209 //return response always- if callback is empty or not
201- return PostProcess ( callback , Rpc , response , RpcContext ) ;
210+ return PostProcess ( Rpc , response , RpcContext ) ;
202211 }
203212
204213 SMDService metadata = null ;
@@ -217,7 +226,7 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null, Action<Jso
217226 Error = new JsonRpcException ( - 32601 , "Method not found" , "The method does not exist / is not available." ) ,
218227 Id = Rpc . Id
219228 } ;
220- return PostProcess ( callback , Rpc , response , RpcContext ) ;
229+ return PostProcess ( Rpc , response , RpcContext ) ;
221230 }
222231
223232 bool isJObject = Rpc . Params is Newtonsoft . Json . Linq . JObject ;
@@ -278,7 +287,7 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null, Action<Jso
278287 ) ) ,
279288 Id = Rpc . Id
280289 } ;
281- return PostProcess ( callback , Rpc , response , RpcContext ) ;
290+ return PostProcess ( Rpc , response , RpcContext ) ;
282291 }
283292 parameters [ i ] = CleanUpParameter ( jo [ metadata . parameters [ i ] . Name ] , metadata . parameters [ i ] ) ;
284293 }
@@ -313,7 +322,7 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null, Action<Jso
313322 ) ) ,
314323 Id = Rpc . Id
315324 } ;
316- return PostProcess ( callback , Rpc , response , RpcContext ) ;
325+ return PostProcess ( Rpc , response , RpcContext ) ;
317326 }
318327 }
319328
@@ -330,103 +339,72 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null, Action<Jso
330339 ) ) ,
331340 Id = Rpc . Id
332341 } ;
333- return PostProcess ( callback , Rpc , response , RpcContext ) ;
342+ return PostProcess ( Rpc , response , RpcContext ) ;
334343 }
335344
336345 try
337346 {
338- //callback is stored to thread's local storage in order to get it directly from concrete JsonRpcService method implementation
339- //where callback is just returned from method
340- Thread . SetData ( Thread . GetNamedDataSlot ( THREAD_CALLBACK_SLOT_NAME ) , callback ) ;
341-
342-
343347 var results = handle . DynamicInvoke ( parameters ) ;
344348
345349 var last = parameters . LastOrDefault ( ) ;
346- JsonRpcException contextException ;
347- if ( Task . CurrentId . HasValue && RpcExceptions . TryRemove ( Task . CurrentId . Value , out contextException ) )
350+ var contextException = RpcGetAndRemoveRpcException ( ) ;
351+ if ( contextException != null )
348352 {
349353 JsonResponse response = new JsonResponse ( ) { Error = ProcessException ( Rpc , contextException ) , Id = Rpc . Id } ;
350- return PostProcess ( callback , Rpc , response , RpcContext ) ;
354+ return PostProcess ( Rpc , response , RpcContext ) ;
351355 }
352356 if ( expectsRefException && last != null && last is JsonRpcException )
353357 {
354358 JsonResponse response = new JsonResponse ( ) { Error = ProcessException ( Rpc , last as JsonRpcException ) , Id = Rpc . Id } ;
355- return PostProcess ( callback , Rpc , response , RpcContext ) ;
359+ return PostProcess ( Rpc , response , RpcContext ) ;
356360 }
357- //return response, if callback is set (method is asynchronous) - result could be empty string and future result operations
358- //will be processed in the callback
359- return PostProcess ( null , Rpc , new JsonResponse ( ) { Result = results } , RpcContext ) ;
361+ return PostProcess ( Rpc , new JsonResponse ( ) { Result = results } , RpcContext ) ;
360362 }
361363 catch ( Exception ex )
362364 {
363365 JsonResponse response ;
364366 if ( ex is TargetParameterCountException )
365367 {
366368 response = new JsonResponse ( ) { Error = ProcessException ( Rpc , new JsonRpcException ( - 32602 , "Invalid params" , ex ) ) } ;
367- return PostProcess ( callback , Rpc , response , RpcContext ) ;
369+ return PostProcess ( Rpc , response , RpcContext ) ;
368370 }
369371
370372 // We really dont care about the TargetInvocationException, just pass on the inner exception
371373 if ( ex is JsonRpcException )
372374 {
373375 response = new JsonResponse ( ) { Error = ProcessException ( Rpc , ex as JsonRpcException ) } ;
374- return PostProcess ( callback , Rpc , response , RpcContext ) ;
376+ return PostProcess ( Rpc , response , RpcContext ) ;
375377 }
376378 if ( ex . InnerException != null && ex . InnerException is JsonRpcException )
377379 {
378380 response = new JsonResponse ( ) { Error = ProcessException ( Rpc , ex . InnerException as JsonRpcException ) } ;
379- return PostProcess ( callback , Rpc , response , RpcContext ) ;
381+ return PostProcess ( Rpc , response , RpcContext ) ;
380382 }
381383 else if ( ex . InnerException != null )
382384 {
383385 response = new JsonResponse ( ) { Error = ProcessException ( Rpc , new JsonRpcException ( - 32603 , "Internal Error" , ex . InnerException ) ) } ;
384- return PostProcess ( callback , Rpc , response , RpcContext ) ;
386+ return PostProcess ( Rpc , response , RpcContext ) ;
385387 }
386388
387389 response = new JsonResponse ( ) { Error = ProcessException ( Rpc , new JsonRpcException ( - 32603 , "Internal Error" , ex ) ) } ;
388- return PostProcess ( callback , Rpc , response , RpcContext ) ;
390+ return PostProcess ( Rpc , response , RpcContext ) ;
389391 }
390392 finally
391393 {
392394 RemoveRpcContext ( ) ;
393395 }
394396 }
395397 #endregion
396- /// <summary>
397- /// Method returns the actual callback set to this thread in Handle() method.
398- /// If callback is not set, then empty callback is returned.
399- /// </summary>
400- /// <returns></returns>
401- internal Action < JsonResponse > GetAsyncCallback ( )
402- {
403- object o = Thread . GetData ( Thread . GetNamedDataSlot ( THREAD_CALLBACK_SLOT_NAME ) ) ;
404- Action < JsonResponse > callback ;
405- if ( o is Action < JsonResponse > )
406- {
407- callback = o as Action < JsonResponse > ;
408- }
409- else
410- {
411- callback = delegate ( JsonResponse a ) { } ;
412- }
413- return callback ;
414- }
415398
399+ [ ThreadStatic ]
400+ static object __currentRpcContext ;
416401 private void AddRpcContext ( object RpcContext )
417402 {
418- if ( Task . CurrentId != null )
419- RpcContexts [ Task . CurrentId . Value ] = RpcContext ;
403+ __currentRpcContext = RpcContext ;
420404 }
421405 private void RemoveRpcContext ( )
422406 {
423- if ( Task . CurrentId != null )
424- {
425- var id = Task . CurrentId . Value ;
426- RpcContexts [ id ] = null ;
427- object va ;
428- RpcContexts . TryRemove ( id , out va ) ;
429- }
407+ __currentRpcContext = null ;
430408 }
431409
432410 private JsonRpcException ProcessException ( JsonRequest req , JsonRpcException ex )
@@ -449,18 +427,6 @@ internal void SetParseErrorHandler(Func<string, JsonRpcException, JsonRpcExcepti
449427 {
450428 parseErrorHandler = handler ;
451429 }
452-
453- private void RemoveRpcException ( )
454- {
455- if ( Task . CurrentId != null )
456- {
457- var id = Task . CurrentId . Value ;
458- RpcExceptions [ id ] = null ;
459- JsonRpcException va ;
460- RpcExceptions . TryRemove ( id , out va ) ;
461- }
462- }
463-
464430
465431 private object CleanUpParameter ( object p , SMDAdditionalParameters metaData )
466432 {
@@ -531,7 +497,7 @@ private JsonRpcException PreProcess(JsonRequest request, object context)
531497 return externalPreProcessingHandler ( request , context ) ;
532498 }
533499
534- private JsonResponse PostProcess ( Action < JsonResponse > callback , JsonRequest request , JsonResponse response , object context )
500+ private JsonResponse PostProcess ( JsonRequest request , JsonResponse response , object context )
535501 {
536502 if ( externalPostProcessingHandler != null )
537503 {
@@ -548,10 +514,6 @@ private JsonResponse PostProcess(Action<JsonResponse> callback, JsonRequest requ
548514 response = new JsonResponse ( ) { Error = ProcessException ( request , new JsonRpcException ( - 32603 , "Internal Error" , ex ) ) } ;
549515 }
550516 }
551-
552- if ( callback != null )
553- callback . Invoke ( response ) ;
554-
555517 return response ;
556518 }
557519
0 commit comments