OperationContext.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel
  5. {
  6. using System.Collections.Generic;
  7. using System.ComponentModel;
  8. using System.Runtime;
  9. using System.Security.Claims;
  10. using System.Security.Principal;
  11. using System.ServiceModel.Channels;
  12. using System.ServiceModel.Dispatcher;
  13. using System.ServiceModel.Security;
  14. public sealed class OperationContext : IExtensibleObject<OperationContext>
  15. {
  16. [ThreadStatic]
  17. static Holder currentContext;
  18. ServiceChannel channel;
  19. Message clientReply;
  20. bool closeClientReply;
  21. ExtensionCollection<OperationContext> extensions;
  22. ServiceHostBase host;
  23. RequestContext requestContext;
  24. Message request;
  25. InstanceContext instanceContext;
  26. bool isServiceReentrant = false;
  27. internal IPrincipal threadPrincipal;
  28. TransactionRpcFacet txFacet;
  29. MessageProperties outgoingMessageProperties;
  30. MessageHeaders outgoingMessageHeaders;
  31. MessageVersion outgoingMessageVersion;
  32. EndpointDispatcher endpointDispatcher;
  33. public event EventHandler OperationCompleted;
  34. public OperationContext(IContextChannel channel)
  35. {
  36. if (channel == null)
  37. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("channel"));
  38. ServiceChannel serviceChannel = channel as ServiceChannel;
  39. //Could be a TransparentProxy
  40. if (serviceChannel == null)
  41. {
  42. serviceChannel = ServiceChannelFactory.GetServiceChannel(channel);
  43. }
  44. if (serviceChannel != null)
  45. {
  46. this.outgoingMessageVersion = serviceChannel.MessageVersion;
  47. this.channel = serviceChannel;
  48. }
  49. else
  50. {
  51. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidChannelToOperationContext)));
  52. }
  53. }
  54. internal OperationContext(ServiceHostBase host)
  55. : this(host, MessageVersion.Soap12WSAddressing10)
  56. {
  57. }
  58. internal OperationContext(ServiceHostBase host, MessageVersion outgoingMessageVersion)
  59. {
  60. if (outgoingMessageVersion == null)
  61. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("outgoingMessageVersion"));
  62. this.host = host;
  63. this.outgoingMessageVersion = outgoingMessageVersion;
  64. }
  65. internal OperationContext(RequestContext requestContext, Message request, ServiceChannel channel, ServiceHostBase host)
  66. {
  67. this.channel = channel;
  68. this.host = host;
  69. this.requestContext = requestContext;
  70. this.request = request;
  71. this.outgoingMessageVersion = channel.MessageVersion;
  72. }
  73. public IContextChannel Channel
  74. {
  75. get { return this.GetCallbackChannel<IContextChannel>(); }
  76. }
  77. public static OperationContext Current
  78. {
  79. get
  80. {
  81. return CurrentHolder.Context;
  82. }
  83. set
  84. {
  85. CurrentHolder.Context = value;
  86. }
  87. }
  88. internal static Holder CurrentHolder
  89. {
  90. get
  91. {
  92. Holder holder = OperationContext.currentContext;
  93. if (holder == null)
  94. {
  95. holder = new Holder();
  96. OperationContext.currentContext = holder;
  97. }
  98. return holder;
  99. }
  100. }
  101. public EndpointDispatcher EndpointDispatcher
  102. {
  103. get
  104. {
  105. return this.endpointDispatcher;
  106. }
  107. set
  108. {
  109. this.endpointDispatcher = value;
  110. }
  111. }
  112. public bool IsUserContext
  113. {
  114. get
  115. {
  116. return (this.request == null);
  117. }
  118. }
  119. public IExtensionCollection<OperationContext> Extensions
  120. {
  121. get
  122. {
  123. if (this.extensions == null)
  124. {
  125. this.extensions = new ExtensionCollection<OperationContext>(this);
  126. }
  127. return this.extensions;
  128. }
  129. }
  130. internal bool IsServiceReentrant
  131. {
  132. get { return this.isServiceReentrant; }
  133. set { this.isServiceReentrant = value; }
  134. }
  135. public bool HasSupportingTokens
  136. {
  137. get
  138. {
  139. MessageProperties properties = this.IncomingMessageProperties;
  140. return properties != null && properties.Security != null &&
  141. properties.Security.HasIncomingSupportingTokens;
  142. }
  143. }
  144. public ServiceHostBase Host
  145. {
  146. get { return this.host; }
  147. }
  148. internal Message IncomingMessage
  149. {
  150. get { return this.clientReply ?? this.request; }
  151. }
  152. internal ServiceChannel InternalServiceChannel
  153. {
  154. get { return this.channel; }
  155. set { this.channel = value; }
  156. }
  157. internal bool HasOutgoingMessageHeaders
  158. {
  159. get { return (this.outgoingMessageHeaders != null); }
  160. }
  161. public MessageHeaders OutgoingMessageHeaders
  162. {
  163. get
  164. {
  165. if (this.outgoingMessageHeaders == null)
  166. this.outgoingMessageHeaders = new MessageHeaders(this.OutgoingMessageVersion);
  167. return this.outgoingMessageHeaders;
  168. }
  169. }
  170. internal bool HasOutgoingMessageProperties
  171. {
  172. get { return (this.outgoingMessageProperties != null); }
  173. }
  174. public MessageProperties OutgoingMessageProperties
  175. {
  176. get
  177. {
  178. if (this.outgoingMessageProperties == null)
  179. this.outgoingMessageProperties = new MessageProperties();
  180. return this.outgoingMessageProperties;
  181. }
  182. }
  183. internal MessageVersion OutgoingMessageVersion
  184. {
  185. get { return this.outgoingMessageVersion; }
  186. }
  187. public MessageHeaders IncomingMessageHeaders
  188. {
  189. get
  190. {
  191. Message message = this.clientReply ?? this.request;
  192. if (message != null)
  193. return message.Headers;
  194. else
  195. return null;
  196. }
  197. }
  198. public MessageProperties IncomingMessageProperties
  199. {
  200. get
  201. {
  202. Message message = this.clientReply ?? this.request;
  203. if (message != null)
  204. return message.Properties;
  205. else
  206. return null;
  207. }
  208. }
  209. public MessageVersion IncomingMessageVersion
  210. {
  211. get
  212. {
  213. Message message = this.clientReply ?? this.request;
  214. if (message != null)
  215. return message.Version;
  216. else
  217. return null;
  218. }
  219. }
  220. public InstanceContext InstanceContext
  221. {
  222. get { return this.instanceContext; }
  223. }
  224. public RequestContext RequestContext
  225. {
  226. get { return this.requestContext; }
  227. set { this.requestContext = value; }
  228. }
  229. public ServiceSecurityContext ServiceSecurityContext
  230. {
  231. get
  232. {
  233. MessageProperties properties = this.IncomingMessageProperties;
  234. if (properties != null && properties.Security != null)
  235. {
  236. return properties.Security.ServiceSecurityContext;
  237. }
  238. return null;
  239. }
  240. }
  241. public string SessionId
  242. {
  243. get
  244. {
  245. if (this.channel != null)
  246. {
  247. IChannel inner = this.channel.InnerChannel;
  248. if (inner != null)
  249. {
  250. ISessionChannel<IDuplexSession> duplex = inner as ISessionChannel<IDuplexSession>;
  251. if ((duplex != null) && (duplex.Session != null))
  252. return duplex.Session.Id;
  253. ISessionChannel<IInputSession> input = inner as ISessionChannel<IInputSession>;
  254. if ((input != null) && (input.Session != null))
  255. return input.Session.Id;
  256. ISessionChannel<IOutputSession> output = inner as ISessionChannel<IOutputSession>;
  257. if ((output != null) && (output.Session != null))
  258. return output.Session.Id;
  259. }
  260. }
  261. return null;
  262. }
  263. }
  264. public ICollection<SupportingTokenSpecification> SupportingTokens
  265. {
  266. get
  267. {
  268. MessageProperties properties = this.IncomingMessageProperties;
  269. if (properties != null && properties.Security != null)
  270. {
  271. return new System.Collections.ObjectModel.ReadOnlyCollection<SupportingTokenSpecification>(
  272. properties.Security.IncomingSupportingTokens);
  273. }
  274. return null;
  275. }
  276. }
  277. internal IPrincipal ThreadPrincipal
  278. {
  279. get { return this.threadPrincipal; }
  280. set { this.threadPrincipal = value; }
  281. }
  282. public ClaimsPrincipal ClaimsPrincipal
  283. {
  284. get;
  285. internal set;
  286. }
  287. internal TransactionRpcFacet TransactionFacet
  288. {
  289. get { return this.txFacet; }
  290. set { this.txFacet = value; }
  291. }
  292. internal void ClearClientReplyNoThrow()
  293. {
  294. this.clientReply = null;
  295. }
  296. internal void FireOperationCompleted()
  297. {
  298. try
  299. {
  300. EventHandler handler = this.OperationCompleted;
  301. if (handler != null)
  302. {
  303. handler(this, EventArgs.Empty);
  304. }
  305. }
  306. catch (Exception e)
  307. {
  308. if (Fx.IsFatal(e))
  309. throw;
  310. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
  311. }
  312. }
  313. public T GetCallbackChannel<T>()
  314. {
  315. if (this.channel == null || this.IsUserContext)
  316. return default(T);
  317. // yes, we might throw InvalidCastException here. Is it really
  318. // better to check and throw something else instead?
  319. return (T)this.channel.Proxy;
  320. }
  321. internal void ReInit(RequestContext requestContext, Message request, ServiceChannel channel)
  322. {
  323. this.requestContext = requestContext;
  324. this.request = request;
  325. this.channel = channel;
  326. }
  327. internal void Recycle()
  328. {
  329. this.requestContext = null;
  330. this.request = null;
  331. this.extensions = null;
  332. this.instanceContext = null;
  333. this.threadPrincipal = null;
  334. this.txFacet = null;
  335. this.SetClientReply(null, false);
  336. }
  337. internal void SetClientReply(Message message, bool closeMessage)
  338. {
  339. Message oldClientReply = null;
  340. if (!object.Equals(message, this.clientReply))
  341. {
  342. if (this.closeClientReply && (this.clientReply != null))
  343. {
  344. oldClientReply = this.clientReply;
  345. }
  346. this.clientReply = message;
  347. }
  348. this.closeClientReply = closeMessage;
  349. if (oldClientReply != null)
  350. {
  351. oldClientReply.Close();
  352. }
  353. }
  354. public void SetTransactionComplete()
  355. {
  356. if (this.txFacet == null)
  357. {
  358. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NoTransactionInContext)));
  359. }
  360. this.txFacet.Completed();
  361. }
  362. internal void SetInstanceContext(InstanceContext instanceContext)
  363. {
  364. this.instanceContext = instanceContext;
  365. }
  366. internal class Holder
  367. {
  368. OperationContext context;
  369. public OperationContext Context
  370. {
  371. get
  372. {
  373. return this.context;
  374. }
  375. set
  376. {
  377. this.context = value;
  378. }
  379. }
  380. }
  381. }
  382. }