ClientRuntime.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.ComponentModel;
  9. using System.Collections.ObjectModel;
  10. using System.Diagnostics.CodeAnalysis;
  11. using System.Net;
  12. using System.Runtime;
  13. using System.ServiceModel.Channels;
  14. using System.ServiceModel.Security;
  15. using System.Xml;
  16. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Compat", Justification = "Compat is an accepted abbreviation")]
  17. [EditorBrowsable(EditorBrowsableState.Never)]
  18. public class ClientRuntimeCompatBase
  19. {
  20. internal ClientRuntimeCompatBase() { }
  21. [EditorBrowsable(EditorBrowsableState.Never)]
  22. [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
  23. public IList<IClientMessageInspector> MessageInspectors
  24. {
  25. get
  26. {
  27. return this.messageInspectors;
  28. }
  29. }
  30. [EditorBrowsable(EditorBrowsableState.Never)]
  31. [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
  32. public KeyedCollection<string, ClientOperation> Operations
  33. {
  34. get
  35. {
  36. return this.compatOperations;
  37. }
  38. }
  39. internal SynchronizedCollection<IClientMessageInspector> messageInspectors;
  40. internal SynchronizedKeyedCollection<string, ClientOperation> operations;
  41. internal KeyedCollection<string, ClientOperation> compatOperations;
  42. }
  43. public sealed class ClientRuntime : ClientRuntimeCompatBase
  44. {
  45. bool addTransactionFlowProperties = true;
  46. Type callbackProxyType;
  47. ProxyBehaviorCollection<IChannelInitializer> channelInitializers;
  48. string contractName;
  49. string contractNamespace;
  50. Type contractProxyType;
  51. DispatchRuntime dispatchRuntime;
  52. IdentityVerifier identityVerifier;
  53. ProxyBehaviorCollection<IInteractiveChannelInitializer> interactiveChannelInitializers;
  54. IClientOperationSelector operationSelector;
  55. ImmutableClientRuntime runtime;
  56. ClientOperation unhandled;
  57. bool useSynchronizationContext = true;
  58. Uri via;
  59. SharedRuntimeState shared;
  60. int maxFaultSize;
  61. bool messageVersionNoneFaultsEnabled;
  62. internal ClientRuntime(DispatchRuntime dispatchRuntime, SharedRuntimeState shared)
  63. : this(dispatchRuntime.EndpointDispatcher.ContractName,
  64. dispatchRuntime.EndpointDispatcher.ContractNamespace,
  65. shared)
  66. {
  67. if (dispatchRuntime == null)
  68. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dispatchRuntime");
  69. this.dispatchRuntime = dispatchRuntime;
  70. this.shared = shared;
  71. Fx.Assert(shared.IsOnServer, "Server constructor called on client?");
  72. }
  73. internal ClientRuntime(string contractName, string contractNamespace)
  74. : this(contractName, contractNamespace, new SharedRuntimeState(false))
  75. {
  76. Fx.Assert(!shared.IsOnServer, "Client constructor called on server?");
  77. }
  78. ClientRuntime(string contractName, string contractNamespace, SharedRuntimeState shared)
  79. {
  80. this.contractName = contractName;
  81. this.contractNamespace = contractNamespace;
  82. this.shared = shared;
  83. OperationCollection operations = new OperationCollection(this);
  84. this.operations = operations;
  85. this.compatOperations = new OperationCollectionWrapper(operations);
  86. this.channelInitializers = new ProxyBehaviorCollection<IChannelInitializer>(this);
  87. this.messageInspectors = new ProxyBehaviorCollection<IClientMessageInspector>(this);
  88. this.interactiveChannelInitializers = new ProxyBehaviorCollection<IInteractiveChannelInitializer>(this);
  89. this.unhandled = new ClientOperation(this, "*", MessageHeaders.WildcardAction, MessageHeaders.WildcardAction);
  90. this.unhandled.InternalFormatter = new MessageOperationFormatter();
  91. this.maxFaultSize = TransportDefaults.MaxFaultSize;
  92. }
  93. internal bool AddTransactionFlowProperties
  94. {
  95. get { return this.addTransactionFlowProperties; }
  96. set
  97. {
  98. lock (this.ThisLock)
  99. {
  100. this.InvalidateRuntime();
  101. this.addTransactionFlowProperties = value;
  102. }
  103. }
  104. }
  105. public Type CallbackClientType
  106. {
  107. get { return this.callbackProxyType; }
  108. set
  109. {
  110. lock (this.ThisLock)
  111. {
  112. this.InvalidateRuntime();
  113. this.callbackProxyType = value;
  114. }
  115. }
  116. }
  117. public SynchronizedCollection<IChannelInitializer> ChannelInitializers
  118. {
  119. get { return this.channelInitializers; }
  120. }
  121. public string ContractName
  122. {
  123. get { return this.contractName; }
  124. }
  125. public string ContractNamespace
  126. {
  127. get { return this.contractNamespace; }
  128. }
  129. public Type ContractClientType
  130. {
  131. get { return this.contractProxyType; }
  132. set
  133. {
  134. lock (this.ThisLock)
  135. {
  136. this.InvalidateRuntime();
  137. this.contractProxyType = value;
  138. }
  139. }
  140. }
  141. internal IdentityVerifier IdentityVerifier
  142. {
  143. get
  144. {
  145. if (this.identityVerifier == null)
  146. {
  147. this.identityVerifier = IdentityVerifier.CreateDefault();
  148. }
  149. return this.identityVerifier;
  150. }
  151. set
  152. {
  153. if (value == null)
  154. {
  155. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
  156. }
  157. this.InvalidateRuntime();
  158. this.identityVerifier = value;
  159. }
  160. }
  161. public Uri Via
  162. {
  163. get { return this.via; }
  164. set
  165. {
  166. lock (this.ThisLock)
  167. {
  168. this.InvalidateRuntime();
  169. this.via = value;
  170. }
  171. }
  172. }
  173. public bool ValidateMustUnderstand
  174. {
  175. get { return this.shared.ValidateMustUnderstand; }
  176. set
  177. {
  178. lock (this.ThisLock)
  179. {
  180. this.InvalidateRuntime();
  181. this.shared.ValidateMustUnderstand = value;
  182. }
  183. }
  184. }
  185. public bool MessageVersionNoneFaultsEnabled
  186. {
  187. get
  188. {
  189. return this.messageVersionNoneFaultsEnabled;
  190. }
  191. set
  192. {
  193. this.InvalidateRuntime();
  194. this.messageVersionNoneFaultsEnabled = value;
  195. }
  196. }
  197. internal DispatchRuntime DispatchRuntime
  198. {
  199. get { return this.dispatchRuntime; }
  200. }
  201. public DispatchRuntime CallbackDispatchRuntime
  202. {
  203. get
  204. {
  205. if (this.dispatchRuntime == null)
  206. this.dispatchRuntime = new DispatchRuntime(this, this.shared);
  207. return this.dispatchRuntime;
  208. }
  209. }
  210. internal bool EnableFaults
  211. {
  212. get
  213. {
  214. if (this.IsOnServer)
  215. {
  216. return this.dispatchRuntime.EnableFaults;
  217. }
  218. else
  219. {
  220. return this.shared.EnableFaults;
  221. }
  222. }
  223. set
  224. {
  225. lock (this.ThisLock)
  226. {
  227. if (this.IsOnServer)
  228. {
  229. string text = SR.GetString(SR.SFxSetEnableFaultsOnChannelDispatcher0);
  230. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(text));
  231. }
  232. else
  233. {
  234. this.InvalidateRuntime();
  235. this.shared.EnableFaults = value;
  236. }
  237. }
  238. }
  239. }
  240. public SynchronizedCollection<IInteractiveChannelInitializer> InteractiveChannelInitializers
  241. {
  242. get { return this.interactiveChannelInitializers; }
  243. }
  244. public int MaxFaultSize
  245. {
  246. get
  247. {
  248. return this.maxFaultSize;
  249. }
  250. set
  251. {
  252. this.InvalidateRuntime();
  253. this.maxFaultSize = value;
  254. }
  255. }
  256. internal bool IsOnServer
  257. {
  258. get { return this.shared.IsOnServer; }
  259. }
  260. public bool ManualAddressing
  261. {
  262. get
  263. {
  264. if (this.IsOnServer)
  265. {
  266. return this.dispatchRuntime.ManualAddressing;
  267. }
  268. else
  269. {
  270. return this.shared.ManualAddressing;
  271. }
  272. }
  273. set
  274. {
  275. lock (this.ThisLock)
  276. {
  277. if (this.IsOnServer)
  278. {
  279. string text = SR.GetString(SR.SFxSetManualAddresssingOnChannelDispatcher0);
  280. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(text));
  281. }
  282. else
  283. {
  284. this.InvalidateRuntime();
  285. this.shared.ManualAddressing = value;
  286. }
  287. }
  288. }
  289. }
  290. internal int MaxParameterInspectors
  291. {
  292. get
  293. {
  294. lock (this.ThisLock)
  295. {
  296. int max = 0;
  297. for (int i = 0; i < this.operations.Count; i++)
  298. max = System.Math.Max(max, this.operations[i].ParameterInspectors.Count);
  299. return max;
  300. }
  301. }
  302. }
  303. public ICollection<IClientMessageInspector> ClientMessageInspectors
  304. {
  305. get { return this.MessageInspectors; }
  306. }
  307. [EditorBrowsable(EditorBrowsableState.Never)]
  308. public new SynchronizedCollection<IClientMessageInspector> MessageInspectors
  309. {
  310. get { return this.messageInspectors; }
  311. }
  312. public ICollection<ClientOperation> ClientOperations
  313. {
  314. get { return this.Operations; }
  315. }
  316. [EditorBrowsable(EditorBrowsableState.Never)]
  317. public new SynchronizedKeyedCollection<string, ClientOperation> Operations
  318. {
  319. get { return this.operations; }
  320. }
  321. public IClientOperationSelector OperationSelector
  322. {
  323. get { return this.operationSelector; }
  324. set
  325. {
  326. lock (this.ThisLock)
  327. {
  328. this.InvalidateRuntime();
  329. this.operationSelector = value;
  330. }
  331. }
  332. }
  333. internal object ThisLock
  334. {
  335. get { return this.shared; }
  336. }
  337. public ClientOperation UnhandledClientOperation
  338. {
  339. get { return this.unhandled; }
  340. }
  341. internal bool UseSynchronizationContext
  342. {
  343. get { return this.useSynchronizationContext; }
  344. set
  345. {
  346. lock (this.ThisLock)
  347. {
  348. this.InvalidateRuntime();
  349. this.useSynchronizationContext = value;
  350. }
  351. }
  352. }
  353. internal T[] GetArray<T>(SynchronizedCollection<T> collection)
  354. {
  355. lock (collection.SyncRoot)
  356. {
  357. if (collection.Count == 0)
  358. {
  359. return EmptyArray<T>.Instance;
  360. }
  361. else
  362. {
  363. T[] array = new T[collection.Count];
  364. collection.CopyTo(array, 0);
  365. return array;
  366. }
  367. }
  368. }
  369. internal ImmutableClientRuntime GetRuntime()
  370. {
  371. lock (this.ThisLock)
  372. {
  373. if (this.runtime == null)
  374. this.runtime = new ImmutableClientRuntime(this);
  375. return this.runtime;
  376. }
  377. }
  378. internal void InvalidateRuntime()
  379. {
  380. lock (this.ThisLock)
  381. {
  382. this.shared.ThrowIfImmutable();
  383. this.runtime = null;
  384. }
  385. }
  386. internal void LockDownProperties()
  387. {
  388. this.shared.LockDownProperties();
  389. }
  390. internal SynchronizedCollection<T> NewBehaviorCollection<T>()
  391. {
  392. return new ProxyBehaviorCollection<T>(this);
  393. }
  394. internal bool IsFault(ref Message reply)
  395. {
  396. if (reply == null)
  397. {
  398. return false;
  399. }
  400. if (reply.IsFault)
  401. {
  402. return true;
  403. }
  404. if (this.MessageVersionNoneFaultsEnabled && IsMessageVersionNoneFault(ref reply, this.MaxFaultSize))
  405. {
  406. return true;
  407. }
  408. return false;
  409. }
  410. internal static bool IsMessageVersionNoneFault(ref Message message, int maxFaultSize)
  411. {
  412. if (message.Version != MessageVersion.None || message.IsEmpty)
  413. {
  414. return false;
  415. }
  416. HttpResponseMessageProperty prop = message.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
  417. if (prop == null || prop.StatusCode != HttpStatusCode.InternalServerError)
  418. {
  419. return false;
  420. }
  421. using (MessageBuffer buffer = message.CreateBufferedCopy(maxFaultSize))
  422. {
  423. message.Close();
  424. message = buffer.CreateMessage();
  425. using (Message copy = buffer.CreateMessage())
  426. {
  427. using (XmlDictionaryReader reader = copy.GetReaderAtBodyContents())
  428. {
  429. return reader.IsStartElement(XD.MessageDictionary.Fault, MessageVersion.None.Envelope.DictionaryNamespace);
  430. }
  431. }
  432. }
  433. }
  434. class ProxyBehaviorCollection<T> : SynchronizedCollection<T>
  435. {
  436. ClientRuntime outer;
  437. internal ProxyBehaviorCollection(ClientRuntime outer)
  438. : base(outer.ThisLock)
  439. {
  440. this.outer = outer;
  441. }
  442. protected override void ClearItems()
  443. {
  444. this.outer.InvalidateRuntime();
  445. base.ClearItems();
  446. }
  447. protected override void InsertItem(int index, T item)
  448. {
  449. if (item == null)
  450. {
  451. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item");
  452. }
  453. this.outer.InvalidateRuntime();
  454. base.InsertItem(index, item);
  455. }
  456. protected override void RemoveItem(int index)
  457. {
  458. this.outer.InvalidateRuntime();
  459. base.RemoveItem(index);
  460. }
  461. protected override void SetItem(int index, T item)
  462. {
  463. if (item == null)
  464. {
  465. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item");
  466. }
  467. this.outer.InvalidateRuntime();
  468. base.SetItem(index, item);
  469. }
  470. }
  471. class OperationCollection : SynchronizedKeyedCollection<string, ClientOperation>
  472. {
  473. ClientRuntime outer;
  474. internal OperationCollection(ClientRuntime outer)
  475. : base(outer.ThisLock)
  476. {
  477. this.outer = outer;
  478. }
  479. protected override void ClearItems()
  480. {
  481. this.outer.InvalidateRuntime();
  482. base.ClearItems();
  483. }
  484. protected override string GetKeyForItem(ClientOperation item)
  485. {
  486. return item.Name;
  487. }
  488. protected override void InsertItem(int index, ClientOperation item)
  489. {
  490. if (item == null)
  491. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item");
  492. if (item.Parent != this.outer)
  493. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxMismatchedOperationParent));
  494. this.outer.InvalidateRuntime();
  495. base.InsertItem(index, item);
  496. }
  497. protected override void RemoveItem(int index)
  498. {
  499. this.outer.InvalidateRuntime();
  500. base.RemoveItem(index);
  501. }
  502. protected override void SetItem(int index, ClientOperation item)
  503. {
  504. if (item == null)
  505. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item");
  506. if (item.Parent != this.outer)
  507. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxMismatchedOperationParent));
  508. this.outer.InvalidateRuntime();
  509. base.SetItem(index, item);
  510. }
  511. internal void InternalClearItems() { this.ClearItems(); }
  512. internal string InternalGetKeyForItem(ClientOperation item) { return this.GetKeyForItem(item); }
  513. internal void InternalInsertItem(int index, ClientOperation item) { this.InsertItem(index, item); }
  514. internal void InternalRemoveItem(int index) { this.RemoveItem(index); }
  515. internal void InternalSetItem(int index, ClientOperation item) { this.SetItem(index, item); }
  516. }
  517. class OperationCollectionWrapper : KeyedCollection<string, ClientOperation>
  518. {
  519. OperationCollection inner;
  520. internal OperationCollectionWrapper(OperationCollection inner) { this.inner = inner; }
  521. protected override void ClearItems() { this.inner.InternalClearItems(); }
  522. protected override string GetKeyForItem(ClientOperation item) { return this.inner.InternalGetKeyForItem(item); }
  523. protected override void InsertItem(int index, ClientOperation item) { this.inner.InternalInsertItem(index, item); }
  524. protected override void RemoveItem(int index) { this.inner.InternalRemoveItem(index); }
  525. protected override void SetItem(int index, ClientOperation item) { this.inner.InternalSetItem(index, item); }
  526. }
  527. }
  528. }