Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / clr / src / BCL / System / Runtime / Remoting / CallContext.cs / 1 / CallContext.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // Implementation of CallContext ... currently leverages off // the LocalDataStore facility. namespace System.Runtime.Remoting.Messaging{ using System.Threading; using System.Runtime.Remoting; using System.Security.Principal; using System.Collections; using System.Runtime.Serialization; using System.Security.Permissions; // This class exposes the API for the users of call context. All methods // in CallContext are static and operate upon the call context in the Thread. // NOTE: CallContext is a specialized form of something that behaves like // TLS for method calls. However, since the call objects may get serialized // and deserialized along the path, it is tough to guarantee identity // preservation. // The LogicalCallContext class has all the actual functionality. We have // to use this scheme because Remoting message sinks etc do need to have // the distinction between the call context on the physical thread and // the call context that the remoting message actually carries. In most cases // they will operate on the message's call context and hence the latter // exposes the same set of methods as instance methods. // Only statics does not need to marked with the serializable attribute [Serializable] [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)] [System.Runtime.InteropServices.ComVisible(true)] public sealed class CallContext { private CallContext() { } // Get the logical call context object for the current thread. internal static LogicalCallContext GetLogicalCallContext() { return Thread.CurrentThread.GetLogicalCallContext(); } // Sets the given logical call context object on the thread. // Returns the previous one. internal static LogicalCallContext SetLogicalCallContext( LogicalCallContext callCtx) { return Thread.CurrentThread.SetLogicalCallContext(callCtx); } internal static LogicalCallContext SetLogicalCallContext( Thread currThread, LogicalCallContext callCtx) { return currThread.SetLogicalCallContext(callCtx); } internal static CallContextSecurityData SecurityData { get { return Thread.CurrentThread.GetLogicalCallContext().SecurityData; } } internal static CallContextRemotingData RemotingData { get { return Thread.CurrentThread.GetLogicalCallContext().RemotingData; } } /*========================================================================== ** Frees a named data slot. =========================================================================*/ public static void FreeNamedDataSlot(String name) { Thread.CurrentThread.GetLogicalCallContext().FreeNamedDataSlot(name); Thread.CurrentThread.GetIllogicalCallContext().FreeNamedDataSlot(name); } /*========================================================================= ** Get data on the logical call context =========================================================================*/ public static Object LogicalGetData(String name) { LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); return lcc.GetData(name); } /*========================================================================= ** Get data on the illogical call context =========================================================================*/ private static Object IllogicalGetData(String name) { IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); return ilcc.GetData(name); } internal static IPrincipal Principal { get { LogicalCallContext lcc = GetLogicalCallContext(); return lcc.Principal; } set { LogicalCallContext lcc = GetLogicalCallContext(); lcc.Principal = value; } } public static Object HostContext { get { Object hC; IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); hC = ilcc.HostContext; if (hC == null) { LogicalCallContext lcc = GetLogicalCallContext(); hC = lcc.HostContext; } return hC; } [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)] set { if (value is ILogicalThreadAffinative) { IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); ilcc.HostContext = null; LogicalCallContext lcc = GetLogicalCallContext(); lcc.HostContext = value; } else { LogicalCallContext lcc = GetLogicalCallContext(); lcc.HostContext = null; IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); ilcc.HostContext = value; } } } //For callContexts we intend to expose only name, value dictionary // type of behavior for now. We will re-consider if we need to expose // the other functions above for Beta-2. public static Object GetData(String name) { Object o = LogicalGetData(name); if (o == null) { return IllogicalGetData(name); } else { return o; } } public static void SetData(String name, Object data) { if (data is ILogicalThreadAffinative) { LogicalSetData(name, data); } else { LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); lcc.FreeNamedDataSlot(name); IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); ilcc.SetData(name, data); } } public static void LogicalSetData(String name, Object data) { IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); ilcc.FreeNamedDataSlot(name); LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); lcc.SetData(name, data); } public static Header[] GetHeaders() { LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); return lcc.InternalGetHeaders(); } // GetHeaders public static void SetHeaders(Header[] headers) { LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); lcc.InternalSetHeaders(headers); } // SetHeaders } // class CallContext [System.Runtime.InteropServices.ComVisible(true)] public interface ILogicalThreadAffinative { } internal class IllogicalCallContext: ICloneable { private Hashtable m_Datastore; private Object m_HostContext; private Hashtable Datastore { get { if (null == m_Datastore) { // The local store has not yet been created for this thread. m_Datastore = new Hashtable(); } return m_Datastore; } } internal Object HostContext { get { return m_HostContext; } set { m_HostContext = value; } } internal bool HasUserData { get { return ((m_Datastore != null) && (m_Datastore.Count > 0));} } /*========================================================================= ** Frees a named data slot. =========================================================================*/ public void FreeNamedDataSlot(String name) { Datastore.Remove(name); } public Object GetData(String name) { return Datastore[name]; } public void SetData(String name, Object data) { Datastore[name] = data; } public Object Clone() { IllogicalCallContext ilcc = new IllogicalCallContext(); if (HasUserData) { IDictionaryEnumerator de = m_Datastore.GetEnumerator(); while (de.MoveNext()) { ilcc.Datastore[(String)de.Key] = de.Value; } } return ilcc; } } // This class handles the actual call context functionality. It leverages on the // implementation of local data store ... except that the local store manager is // not static. That is to say, allocating a slot in one call context has no effect // on another call contexts. Different call contexts are entirely unrelated. [Serializable] [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)] [System.Runtime.InteropServices.ComVisible(true)] public sealed class LogicalCallContext : ISerializable, ICloneable { // Private static data private static Type s_callContextType = typeof(LogicalCallContext); private const string s_CorrelationMgrSlotName = "System.Diagnostics.Trace.CorrelationManagerSlot"; /*========================================================================== ** Data accessed from managed code that needs to be defined in ** LogicalCallContextObject to maintain alignment between the two classes. ** DON'T CHANGE THESE UNLESS YOU MODIFY LogicalContextObject in vm\object.h =========================================================================*/ // Private member data private Hashtable m_Datastore; private CallContextRemotingData m_RemotingData = null; private CallContextSecurityData m_SecurityData = null; private Object m_HostContext = null; private bool m_IsCorrelationMgr = false; // _sendHeaders is for Headers that should be sent out on the next call. // _recvHeaders are for Headers that came from a response. private Header[] _sendHeaders = null; private Header[] _recvHeaders = null; internal LogicalCallContext() { } internal LogicalCallContext(SerializationInfo info, StreamingContext context) { SerializationInfoEnumerator e = info.GetEnumerator(); while (e.MoveNext()) { if (e.Name.Equals("__RemotingData")) { m_RemotingData = (CallContextRemotingData) e.Value; } else if (e.Name.Equals("__SecurityData")) { if (context.State == StreamingContextStates.CrossAppDomain) { m_SecurityData = (CallContextSecurityData) e.Value; } else { BCLDebug.Assert(false, "Security data should only be serialized in cross appdomain case."); } } else if (e.Name.Equals("__HostContext")) { m_HostContext = e.Value; } else if (e.Name.Equals("__CorrelationMgrSlotPresent")) { m_IsCorrelationMgr = (bool)e.Value; } else { Datastore[e.Name] = e.Value; } } } [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] public void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) throw new ArgumentNullException("info"); info.SetType(s_callContextType); if (m_RemotingData != null) { info.AddValue("__RemotingData", m_RemotingData); } if (m_SecurityData != null) { if (context.State == StreamingContextStates.CrossAppDomain) { info.AddValue("__SecurityData", m_SecurityData); } } if (m_HostContext != null) { info.AddValue("__HostContext", m_HostContext); } if (m_IsCorrelationMgr) { info.AddValue("__CorrelationMgrSlotPresent", m_IsCorrelationMgr); } if (HasUserData) { IDictionaryEnumerator de = m_Datastore.GetEnumerator(); while (de.MoveNext()) { info.AddValue((String)de.Key, de.Value); } } } // ICloneable::Clone // Used to create a deep copy of the call context when an async // call starts. // < public Object Clone() { LogicalCallContext lc = new LogicalCallContext(); if (m_RemotingData != null) lc.m_RemotingData = (CallContextRemotingData)m_RemotingData.Clone(); if (m_SecurityData != null) lc.m_SecurityData = (CallContextSecurityData)m_SecurityData.Clone(); if (m_HostContext != null) lc.m_HostContext = m_HostContext; lc.m_IsCorrelationMgr = m_IsCorrelationMgr; if (HasUserData) { IDictionaryEnumerator de = m_Datastore.GetEnumerator(); if (!m_IsCorrelationMgr) { while (de.MoveNext()) { lc.Datastore[(String)de.Key] = de.Value; } } else { while (de.MoveNext()) { String key = (String)de.Key; // Deep clone "System.Diagnostics.Trace.CorrelationManagerSlot" if (key.Equals(s_CorrelationMgrSlotName)) { lc.Datastore[key] = ((ICloneable)de.Value).Clone(); } else lc.Datastore[key] = de.Value; } } } return lc; } // Used to do a (limited) merge the call context from a returning async call internal void Merge(LogicalCallContext lc) { // we ignore the RemotingData & SecurityData // and only merge the user sections of the two call contexts // the idea being that if the original call had any // identity/remoting callID that should remain unchanged // If we have a non-null callContext and it is not the same // as the one on the current thread (can happen in x-context async) // and there is any userData in the callContext, do the merge if ((lc != null) && (this != lc) && lc.HasUserData) { IDictionaryEnumerator de = lc.Datastore.GetEnumerator(); while (de.MoveNext()) { Datastore[(String)de.Key] = de.Value; } } } public bool HasInfo { get { bool fInfo = false; // Set the flag to true if there is either remoting data, or // security data or user data if( (m_RemotingData != null && m_RemotingData.HasInfo) || (m_SecurityData != null && m_SecurityData.HasInfo) || (m_HostContext != null) || HasUserData ) { fInfo = true; } return fInfo; } } private bool HasUserData { get { return ((m_Datastore != null) && (m_Datastore.Count > 0));} } internal CallContextRemotingData RemotingData { get { if (m_RemotingData == null) m_RemotingData = new CallContextRemotingData(); return m_RemotingData; } } internal CallContextSecurityData SecurityData { get { if (m_SecurityData == null) m_SecurityData = new CallContextSecurityData(); return m_SecurityData; } } internal Object HostContext { get { return m_HostContext; } set { m_HostContext = value; } } private Hashtable Datastore { get { if (null == m_Datastore) { // The local store has not yet been created for this thread. m_Datastore = new Hashtable(); } return m_Datastore; } } // This is used for quick access to the current principal when going // between appdomains. internal IPrincipal Principal { get { // This MUST not fault in the security data object if it doesn't exist. if (m_SecurityData != null) return m_SecurityData.Principal; return null; } // get set { SecurityData.Principal = value; } // set } // Principal /*========================================================================= ** Frees a named data slot. =========================================================================*/ public void FreeNamedDataSlot(String name) { Datastore.Remove(name); } public Object GetData(String name) { return Datastore[name]; } public void SetData(String name, Object data) { Datastore[name] = data; if (name.Equals(s_CorrelationMgrSlotName)) m_IsCorrelationMgr = true; } private Header[] InternalGetOutgoingHeaders() { Header[] outgoingHeaders = _sendHeaders; _sendHeaders = null; // A new remote call is being made, so we null out the // current received headers so these can't be confused // with a response from the next call. _recvHeaders = null; return outgoingHeaders; } // InternalGetOutgoingHeaders internal void InternalSetHeaders(Header[] headers) { _sendHeaders = headers; _recvHeaders = null; } // InternalSetHeaders internal Header[] InternalGetHeaders() { // If _sendHeaders is currently set, we always want to return them. if (_sendHeaders != null) return _sendHeaders; // Either _recvHeaders is non-null and those are the ones we want to // return, or there are no currently set headers, so we'll return // null. return _recvHeaders; } // InternalGetHeaders // Nulls out the principal if its not serializable. // Since principals do flow for x-appdomain casses // we need to handle this behaviour both during invoke // and response internal IPrincipal RemovePrincipalIfNotSerializable() { IPrincipal currentPrincipal = this.Principal; // If the principal is not serializable, we need to // null it out. if (currentPrincipal != null) { if (!currentPrincipal.GetType().IsSerializable) this.Principal = null; } return currentPrincipal; } // Takes outgoing headers and inserts them internal void PropagateOutgoingHeadersToMessage(IMessage msg) { Header[] headers = InternalGetOutgoingHeaders(); if (headers != null) { BCLDebug.Assert(msg != null, "Why is the message null?"); IDictionary properties = msg.Properties; BCLDebug.Assert(properties != null, "Why are the properties null?"); foreach (Header header in headers) { // add header to the message dictionary if (header != null) { // The header key is composed from its name and namespace. String name = GetPropertyKeyForHeader(header); properties[name] = header; } } } } // PropagateOutgoingHeadersToMessage // Retrieve key to use for header. internal static String GetPropertyKeyForHeader(Header header) { if (header == null) return null; if (header.HeaderNamespace != null) return header.Name + ", " + header.HeaderNamespace; else return header.Name; } // GetPropertyKeyForHeader // Take headers out of message and stores them in call context internal void PropagateIncomingHeadersToCallContext(IMessage msg) { BCLDebug.Assert(msg != null, "Why is the message null?"); // If it's an internal message, we can quickly tell if there are any // headers. IInternalMessage iim = msg as IInternalMessage; if (iim != null) { if (!iim.HasProperties()) { // If there are no properties just return immediately. return; } } IDictionary properties = msg.Properties; BCLDebug.Assert(properties != null, "Why are the properties null?"); IDictionaryEnumerator e = (IDictionaryEnumerator) properties.GetEnumerator(); // cycle through the properties to get a count of the headers int count = 0; while (e.MoveNext()) { String key = (String)e.Key; if (!key.StartsWith("__", StringComparison.Ordinal)) { // We don't want to have to check for special values, so we // blanketly state that header names can't start with // double underscore. if (e.Value is Header) count++; } } // If there are headers, create array and set it to the received header property Header[] headers = null; if (count > 0) { headers = new Header[count]; count = 0; e.Reset(); while (e.MoveNext()) { String key = (String)e.Key; if (!key.StartsWith("__", StringComparison.Ordinal)) { Header header = e.Value as Header; if (header != null) headers[count++] = header; } } } _recvHeaders = headers; _sendHeaders = null; } // PropagateIncomingHeadersToCallContext } // class LogicalCallContext [Serializable] internal class CallContextSecurityData : ICloneable { // This is used for the special getter/setter for security related // info in the callContext. IPrincipal _principal; // < internal IPrincipal Principal { get {return _principal;} set {_principal = value;} } // Checks if there is any useful data to be serialized internal bool HasInfo { get { return (null != _principal); } } public Object Clone() { CallContextSecurityData sd = new CallContextSecurityData(); sd._principal = _principal; return sd; } } [Serializable] internal class CallContextRemotingData : ICloneable { // This is used for the special getter/setter for remoting related // info in the callContext. String _logicalCallID; internal String LogicalCallID { get {return _logicalCallID;} set {_logicalCallID = value;} } // Checks if there is any useful data to be serialized internal bool HasInfo { get { // Keep this updated if we add more stuff to remotingData! return (_logicalCallID!=null); } } public Object Clone() { CallContextRemotingData rd = new CallContextRemotingData(); rd.LogicalCallID = LogicalCallID; return rd; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // Implementation of CallContext ... currently leverages off // the LocalDataStore facility. namespace System.Runtime.Remoting.Messaging{ using System.Threading; using System.Runtime.Remoting; using System.Security.Principal; using System.Collections; using System.Runtime.Serialization; using System.Security.Permissions; // This class exposes the API for the users of call context. All methods // in CallContext are static and operate upon the call context in the Thread. // NOTE: CallContext is a specialized form of something that behaves like // TLS for method calls. However, since the call objects may get serialized // and deserialized along the path, it is tough to guarantee identity // preservation. // The LogicalCallContext class has all the actual functionality. We have // to use this scheme because Remoting message sinks etc do need to have // the distinction between the call context on the physical thread and // the call context that the remoting message actually carries. In most cases // they will operate on the message's call context and hence the latter // exposes the same set of methods as instance methods. // Only statics does not need to marked with the serializable attribute [Serializable] [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)] [System.Runtime.InteropServices.ComVisible(true)] public sealed class CallContext { private CallContext() { } // Get the logical call context object for the current thread. internal static LogicalCallContext GetLogicalCallContext() { return Thread.CurrentThread.GetLogicalCallContext(); } // Sets the given logical call context object on the thread. // Returns the previous one. internal static LogicalCallContext SetLogicalCallContext( LogicalCallContext callCtx) { return Thread.CurrentThread.SetLogicalCallContext(callCtx); } internal static LogicalCallContext SetLogicalCallContext( Thread currThread, LogicalCallContext callCtx) { return currThread.SetLogicalCallContext(callCtx); } internal static CallContextSecurityData SecurityData { get { return Thread.CurrentThread.GetLogicalCallContext().SecurityData; } } internal static CallContextRemotingData RemotingData { get { return Thread.CurrentThread.GetLogicalCallContext().RemotingData; } } /*========================================================================== ** Frees a named data slot. =========================================================================*/ public static void FreeNamedDataSlot(String name) { Thread.CurrentThread.GetLogicalCallContext().FreeNamedDataSlot(name); Thread.CurrentThread.GetIllogicalCallContext().FreeNamedDataSlot(name); } /*========================================================================= ** Get data on the logical call context =========================================================================*/ public static Object LogicalGetData(String name) { LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); return lcc.GetData(name); } /*========================================================================= ** Get data on the illogical call context =========================================================================*/ private static Object IllogicalGetData(String name) { IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); return ilcc.GetData(name); } internal static IPrincipal Principal { get { LogicalCallContext lcc = GetLogicalCallContext(); return lcc.Principal; } set { LogicalCallContext lcc = GetLogicalCallContext(); lcc.Principal = value; } } public static Object HostContext { get { Object hC; IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); hC = ilcc.HostContext; if (hC == null) { LogicalCallContext lcc = GetLogicalCallContext(); hC = lcc.HostContext; } return hC; } [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)] set { if (value is ILogicalThreadAffinative) { IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); ilcc.HostContext = null; LogicalCallContext lcc = GetLogicalCallContext(); lcc.HostContext = value; } else { LogicalCallContext lcc = GetLogicalCallContext(); lcc.HostContext = null; IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); ilcc.HostContext = value; } } } //For callContexts we intend to expose only name, value dictionary // type of behavior for now. We will re-consider if we need to expose // the other functions above for Beta-2. public static Object GetData(String name) { Object o = LogicalGetData(name); if (o == null) { return IllogicalGetData(name); } else { return o; } } public static void SetData(String name, Object data) { if (data is ILogicalThreadAffinative) { LogicalSetData(name, data); } else { LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); lcc.FreeNamedDataSlot(name); IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); ilcc.SetData(name, data); } } public static void LogicalSetData(String name, Object data) { IllogicalCallContext ilcc = Thread.CurrentThread.GetIllogicalCallContext(); ilcc.FreeNamedDataSlot(name); LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); lcc.SetData(name, data); } public static Header[] GetHeaders() { LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); return lcc.InternalGetHeaders(); } // GetHeaders public static void SetHeaders(Header[] headers) { LogicalCallContext lcc = Thread.CurrentThread.GetLogicalCallContext(); lcc.InternalSetHeaders(headers); } // SetHeaders } // class CallContext [System.Runtime.InteropServices.ComVisible(true)] public interface ILogicalThreadAffinative { } internal class IllogicalCallContext: ICloneable { private Hashtable m_Datastore; private Object m_HostContext; private Hashtable Datastore { get { if (null == m_Datastore) { // The local store has not yet been created for this thread. m_Datastore = new Hashtable(); } return m_Datastore; } } internal Object HostContext { get { return m_HostContext; } set { m_HostContext = value; } } internal bool HasUserData { get { return ((m_Datastore != null) && (m_Datastore.Count > 0));} } /*========================================================================= ** Frees a named data slot. =========================================================================*/ public void FreeNamedDataSlot(String name) { Datastore.Remove(name); } public Object GetData(String name) { return Datastore[name]; } public void SetData(String name, Object data) { Datastore[name] = data; } public Object Clone() { IllogicalCallContext ilcc = new IllogicalCallContext(); if (HasUserData) { IDictionaryEnumerator de = m_Datastore.GetEnumerator(); while (de.MoveNext()) { ilcc.Datastore[(String)de.Key] = de.Value; } } return ilcc; } } // This class handles the actual call context functionality. It leverages on the // implementation of local data store ... except that the local store manager is // not static. That is to say, allocating a slot in one call context has no effect // on another call contexts. Different call contexts are entirely unrelated. [Serializable] [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)] [System.Runtime.InteropServices.ComVisible(true)] public sealed class LogicalCallContext : ISerializable, ICloneable { // Private static data private static Type s_callContextType = typeof(LogicalCallContext); private const string s_CorrelationMgrSlotName = "System.Diagnostics.Trace.CorrelationManagerSlot"; /*========================================================================== ** Data accessed from managed code that needs to be defined in ** LogicalCallContextObject to maintain alignment between the two classes. ** DON'T CHANGE THESE UNLESS YOU MODIFY LogicalContextObject in vm\object.h =========================================================================*/ // Private member data private Hashtable m_Datastore; private CallContextRemotingData m_RemotingData = null; private CallContextSecurityData m_SecurityData = null; private Object m_HostContext = null; private bool m_IsCorrelationMgr = false; // _sendHeaders is for Headers that should be sent out on the next call. // _recvHeaders are for Headers that came from a response. private Header[] _sendHeaders = null; private Header[] _recvHeaders = null; internal LogicalCallContext() { } internal LogicalCallContext(SerializationInfo info, StreamingContext context) { SerializationInfoEnumerator e = info.GetEnumerator(); while (e.MoveNext()) { if (e.Name.Equals("__RemotingData")) { m_RemotingData = (CallContextRemotingData) e.Value; } else if (e.Name.Equals("__SecurityData")) { if (context.State == StreamingContextStates.CrossAppDomain) { m_SecurityData = (CallContextSecurityData) e.Value; } else { BCLDebug.Assert(false, "Security data should only be serialized in cross appdomain case."); } } else if (e.Name.Equals("__HostContext")) { m_HostContext = e.Value; } else if (e.Name.Equals("__CorrelationMgrSlotPresent")) { m_IsCorrelationMgr = (bool)e.Value; } else { Datastore[e.Name] = e.Value; } } } [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] public void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) throw new ArgumentNullException("info"); info.SetType(s_callContextType); if (m_RemotingData != null) { info.AddValue("__RemotingData", m_RemotingData); } if (m_SecurityData != null) { if (context.State == StreamingContextStates.CrossAppDomain) { info.AddValue("__SecurityData", m_SecurityData); } } if (m_HostContext != null) { info.AddValue("__HostContext", m_HostContext); } if (m_IsCorrelationMgr) { info.AddValue("__CorrelationMgrSlotPresent", m_IsCorrelationMgr); } if (HasUserData) { IDictionaryEnumerator de = m_Datastore.GetEnumerator(); while (de.MoveNext()) { info.AddValue((String)de.Key, de.Value); } } } // ICloneable::Clone // Used to create a deep copy of the call context when an async // call starts. // < public Object Clone() { LogicalCallContext lc = new LogicalCallContext(); if (m_RemotingData != null) lc.m_RemotingData = (CallContextRemotingData)m_RemotingData.Clone(); if (m_SecurityData != null) lc.m_SecurityData = (CallContextSecurityData)m_SecurityData.Clone(); if (m_HostContext != null) lc.m_HostContext = m_HostContext; lc.m_IsCorrelationMgr = m_IsCorrelationMgr; if (HasUserData) { IDictionaryEnumerator de = m_Datastore.GetEnumerator(); if (!m_IsCorrelationMgr) { while (de.MoveNext()) { lc.Datastore[(String)de.Key] = de.Value; } } else { while (de.MoveNext()) { String key = (String)de.Key; // Deep clone "System.Diagnostics.Trace.CorrelationManagerSlot" if (key.Equals(s_CorrelationMgrSlotName)) { lc.Datastore[key] = ((ICloneable)de.Value).Clone(); } else lc.Datastore[key] = de.Value; } } } return lc; } // Used to do a (limited) merge the call context from a returning async call internal void Merge(LogicalCallContext lc) { // we ignore the RemotingData & SecurityData // and only merge the user sections of the two call contexts // the idea being that if the original call had any // identity/remoting callID that should remain unchanged // If we have a non-null callContext and it is not the same // as the one on the current thread (can happen in x-context async) // and there is any userData in the callContext, do the merge if ((lc != null) && (this != lc) && lc.HasUserData) { IDictionaryEnumerator de = lc.Datastore.GetEnumerator(); while (de.MoveNext()) { Datastore[(String)de.Key] = de.Value; } } } public bool HasInfo { get { bool fInfo = false; // Set the flag to true if there is either remoting data, or // security data or user data if( (m_RemotingData != null && m_RemotingData.HasInfo) || (m_SecurityData != null && m_SecurityData.HasInfo) || (m_HostContext != null) || HasUserData ) { fInfo = true; } return fInfo; } } private bool HasUserData { get { return ((m_Datastore != null) && (m_Datastore.Count > 0));} } internal CallContextRemotingData RemotingData { get { if (m_RemotingData == null) m_RemotingData = new CallContextRemotingData(); return m_RemotingData; } } internal CallContextSecurityData SecurityData { get { if (m_SecurityData == null) m_SecurityData = new CallContextSecurityData(); return m_SecurityData; } } internal Object HostContext { get { return m_HostContext; } set { m_HostContext = value; } } private Hashtable Datastore { get { if (null == m_Datastore) { // The local store has not yet been created for this thread. m_Datastore = new Hashtable(); } return m_Datastore; } } // This is used for quick access to the current principal when going // between appdomains. internal IPrincipal Principal { get { // This MUST not fault in the security data object if it doesn't exist. if (m_SecurityData != null) return m_SecurityData.Principal; return null; } // get set { SecurityData.Principal = value; } // set } // Principal /*========================================================================= ** Frees a named data slot. =========================================================================*/ public void FreeNamedDataSlot(String name) { Datastore.Remove(name); } public Object GetData(String name) { return Datastore[name]; } public void SetData(String name, Object data) { Datastore[name] = data; if (name.Equals(s_CorrelationMgrSlotName)) m_IsCorrelationMgr = true; } private Header[] InternalGetOutgoingHeaders() { Header[] outgoingHeaders = _sendHeaders; _sendHeaders = null; // A new remote call is being made, so we null out the // current received headers so these can't be confused // with a response from the next call. _recvHeaders = null; return outgoingHeaders; } // InternalGetOutgoingHeaders internal void InternalSetHeaders(Header[] headers) { _sendHeaders = headers; _recvHeaders = null; } // InternalSetHeaders internal Header[] InternalGetHeaders() { // If _sendHeaders is currently set, we always want to return them. if (_sendHeaders != null) return _sendHeaders; // Either _recvHeaders is non-null and those are the ones we want to // return, or there are no currently set headers, so we'll return // null. return _recvHeaders; } // InternalGetHeaders // Nulls out the principal if its not serializable. // Since principals do flow for x-appdomain casses // we need to handle this behaviour both during invoke // and response internal IPrincipal RemovePrincipalIfNotSerializable() { IPrincipal currentPrincipal = this.Principal; // If the principal is not serializable, we need to // null it out. if (currentPrincipal != null) { if (!currentPrincipal.GetType().IsSerializable) this.Principal = null; } return currentPrincipal; } // Takes outgoing headers and inserts them internal void PropagateOutgoingHeadersToMessage(IMessage msg) { Header[] headers = InternalGetOutgoingHeaders(); if (headers != null) { BCLDebug.Assert(msg != null, "Why is the message null?"); IDictionary properties = msg.Properties; BCLDebug.Assert(properties != null, "Why are the properties null?"); foreach (Header header in headers) { // add header to the message dictionary if (header != null) { // The header key is composed from its name and namespace. String name = GetPropertyKeyForHeader(header); properties[name] = header; } } } } // PropagateOutgoingHeadersToMessage // Retrieve key to use for header. internal static String GetPropertyKeyForHeader(Header header) { if (header == null) return null; if (header.HeaderNamespace != null) return header.Name + ", " + header.HeaderNamespace; else return header.Name; } // GetPropertyKeyForHeader // Take headers out of message and stores them in call context internal void PropagateIncomingHeadersToCallContext(IMessage msg) { BCLDebug.Assert(msg != null, "Why is the message null?"); // If it's an internal message, we can quickly tell if there are any // headers. IInternalMessage iim = msg as IInternalMessage; if (iim != null) { if (!iim.HasProperties()) { // If there are no properties just return immediately. return; } } IDictionary properties = msg.Properties; BCLDebug.Assert(properties != null, "Why are the properties null?"); IDictionaryEnumerator e = (IDictionaryEnumerator) properties.GetEnumerator(); // cycle through the properties to get a count of the headers int count = 0; while (e.MoveNext()) { String key = (String)e.Key; if (!key.StartsWith("__", StringComparison.Ordinal)) { // We don't want to have to check for special values, so we // blanketly state that header names can't start with // double underscore. if (e.Value is Header) count++; } } // If there are headers, create array and set it to the received header property Header[] headers = null; if (count > 0) { headers = new Header[count]; count = 0; e.Reset(); while (e.MoveNext()) { String key = (String)e.Key; if (!key.StartsWith("__", StringComparison.Ordinal)) { Header header = e.Value as Header; if (header != null) headers[count++] = header; } } } _recvHeaders = headers; _sendHeaders = null; } // PropagateIncomingHeadersToCallContext } // class LogicalCallContext [Serializable] internal class CallContextSecurityData : ICloneable { // This is used for the special getter/setter for security related // info in the callContext. IPrincipal _principal; // < internal IPrincipal Principal { get {return _principal;} set {_principal = value;} } // Checks if there is any useful data to be serialized internal bool HasInfo { get { return (null != _principal); } } public Object Clone() { CallContextSecurityData sd = new CallContextSecurityData(); sd._principal = _principal; return sd; } } [Serializable] internal class CallContextRemotingData : ICloneable { // This is used for the special getter/setter for remoting related // info in the callContext. String _logicalCallID; internal String LogicalCallID { get {return _logicalCallID;} set {_logicalCallID = value;} } // Checks if there is any useful data to be serialized internal bool HasInfo { get { // Keep this updated if we add more stuff to remotingData! return (_logicalCallID!=null); } } public Object Clone() { CallContextRemotingData rd = new CallContextRemotingData(); rd.LogicalCallID = LogicalCallID; return rd; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ListBindableAttribute.cs
- PropertyChangeTracker.cs
- SqlConnectionManager.cs
- LoaderAllocator.cs
- RuntimeEnvironment.cs
- XmlHierarchicalDataSourceView.cs
- WebScriptEnablingElement.cs
- DataGridViewTopLeftHeaderCell.cs
- InternalControlCollection.cs
- ExpressionConverter.cs
- ProvideValueServiceProvider.cs
- TriggerAction.cs
- FileDialog_Vista.cs
- XPathScanner.cs
- FontWeightConverter.cs
- Int32RectValueSerializer.cs
- DictionaryEditChange.cs
- BamlLocalizableResource.cs
- QueryNode.cs
- BevelBitmapEffect.cs
- WebServicesSection.cs
- TypeDependencyAttribute.cs
- SQLMoneyStorage.cs
- SecurityContext.cs
- ExceptQueryOperator.cs
- CompositeDesignerAccessibleObject.cs
- infer.cs
- SettingsContext.cs
- AsmxEndpointPickerExtension.cs
- Pen.cs
- LogEntrySerialization.cs
- DataSourceCacheDurationConverter.cs
- DataSourceSelectArguments.cs
- ClientSponsor.cs
- Transform3DGroup.cs
- Point3DCollection.cs
- WorkflowInvoker.cs
- ChannelDispatcherCollection.cs
- SemanticAnalyzer.cs
- AgileSafeNativeMemoryHandle.cs
- Screen.cs
- DependencyPropertyValueSerializer.cs
- DrawingBrush.cs
- DataSourceConverter.cs
- SqlTransaction.cs
- DesignerOptionService.cs
- PropertyInfoSet.cs
- FontResourceCache.cs
- UnsafeNativeMethodsMilCoreApi.cs
- XmlChoiceIdentifierAttribute.cs
- LockedActivityGlyph.cs
- ScopeCompiler.cs
- Misc.cs
- XmlJsonReader.cs
- PrintDialogException.cs
- OracleColumn.cs
- ToolStripPanelRow.cs
- SystemSounds.cs
- SettingsContext.cs
- SqlColumnizer.cs
- ServiceModelSectionGroup.cs
- HostedElements.cs
- ServiceDiscoveryElement.cs
- EventTrigger.cs
- ToolStripScrollButton.cs
- ProxyWebPartManager.cs
- InvalidCastException.cs
- DataGridViewButtonColumn.cs
- sqlmetadatafactory.cs
- GridView.cs
- XmlTypeMapping.cs
- IPeerNeighbor.cs
- SpellerHighlightLayer.cs
- ObjectFullSpanRewriter.cs
- XmlSchemaRedefine.cs
- UnaryNode.cs
- SqlDelegatedTransaction.cs
- AsnEncodedData.cs
- WindowsEditBoxRange.cs
- activationcontext.cs
- Funcletizer.cs
- FileDetails.cs
- LeaseManager.cs
- UInt16.cs
- KeyboardNavigation.cs
- DetailsViewCommandEventArgs.cs
- StylusPointPropertyUnit.cs
- Control.cs
- SkewTransform.cs
- VirtualPathUtility.cs
- Stylus.cs
- FieldMetadata.cs
- ServiceRoute.cs
- _LazyAsyncResult.cs
- AlternationConverter.cs
- TextOnlyOutput.cs
- ToolStripContainer.cs
- ChildDocumentBlock.cs
- GridViewCellAutomationPeer.cs
- HttpCachePolicyElement.cs