ServiceChannelProxy.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Collections;
  7. using System.Collections.Specialized;
  8. using System.Globalization;
  9. using System.Reflection;
  10. using System.Runtime;
  11. using System.Runtime.Diagnostics;
  12. using System.Runtime.Remoting;
  13. using System.Runtime.Remoting.Messaging;
  14. using System.Runtime.Remoting.Proxies;
  15. using System.Security;
  16. using System.ServiceModel.Description;
  17. using System.ServiceModel.Diagnostics;
  18. using System.ServiceModel.Dispatcher;
  19. using System.Threading.Tasks;
  20. [Fx.Tag.SecurityNote(Critical = "Accesses a variety of LinkDemanded classes/methods (especially RealProxy)." +
  21. "Caller should protect access to the ServiceChannelProxy instance after construction.")]
  22. #pragma warning disable 618 // have not moved to the v4 security model yet
  23. [SecurityCritical(SecurityCriticalScope.Everything)]
  24. #pragma warning restore 618
  25. sealed class ServiceChannelProxy : RealProxy, IRemotingTypeInfo
  26. {
  27. const String activityIdSlotName = "E2ETrace.ActivityID";
  28. Type proxiedType;
  29. Type interfaceType;
  30. ServiceChannel serviceChannel;
  31. MbrObject objectWrapper;
  32. ImmutableClientRuntime proxyRuntime;
  33. MethodDataCache methodDataCache;
  34. internal ServiceChannelProxy(Type interfaceType, Type proxiedType, MessageDirection direction, ServiceChannel serviceChannel)
  35. : base(proxiedType)
  36. {
  37. if (!MessageDirectionHelper.IsDefined(direction))
  38. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("direction"));
  39. this.interfaceType = interfaceType;
  40. this.proxiedType = proxiedType;
  41. this.serviceChannel = serviceChannel;
  42. this.proxyRuntime = serviceChannel.ClientRuntime.GetRuntime();
  43. this.methodDataCache = new MethodDataCache();
  44. this.objectWrapper = new MbrObject(this, proxiedType);
  45. }
  46. //Workaround is to set the activityid in remoting call's LogicalCallContext
  47. static LogicalCallContext SetActivityIdInLogicalCallContext(LogicalCallContext logicalCallContext)
  48. {
  49. if (TraceUtility.ActivityTracing)
  50. {
  51. logicalCallContext.SetData(activityIdSlotName, DiagnosticTraceBase.ActivityId);
  52. }
  53. return logicalCallContext;
  54. }
  55. IMethodReturnMessage CreateReturnMessage(object ret, object[] returnArgs, IMethodCallMessage methodCall)
  56. {
  57. if (returnArgs != null)
  58. {
  59. return CreateReturnMessage(ret, returnArgs, returnArgs.Length, SetActivityIdInLogicalCallContext(methodCall.LogicalCallContext), methodCall);
  60. }
  61. else
  62. {
  63. return new SingleReturnMessage(ret, methodCall);
  64. }
  65. }
  66. IMethodReturnMessage CreateReturnMessage(object ret, object[] outArgs, int outArgsCount, LogicalCallContext callCtx, IMethodCallMessage mcm)
  67. {
  68. return new ReturnMessage(ret, outArgs, outArgsCount, callCtx, mcm);
  69. }
  70. IMethodReturnMessage CreateReturnMessage(Exception e, IMethodCallMessage mcm)
  71. {
  72. return new ReturnMessage(e, mcm);
  73. }
  74. MethodData GetMethodData(IMethodCallMessage methodCall)
  75. {
  76. MethodBase method = methodCall.MethodBase;
  77. MethodData methodData;
  78. if (methodDataCache.TryGetMethodData(method, out methodData))
  79. {
  80. return methodData;
  81. }
  82. bool canCacheMessageData;
  83. Type declaringType = method.DeclaringType;
  84. if (declaringType == typeof(object))
  85. {
  86. MethodType methodType;
  87. if (methodCall.MethodBase == typeof(object).GetMethod("GetType"))
  88. {
  89. methodType = MethodType.GetType;
  90. }
  91. else
  92. {
  93. methodType = MethodType.Object;
  94. }
  95. canCacheMessageData = true;
  96. methodData = new MethodData(method, methodType);
  97. }
  98. else if (declaringType.IsInstanceOfType(this.serviceChannel))
  99. {
  100. canCacheMessageData = true;
  101. methodData = new MethodData(method, MethodType.Channel);
  102. }
  103. else
  104. {
  105. ProxyOperationRuntime operation = this.proxyRuntime.GetOperation(method, methodCall.Args, out canCacheMessageData);
  106. if (operation == null)
  107. {
  108. if (this.serviceChannel.Factory != null)
  109. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SFxMethodNotSupported1, method.Name)));
  110. else
  111. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SFxMethodNotSupportedOnCallback1, method.Name)));
  112. }
  113. MethodType methodType;
  114. if (operation.IsTaskCall(methodCall))
  115. {
  116. methodType = MethodType.TaskService;
  117. }
  118. else if (operation.IsSyncCall(methodCall))
  119. {
  120. methodType = MethodType.Service;
  121. }
  122. else if (operation.IsBeginCall(methodCall))
  123. {
  124. methodType = MethodType.BeginService;
  125. }
  126. else
  127. {
  128. methodType = MethodType.EndService;
  129. }
  130. methodData = new MethodData(method, methodType, operation);
  131. }
  132. if (canCacheMessageData)
  133. {
  134. methodDataCache.SetMethodData(methodData);
  135. }
  136. return methodData;
  137. }
  138. internal ServiceChannel GetServiceChannel()
  139. {
  140. return this.serviceChannel;
  141. }
  142. public override IMessage Invoke(IMessage message)
  143. {
  144. try
  145. {
  146. IMethodCallMessage methodCall = message as IMethodCallMessage;
  147. if (methodCall == null)
  148. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SFxExpectedIMethodCallMessage)));
  149. MethodData methodData = GetMethodData(methodCall);
  150. switch (methodData.MethodType)
  151. {
  152. case MethodType.Service:
  153. return InvokeService(methodCall, methodData.Operation);
  154. case MethodType.BeginService:
  155. return InvokeBeginService(methodCall, methodData.Operation);
  156. case MethodType.EndService:
  157. return InvokeEndService(methodCall, methodData.Operation);
  158. case MethodType.TaskService:
  159. return InvokeTaskService(methodCall, methodData.Operation);
  160. case MethodType.Channel:
  161. return InvokeChannel(methodCall);
  162. case MethodType.GetType:
  163. return InvokeGetType(methodCall);
  164. case MethodType.Object:
  165. return InvokeObject(methodCall);
  166. default:
  167. Fx.Assert("Invalid proxy method type");
  168. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid proxy method type")));
  169. }
  170. }
  171. #pragma warning suppress 56500 // covered by FxCOP
  172. catch (Exception e)
  173. {
  174. if (Fx.IsFatal(e))
  175. {
  176. throw;
  177. }
  178. return CreateReturnMessage(e, message as IMethodCallMessage);
  179. }
  180. }
  181. static class TaskCreator
  182. {
  183. static readonly Func<ServiceChannel, ProxyOperationRuntime, object[], AsyncCallback, object, IAsyncResult> beginCallDelegate = ServiceChannel.BeginCall;
  184. static readonly Hashtable createGenericTaskDelegateCache = new Hashtable(); // using Hashtable because it allows for lock-free reads
  185. static readonly MethodInfo createGenericTaskMI = typeof(TaskCreator).GetMethod("CreateGenericTask", new Type[] { typeof(ServiceChannel), typeof(ProxyOperationRuntime), typeof(object[]) });
  186. static Func<ServiceChannel, ProxyOperationRuntime, object[], Task> GetOrCreateTaskDelegate(Type taskResultType)
  187. {
  188. Func<ServiceChannel, ProxyOperationRuntime, object[], Task> createTaskDelegate = createGenericTaskDelegateCache[taskResultType] as Func<ServiceChannel, ProxyOperationRuntime, object[], Task>;
  189. if (createTaskDelegate != null)
  190. {
  191. return createTaskDelegate;
  192. }
  193. lock (createGenericTaskDelegateCache)
  194. {
  195. createTaskDelegate = createGenericTaskDelegateCache[taskResultType] as Func<ServiceChannel, ProxyOperationRuntime, object[], Task>;
  196. if (createTaskDelegate != null)
  197. {
  198. return createTaskDelegate;
  199. }
  200. MethodInfo methodInfo = createGenericTaskMI.MakeGenericMethod(taskResultType);
  201. createTaskDelegate = Delegate.CreateDelegate(typeof(Func<ServiceChannel, ProxyOperationRuntime, object[], Task>), methodInfo) as Func<ServiceChannel, ProxyOperationRuntime, object[], Task>;
  202. createGenericTaskDelegateCache[taskResultType] = createTaskDelegate;
  203. }
  204. return createTaskDelegate;
  205. }
  206. public static Task CreateTask(ServiceChannel channel, IMethodCallMessage methodCall, ProxyOperationRuntime operation)
  207. {
  208. if (operation.TaskTResult == ServiceReflector.VoidType)
  209. {
  210. return TaskCreator.CreateTask(channel, operation, methodCall.InArgs);
  211. }
  212. return TaskCreator.CreateGenericTask(channel, operation, methodCall.InArgs);
  213. }
  214. static Task CreateGenericTask(ServiceChannel channel, ProxyOperationRuntime operation, object[] inputParameters)
  215. {
  216. Func<ServiceChannel, ProxyOperationRuntime, object[], Task> createTaskDelegate = GetOrCreateTaskDelegate(operation.TaskTResult);
  217. return createTaskDelegate(channel, operation, inputParameters);
  218. }
  219. static Task CreateTask(ServiceChannel channel, ProxyOperationRuntime operation, object[] inputParameters)
  220. {
  221. Action<IAsyncResult> endCallDelegate = (asyncResult) =>
  222. {
  223. Fx.Assert(asyncResult != null, "'asyncResult' MUST NOT be NULL.");
  224. OperationContext originalOperationContext = OperationContext.Current;
  225. OperationContext.Current = asyncResult.AsyncState as OperationContext;
  226. try
  227. {
  228. channel.EndCall(operation.Action, ProxyOperationRuntime.EmptyArray, asyncResult);
  229. }
  230. finally
  231. {
  232. OperationContext.Current = originalOperationContext;
  233. }
  234. };
  235. return Task.Factory.FromAsync(beginCallDelegate, endCallDelegate, channel, operation, inputParameters, OperationContext.Current);
  236. }
  237. public static Task<T> CreateGenericTask<T>(ServiceChannel channel, ProxyOperationRuntime operation, object[] inputParameters)
  238. {
  239. Func<IAsyncResult, T> endCallDelegate = (asyncResult) =>
  240. {
  241. OperationContext originalOperationContext = OperationContext.Current;
  242. OperationContext.Current = asyncResult.AsyncState as OperationContext;
  243. try
  244. {
  245. return (T)channel.EndCall(operation.Action, ProxyOperationRuntime.EmptyArray, asyncResult);
  246. }
  247. finally
  248. {
  249. OperationContext.Current = originalOperationContext;
  250. }
  251. };
  252. return Task<T>.Factory.FromAsync<ServiceChannel, ProxyOperationRuntime, object[]>(beginCallDelegate, endCallDelegate, channel, operation, inputParameters, OperationContext.Current);
  253. }
  254. }
  255. IMessage InvokeTaskService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
  256. {
  257. Task task = TaskCreator.CreateTask(this.serviceChannel, methodCall, operation);
  258. return CreateReturnMessage(task, null, methodCall);
  259. }
  260. IMethodReturnMessage InvokeChannel(IMethodCallMessage methodCall)
  261. {
  262. string activityName = null;
  263. ActivityType activityType = ActivityType.Unknown;
  264. if (DiagnosticUtility.ShouldUseActivity)
  265. {
  266. if (ServiceModelActivity.Current == null ||
  267. ServiceModelActivity.Current.ActivityType != ActivityType.Close)
  268. {
  269. MethodData methodData = this.GetMethodData(methodCall);
  270. if (methodData.MethodBase.DeclaringType == typeof(System.ServiceModel.ICommunicationObject)
  271. && methodData.MethodBase.Name.Equals("Close", StringComparison.Ordinal))
  272. {
  273. activityName = SR.GetString(SR.ActivityClose, this.serviceChannel.GetType().FullName);
  274. activityType = ActivityType.Close;
  275. }
  276. }
  277. }
  278. using (ServiceModelActivity activity = string.IsNullOrEmpty(activityName) ? null : ServiceModelActivity.CreateBoundedActivity())
  279. {
  280. if (DiagnosticUtility.ShouldUseActivity)
  281. {
  282. ServiceModelActivity.Start(activity, activityName, activityType);
  283. }
  284. return ExecuteMessage(this.serviceChannel, methodCall);
  285. }
  286. }
  287. IMethodReturnMessage InvokeGetType(IMethodCallMessage methodCall)
  288. {
  289. return CreateReturnMessage(proxiedType, null, 0, SetActivityIdInLogicalCallContext(methodCall.LogicalCallContext), methodCall);
  290. }
  291. IMethodReturnMessage InvokeObject(IMethodCallMessage methodCall)
  292. {
  293. return RemotingServices.ExecuteMessage(this.objectWrapper, methodCall);
  294. }
  295. IMethodReturnMessage InvokeBeginService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
  296. {
  297. AsyncCallback callback;
  298. object asyncState;
  299. object[] ins = operation.MapAsyncBeginInputs(methodCall, out callback, out asyncState);
  300. object ret = this.serviceChannel.BeginCall(operation.Action, operation.IsOneWay, operation, ins, callback, asyncState);
  301. return CreateReturnMessage(ret, null, methodCall);
  302. }
  303. IMethodReturnMessage InvokeEndService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
  304. {
  305. IAsyncResult result;
  306. object[] outs;
  307. operation.MapAsyncEndInputs(methodCall, out result, out outs);
  308. object ret = this.serviceChannel.EndCall(operation.Action, outs, result);
  309. object[] returnArgs = operation.MapAsyncOutputs(methodCall, outs, ref ret);
  310. return CreateReturnMessage(ret, returnArgs, methodCall);
  311. }
  312. IMethodReturnMessage InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
  313. {
  314. object[] outs;
  315. object[] ins = operation.MapSyncInputs(methodCall, out outs);
  316. object ret = this.serviceChannel.Call(operation.Action, operation.IsOneWay, operation, ins, outs);
  317. object[] returnArgs = operation.MapSyncOutputs(methodCall, outs, ref ret);
  318. return CreateReturnMessage(ret, returnArgs, methodCall);
  319. }
  320. IMethodReturnMessage ExecuteMessage(object target, IMethodCallMessage methodCall)
  321. {
  322. MethodBase targetMethod = methodCall.MethodBase;
  323. object[] args = methodCall.Args;
  324. object returnValue = null;
  325. try
  326. {
  327. returnValue = targetMethod.Invoke(target, args);
  328. }
  329. catch (TargetInvocationException e)
  330. {
  331. return CreateReturnMessage(e.InnerException, methodCall);
  332. }
  333. return CreateReturnMessage(returnValue,
  334. args,
  335. args.Length,
  336. null,
  337. methodCall);
  338. }
  339. bool IRemotingTypeInfo.CanCastTo(Type toType, object o)
  340. {
  341. return toType.IsAssignableFrom(proxiedType) || serviceChannel.CanCastTo(toType);
  342. }
  343. string IRemotingTypeInfo.TypeName
  344. {
  345. get { return proxiedType.FullName; }
  346. set { }
  347. }
  348. class MethodDataCache
  349. {
  350. MethodData[] methodDatas;
  351. public MethodDataCache()
  352. {
  353. this.methodDatas = new MethodData[4];
  354. }
  355. object ThisLock
  356. {
  357. get { return this; }
  358. }
  359. public bool TryGetMethodData(MethodBase method, out MethodData methodData)
  360. {
  361. lock (ThisLock)
  362. {
  363. MethodData[] methodDatas = this.methodDatas;
  364. int index = FindMethod(methodDatas, method);
  365. if (index >= 0)
  366. {
  367. methodData = methodDatas[index];
  368. return true;
  369. }
  370. else
  371. {
  372. methodData = new MethodData();
  373. return false;
  374. }
  375. }
  376. }
  377. static int FindMethod(MethodData[] methodDatas, MethodBase methodToFind)
  378. {
  379. for (int i = 0; i < methodDatas.Length; i++)
  380. {
  381. MethodBase method = methodDatas[i].MethodBase;
  382. if (method == null)
  383. {
  384. break;
  385. }
  386. if (method == methodToFind)
  387. {
  388. return i;
  389. }
  390. }
  391. return -1;
  392. }
  393. public void SetMethodData(MethodData methodData)
  394. {
  395. lock (ThisLock)
  396. {
  397. int index = FindMethod(this.methodDatas, methodData.MethodBase);
  398. if (index < 0)
  399. {
  400. for (int i = 0; i < this.methodDatas.Length; i++)
  401. {
  402. if (methodDatas[i].MethodBase == null)
  403. {
  404. methodDatas[i] = methodData;
  405. return;
  406. }
  407. }
  408. MethodData[] newMethodDatas = new MethodData[methodDatas.Length * 2];
  409. Array.Copy(methodDatas, newMethodDatas, methodDatas.Length);
  410. newMethodDatas[methodDatas.Length] = methodData;
  411. this.methodDatas = newMethodDatas;
  412. }
  413. }
  414. }
  415. }
  416. enum MethodType
  417. {
  418. Service,
  419. BeginService,
  420. EndService,
  421. Channel,
  422. Object,
  423. GetType,
  424. TaskService
  425. }
  426. struct MethodData
  427. {
  428. MethodBase methodBase;
  429. MethodType methodType;
  430. ProxyOperationRuntime operation;
  431. public MethodData(MethodBase methodBase, MethodType methodType)
  432. : this(methodBase, methodType, null)
  433. {
  434. }
  435. public MethodData(MethodBase methodBase, MethodType methodType, ProxyOperationRuntime operation)
  436. {
  437. this.methodBase = methodBase;
  438. this.methodType = methodType;
  439. this.operation = operation;
  440. }
  441. public MethodBase MethodBase
  442. {
  443. get { return methodBase; }
  444. }
  445. public MethodType MethodType
  446. {
  447. get { return methodType; }
  448. }
  449. public ProxyOperationRuntime Operation
  450. {
  451. get { return operation; }
  452. }
  453. }
  454. class MbrObject : MarshalByRefObject
  455. {
  456. RealProxy proxy;
  457. Type targetType;
  458. internal MbrObject(RealProxy proxy, Type targetType)
  459. {
  460. this.proxy = proxy;
  461. this.targetType = targetType;
  462. }
  463. public override bool Equals(object obj)
  464. {
  465. return Object.ReferenceEquals(obj, this.proxy.GetTransparentProxy());
  466. }
  467. public override string ToString()
  468. {
  469. return this.targetType.ToString();
  470. }
  471. public override int GetHashCode()
  472. {
  473. return this.proxy.GetHashCode();
  474. }
  475. }
  476. class SingleReturnMessage : IMethodReturnMessage
  477. {
  478. IMethodCallMessage methodCall;
  479. object ret;
  480. PropertyDictionary properties;
  481. public SingleReturnMessage(object ret, IMethodCallMessage methodCall)
  482. {
  483. this.ret = ret;
  484. this.methodCall = methodCall;
  485. this.properties = new PropertyDictionary();
  486. }
  487. public int ArgCount
  488. {
  489. get { return 0; }
  490. }
  491. public object[] Args
  492. {
  493. get { return EmptyArray.Instance; }
  494. }
  495. public Exception Exception
  496. {
  497. get { return null; }
  498. }
  499. public bool HasVarArgs
  500. {
  501. get { return methodCall.HasVarArgs; }
  502. }
  503. public LogicalCallContext LogicalCallContext
  504. {
  505. get { return SetActivityIdInLogicalCallContext(methodCall.LogicalCallContext); }
  506. }
  507. public MethodBase MethodBase
  508. {
  509. get { return methodCall.MethodBase; }
  510. }
  511. public string MethodName
  512. {
  513. get { return methodCall.MethodName; }
  514. }
  515. public object MethodSignature
  516. {
  517. get { return methodCall.MethodSignature; }
  518. }
  519. public object[] OutArgs
  520. {
  521. get { return EmptyArray.Instance; }
  522. }
  523. public int OutArgCount
  524. {
  525. get { return 0; }
  526. }
  527. public IDictionary Properties
  528. {
  529. get { return properties; }
  530. }
  531. public object ReturnValue
  532. {
  533. get { return ret; }
  534. }
  535. public string TypeName
  536. {
  537. get { return methodCall.TypeName; }
  538. }
  539. public string Uri
  540. {
  541. get { return null; }
  542. }
  543. public object GetArg(int index)
  544. {
  545. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index"));
  546. }
  547. public string GetArgName(int index)
  548. {
  549. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index"));
  550. }
  551. public object GetOutArg(int index)
  552. {
  553. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index"));
  554. }
  555. public string GetOutArgName(int index)
  556. {
  557. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index"));
  558. }
  559. class PropertyDictionary : IDictionary
  560. {
  561. ListDictionary properties;
  562. public object this[object key]
  563. {
  564. get { return Properties[key]; }
  565. set { Properties[key] = value; }
  566. }
  567. public int Count
  568. {
  569. get { return Properties.Count; }
  570. }
  571. public bool IsFixedSize
  572. {
  573. get { return false; }
  574. }
  575. public bool IsReadOnly
  576. {
  577. get { return false; }
  578. }
  579. public bool IsSynchronized
  580. {
  581. get { return false; }
  582. }
  583. public ICollection Keys
  584. {
  585. get { return Properties.Keys; }
  586. }
  587. ListDictionary Properties
  588. {
  589. get
  590. {
  591. if (properties == null)
  592. {
  593. properties = new ListDictionary();
  594. }
  595. return properties;
  596. }
  597. }
  598. public ICollection Values
  599. {
  600. get { return Properties.Values; }
  601. }
  602. public object SyncRoot
  603. {
  604. get { return null; }
  605. }
  606. public void Add(object key, object value)
  607. {
  608. Properties.Add(key, value);
  609. }
  610. public void Clear()
  611. {
  612. Properties.Clear();
  613. }
  614. public bool Contains(object key)
  615. {
  616. return Properties.Contains(key);
  617. }
  618. public void CopyTo(Array array, int index)
  619. {
  620. Properties.CopyTo(array, index);
  621. }
  622. public IDictionaryEnumerator GetEnumerator()
  623. {
  624. if (properties == null)
  625. {
  626. return EmptyEnumerator.Instance;
  627. }
  628. else
  629. {
  630. return properties.GetEnumerator();
  631. }
  632. }
  633. IEnumerator IEnumerable.GetEnumerator()
  634. {
  635. return ((IEnumerable)Properties).GetEnumerator();
  636. }
  637. public void Remove(object key)
  638. {
  639. Properties.Remove(key);
  640. }
  641. class EmptyEnumerator : IDictionaryEnumerator
  642. {
  643. static EmptyEnumerator instance = new EmptyEnumerator();
  644. EmptyEnumerator()
  645. {
  646. }
  647. public static EmptyEnumerator Instance
  648. {
  649. get { return instance; }
  650. }
  651. public bool MoveNext()
  652. {
  653. return false;
  654. }
  655. public Object Current
  656. {
  657. get
  658. {
  659. #pragma warning suppress 56503 // [....], IEnumerator guidelines, Current throws exception before calling MoveNext
  660. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxDictionaryIsEmpty)));
  661. }
  662. }
  663. public void Reset()
  664. {
  665. }
  666. public Object Key
  667. {
  668. get
  669. {
  670. #pragma warning suppress 56503 // [....], IEnumerator guidelines, Current throws exception before calling MoveNext
  671. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxDictionaryIsEmpty)));
  672. }
  673. }
  674. public Object Value
  675. {
  676. get
  677. {
  678. #pragma warning suppress 56503 // [....], IEnumerator guidelines, Current throws exception before calling MoveNext
  679. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxDictionaryIsEmpty)));
  680. }
  681. }
  682. public DictionaryEntry Entry
  683. {
  684. get
  685. {
  686. #pragma warning suppress 56503 // [....], IEnumerator guidelines, Current throws exception before calling MoveNext
  687. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxDictionaryIsEmpty)));
  688. }
  689. }
  690. }
  691. }
  692. }
  693. }
  694. }