ServiceBehaviorAttribute.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel
  5. {
  6. using System.ServiceModel.Administration;
  7. using System.ServiceModel.Channels;
  8. using System.ServiceModel.Dispatcher;
  9. using System.ServiceModel.Description;
  10. using System.ServiceModel.Configuration;
  11. using System.Runtime.Serialization;
  12. using System.Collections.ObjectModel;
  13. using System.Collections.Generic;
  14. using System.Threading;
  15. using System.Transactions;
  16. using System.Runtime.CompilerServices;
  17. using System.ComponentModel;
  18. using System.Globalization;
  19. [AttributeUsage(ServiceModelAttributeTargets.ServiceBehavior)]
  20. public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
  21. {
  22. internal static IsolationLevel DefaultIsolationLevel = IsolationLevel.Unspecified;
  23. ConcurrencyMode concurrencyMode = ConcurrencyMode.Single;
  24. bool ensureOrderedDispatch = false;
  25. string configurationName;
  26. bool includeExceptionDetailInFaults = false;
  27. InstanceContextMode instanceMode;
  28. bool releaseServiceInstanceOnTransactionComplete = true;
  29. bool releaseServiceInstanceOnTransactionCompleteSet = false;
  30. bool transactionAutoCompleteOnSessionClose = false;
  31. bool transactionAutoCompleteOnSessionCloseSet = false;
  32. object wellKnownSingleton = null; // if the user passes an object to the ServiceHost, it is stored here
  33. object hiddenSingleton = null; // if the user passes a type to the ServiceHost, and instanceMode==Single, we store the instance here
  34. bool validateMustUnderstand = true;
  35. bool ignoreExtensionDataObject = DataContractSerializerDefaults.IgnoreExtensionDataObject;
  36. int maxItemsInObjectGraph = DataContractSerializerDefaults.MaxItemsInObjectGraph;
  37. IsolationLevel transactionIsolationLevel = DefaultIsolationLevel;
  38. bool isolationLevelSet = false;
  39. bool automaticSessionShutdown = true;
  40. IInstanceProvider instanceProvider = null;
  41. TimeSpan transactionTimeout = TimeSpan.Zero;
  42. string transactionTimeoutString;
  43. bool transactionTimeoutSet = false;
  44. bool useSynchronizationContext = true;
  45. string serviceName = null;
  46. string serviceNamespace = null;
  47. AddressFilterMode addressFilterMode = AddressFilterMode.Exact;
  48. [DefaultValue(null)]
  49. public string Name
  50. {
  51. get { return serviceName; }
  52. set { serviceName = value; }
  53. }
  54. [DefaultValue(null)]
  55. public string Namespace
  56. {
  57. get { return serviceNamespace; }
  58. set { serviceNamespace = value; }
  59. }
  60. internal IInstanceProvider InstanceProvider
  61. {
  62. set { this.instanceProvider = value; }
  63. }
  64. [DefaultValue(AddressFilterMode.Exact)]
  65. public AddressFilterMode AddressFilterMode
  66. {
  67. get { return this.addressFilterMode; }
  68. set
  69. {
  70. if (!AddressFilterModeHelper.IsDefined(value))
  71. {
  72. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
  73. }
  74. this.addressFilterMode = value;
  75. }
  76. }
  77. [DefaultValue(true)]
  78. public bool AutomaticSessionShutdown
  79. {
  80. get { return this.automaticSessionShutdown; }
  81. set { this.automaticSessionShutdown = value; }
  82. }
  83. [DefaultValue(null)]
  84. public string ConfigurationName
  85. {
  86. get { return this.configurationName; }
  87. set
  88. {
  89. if (value == null)
  90. {
  91. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
  92. }
  93. if (value == string.Empty)
  94. {
  95. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value",
  96. SR.GetString(SR.SFxConfigurationNameCannotBeEmpty)));
  97. }
  98. this.configurationName = value;
  99. }
  100. }
  101. public IsolationLevel TransactionIsolationLevel
  102. {
  103. get { return this.transactionIsolationLevel; }
  104. set
  105. {
  106. switch (value)
  107. {
  108. case IsolationLevel.Serializable:
  109. case IsolationLevel.RepeatableRead:
  110. case IsolationLevel.ReadCommitted:
  111. case IsolationLevel.ReadUncommitted:
  112. case IsolationLevel.Unspecified:
  113. case IsolationLevel.Chaos:
  114. case IsolationLevel.Snapshot:
  115. break;
  116. default:
  117. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
  118. }
  119. this.transactionIsolationLevel = value;
  120. isolationLevelSet = true;
  121. }
  122. }
  123. public bool ShouldSerializeTransactionIsolationLevel()
  124. {
  125. return IsolationLevelSet;
  126. }
  127. internal bool IsolationLevelSet
  128. {
  129. get { return this.isolationLevelSet; }
  130. }
  131. [DefaultValue(false)]
  132. public bool IncludeExceptionDetailInFaults
  133. {
  134. get { return this.includeExceptionDetailInFaults; }
  135. set { this.includeExceptionDetailInFaults = value; }
  136. }
  137. [DefaultValue(ConcurrencyMode.Single)]
  138. public ConcurrencyMode ConcurrencyMode
  139. {
  140. get { return this.concurrencyMode; }
  141. set
  142. {
  143. if (!ConcurrencyModeHelper.IsDefined(value))
  144. {
  145. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
  146. }
  147. this.concurrencyMode = value;
  148. }
  149. }
  150. [DefaultValue(false)]
  151. public bool EnsureOrderedDispatch
  152. {
  153. get { return this.ensureOrderedDispatch; }
  154. set { this.ensureOrderedDispatch = value; }
  155. }
  156. [DefaultValue(InstanceContextMode.PerSession)]
  157. public InstanceContextMode InstanceContextMode
  158. {
  159. get { return this.instanceMode; }
  160. set
  161. {
  162. if (!InstanceContextModeHelper.IsDefined(value))
  163. {
  164. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
  165. }
  166. this.instanceMode = value;
  167. }
  168. }
  169. public bool ReleaseServiceInstanceOnTransactionComplete
  170. {
  171. get { return releaseServiceInstanceOnTransactionComplete; }
  172. set
  173. {
  174. this.releaseServiceInstanceOnTransactionComplete = value;
  175. this.releaseServiceInstanceOnTransactionCompleteSet = true;
  176. }
  177. }
  178. public bool ShouldSerializeConfigurationName()
  179. {
  180. return this.configurationName != null;
  181. }
  182. public bool ShouldSerializeReleaseServiceInstanceOnTransactionComplete()
  183. {
  184. return ReleaseServiceInstanceOnTransactionCompleteSet;
  185. }
  186. internal bool ReleaseServiceInstanceOnTransactionCompleteSet
  187. {
  188. get { return this.releaseServiceInstanceOnTransactionCompleteSet; }
  189. }
  190. public bool TransactionAutoCompleteOnSessionClose
  191. {
  192. get { return transactionAutoCompleteOnSessionClose; }
  193. set
  194. {
  195. this.transactionAutoCompleteOnSessionClose = value;
  196. this.transactionAutoCompleteOnSessionCloseSet = true;
  197. }
  198. }
  199. public bool ShouldSerializeTransactionAutoCompleteOnSessionClose()
  200. {
  201. return TransactionAutoCompleteOnSessionCloseSet;
  202. }
  203. internal bool TransactionAutoCompleteOnSessionCloseSet
  204. {
  205. get { return this.transactionAutoCompleteOnSessionCloseSet; }
  206. }
  207. public string TransactionTimeout
  208. {
  209. get { return transactionTimeoutString; }
  210. set
  211. {
  212. if (value == null)
  213. {
  214. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
  215. }
  216. try
  217. {
  218. TimeSpan timeout = TimeSpan.Parse(value, CultureInfo.InvariantCulture);
  219. if (timeout < TimeSpan.Zero)
  220. {
  221. string message = SR.GetString(SR.SFxTimeoutOutOfRange0);
  222. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, message));
  223. }
  224. this.transactionTimeout = timeout;
  225. this.transactionTimeoutString = value;
  226. this.transactionTimeoutSet = true;
  227. }
  228. catch (FormatException e)
  229. {
  230. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SFxTimeoutInvalidStringFormat), "value", e));
  231. }
  232. catch (OverflowException)
  233. {
  234. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
  235. }
  236. }
  237. }
  238. public bool ShouldSerializeTransactionTimeout()
  239. {
  240. return TransactionTimeoutSet;
  241. }
  242. internal TimeSpan TransactionTimeoutTimespan
  243. {
  244. get { return this.transactionTimeout; }
  245. }
  246. internal bool TransactionTimeoutSet
  247. {
  248. get { return this.transactionTimeoutSet; }
  249. }
  250. [DefaultValue(true)]
  251. public bool ValidateMustUnderstand
  252. {
  253. get { return validateMustUnderstand; }
  254. set { validateMustUnderstand = value; }
  255. }
  256. [DefaultValue(DataContractSerializerDefaults.IgnoreExtensionDataObject)]
  257. public bool IgnoreExtensionDataObject
  258. {
  259. get { return ignoreExtensionDataObject; }
  260. set { ignoreExtensionDataObject = value; }
  261. }
  262. [DefaultValue(DataContractSerializerDefaults.MaxItemsInObjectGraph)]
  263. public int MaxItemsInObjectGraph
  264. {
  265. get { return maxItemsInObjectGraph; }
  266. set { maxItemsInObjectGraph = value; }
  267. }
  268. [DefaultValue(true)]
  269. public bool UseSynchronizationContext
  270. {
  271. get { return this.useSynchronizationContext; }
  272. set { this.useSynchronizationContext = value; }
  273. }
  274. public object GetWellKnownSingleton()
  275. {
  276. return this.wellKnownSingleton;
  277. }
  278. public void SetWellKnownSingleton(object value)
  279. {
  280. if (value == null)
  281. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
  282. this.wellKnownSingleton = value;
  283. }
  284. internal object GetHiddenSingleton()
  285. {
  286. return this.hiddenSingleton;
  287. }
  288. internal void SetHiddenSingleton(object value)
  289. {
  290. if (value == null)
  291. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
  292. this.hiddenSingleton = value;
  293. }
  294. [MethodImpl(MethodImplOptions.NoInlining)]
  295. void SetIsolationLevel(ChannelDispatcher channelDispatcher)
  296. {
  297. if (channelDispatcher == null)
  298. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("channelDispatcher");
  299. channelDispatcher.TransactionIsolationLevel = this.transactionIsolationLevel;
  300. }
  301. void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
  302. {
  303. if (this.concurrencyMode != ConcurrencyMode.Single && this.ensureOrderedDispatch)
  304. {
  305. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNonConcurrentOrEnsureOrderedDispatch, description.Name)));
  306. }
  307. }
  308. void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
  309. {
  310. }
  311. void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
  312. {
  313. for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
  314. {
  315. ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
  316. if (channelDispatcher != null)
  317. {
  318. channelDispatcher.IncludeExceptionDetailInFaults = this.includeExceptionDetailInFaults;
  319. if (channelDispatcher.HasApplicationEndpoints())
  320. {
  321. channelDispatcher.TransactionTimeout = transactionTimeout;
  322. if (isolationLevelSet)
  323. SetIsolationLevel(channelDispatcher);
  324. foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
  325. {
  326. if (endpointDispatcher.IsSystemEndpoint)
  327. {
  328. continue;
  329. }
  330. DispatchRuntime behavior = endpointDispatcher.DispatchRuntime;
  331. behavior.ConcurrencyMode = this.concurrencyMode;
  332. behavior.EnsureOrderedDispatch = this.ensureOrderedDispatch;
  333. behavior.ValidateMustUnderstand = validateMustUnderstand;
  334. behavior.AutomaticInputSessionShutdown = this.automaticSessionShutdown;
  335. behavior.TransactionAutoCompleteOnSessionClose = this.transactionAutoCompleteOnSessionClose;
  336. behavior.ReleaseServiceInstanceOnTransactionComplete = this.releaseServiceInstanceOnTransactionComplete;
  337. if (!this.useSynchronizationContext)
  338. {
  339. behavior.SynchronizationContext = null;
  340. }
  341. if (!endpointDispatcher.AddressFilterSetExplicit)
  342. {
  343. EndpointAddress address = endpointDispatcher.OriginalAddress;
  344. if (address == null || this.AddressFilterMode == AddressFilterMode.Any)
  345. {
  346. endpointDispatcher.AddressFilter = new MatchAllMessageFilter();
  347. }
  348. else if (this.AddressFilterMode == AddressFilterMode.Prefix)
  349. {
  350. endpointDispatcher.AddressFilter = new PrefixEndpointAddressMessageFilter(address);
  351. }
  352. else if (this.AddressFilterMode == AddressFilterMode.Exact)
  353. {
  354. endpointDispatcher.AddressFilter = new EndpointAddressMessageFilter(address);
  355. }
  356. }
  357. }
  358. }
  359. #pragma warning suppress 56506
  360. }
  361. }
  362. DataContractSerializerServiceBehavior.ApplySerializationSettings(description, ignoreExtensionDataObject, maxItemsInObjectGraph);
  363. ApplyInstancing(description, serviceHostBase);
  364. }
  365. void ApplyInstancing(ServiceDescription description, ServiceHostBase serviceHostBase)
  366. {
  367. Type serviceType = description.ServiceType;
  368. InstanceContext singleton = null;
  369. for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
  370. {
  371. ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
  372. if (channelDispatcher != null)
  373. {
  374. foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
  375. {
  376. if (endpointDispatcher.IsSystemEndpoint)
  377. {
  378. continue;
  379. }
  380. DispatchRuntime dispatch = endpointDispatcher.DispatchRuntime;
  381. if (dispatch.InstanceProvider == null)
  382. {
  383. if (instanceProvider == null)
  384. {
  385. if (serviceType == null && this.wellKnownSingleton == null)
  386. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InstanceSettingsMustHaveTypeOrWellKnownObject0)));
  387. if (this.instanceMode != InstanceContextMode.Single && this.wellKnownSingleton != null)
  388. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxWellKnownNonSingleton0)));
  389. }
  390. else
  391. {
  392. dispatch.InstanceProvider = instanceProvider;
  393. }
  394. }
  395. dispatch.Type = serviceType;
  396. dispatch.InstanceContextProvider = InstanceContextProviderBase.GetProviderForMode(this.instanceMode, dispatch);
  397. if ((this.instanceMode == InstanceContextMode.Single) &&
  398. (dispatch.SingletonInstanceContext == null))
  399. {
  400. if (singleton == null)
  401. {
  402. if (this.wellKnownSingleton != null)
  403. {
  404. singleton = new InstanceContext(serviceHostBase, this.wellKnownSingleton, true, false);
  405. }
  406. else if (this.hiddenSingleton != null)
  407. {
  408. singleton = new InstanceContext(serviceHostBase, this.hiddenSingleton, false, false);
  409. }
  410. else
  411. {
  412. singleton = new InstanceContext(serviceHostBase, false);
  413. }
  414. singleton.AutoClose = false;
  415. }
  416. dispatch.SingletonInstanceContext = singleton;
  417. }
  418. }
  419. }
  420. }
  421. }
  422. }
  423. }