The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting \ DuplicateIdentityOption

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace System.Runtime.Remoting
  16. {
  17.     using System.Globalization;
  18.     using System.Threading;
  19.     using System.Runtime.CompilerServices;
  20.     using System.Runtime.InteropServices;
  21.     using System.Runtime.Remoting;
  22.     using System.Runtime.Remoting.Contexts;
  23.     using System.Runtime.Remoting.Proxies;
  24.     using System.Runtime.Remoting.Messaging;
  25.     using System.Runtime.ConstrainedExecution;
  26.     using System.Reflection;
  27.     using System;
  28.     // IdentityHolder maintains a lookup service for remoting identities. The methods
  29.     // provided by it are used during calls to Wrap, UnWrap, Marshal, Unmarshal etc.
  30.     //
  31.     using System.Collections;
  32.    
  33.     // This is just a internal struct to hold the various flags
  34.     // that get passed for different flavors of idtable operations
  35.     // just so that we do not have too many separate boolean parameters
  36.     // all over the place (eg. xxxIdentity(id,uri, true, false, true);)
  37.     internal struct IdOps
  38.     {
  39.         internal const int None = 0;
  40.         internal const int GenerateURI = 1;
  41.         internal const int StrongIdentity = 2;
  42.        
  43.         static internal bool bStrongIdentity(int flags)
  44.         {
  45.             return (flags & StrongIdentity) != 0;
  46.         }
  47.     }
  48.    
  49.     // Internal enum to specify options for SetIdentity
  50.     [Serializable()]
  51.     internal enum DuplicateIdentityOption
  52.     {
  53.         Unique,
  54.         // -throw an exception if there is already an identity in the table
  55.         UseExisting
  56.         // -if there is already an identity in the table, then use that one.
  57.         // (could happen in a Connect race, but we don't care which identity we get)
  58.     }
  59.     // enum DuplicateIdentityOption
  60.    
  61.     internal sealed class IdentityHolder
  62.     {
  63.         // private static Timer CleanupTimer = null;
  64.         // private const int CleanupInterval = 60000; // 1 minute.
  65.        
  66.         // private static Object staticSyncObject = new Object();
  67.         private static int SetIDCount = 0;
  68.         private const int CleanUpCountInterval = 64;
  69.         private const int INFINITE = 2147483647;
  70.        
  71.         private static Hashtable _URITable = new Hashtable();
  72.         private static Context _cachedDefaultContext = null;
  73.        
  74.        
  75.         static internal Hashtable URITable {
  76.             get { return _URITable; }
  77.         }
  78.        
  79.         static internal Context DefaultContext {
  80.             get {
  81.                 if (_cachedDefaultContext == null) {
  82.                     _cachedDefaultContext = Thread.GetDomain().GetDefaultContext();
  83.                 }
  84.                 return _cachedDefaultContext;
  85.             }
  86.         }
  87.        
  88.         // NOTE!!!: This must be used to convert any uri into something that can
  89.         // be used as a key in the URITable!!!
  90.         private static string MakeURIKey(string uri)
  91.         {
  92.             return Identity.RemoveAppNameOrAppGuidIfNecessary(uri.ToLower(CultureInfo.InvariantCulture));
  93.         }
  94.        
  95.         private static string MakeURIKeyNoLower(string uri)
  96.         {
  97.             return Identity.RemoveAppNameOrAppGuidIfNecessary(uri);
  98.         }
  99.        
  100.         static internal ReaderWriterLock TableLock {
  101.             get { return Thread.GetDomain().RemotingData.IDTableLock; }
  102.         }
  103.        
  104.        
  105.         // Cycles through the table periodically and cleans up expired entries.
  106.         //
  107.         private static void CleanupIdentities(object state)
  108.         {
  109.             BCLDebug.Assert(Thread.GetDomain().RemotingData.IDTableLock.IsWriterLockHeld, "ID Table being cleaned up without taking a lock!");
  110.            
  111.             IDictionaryEnumerator e = URITable.GetEnumerator();
  112.             ArrayList removeList = new ArrayList();
  113.             while (e.MoveNext()) {
  114.                 object o = e.Value;
  115.                 WeakReference wr = o as WeakReference;
  116.                 if ((null != wr) && (null == wr.Target)) {
  117.                     removeList.Add(e.Key);
  118.                 }
  119.             }
  120.            
  121.             foreach (string key in removeList) {
  122.                 URITable.Remove(key);
  123.             }
  124.         }
  125.        
  126.         static internal void FlushIdentityTable()
  127.         {
  128.             // We need to guarantee that finally is not interrupted so that the lock is released.
  129.             // TableLock has a long path without reliability contract. To avoid adding contract on
  130.             // the path, we will use ReaderWriterLock directly.
  131.             ReaderWriterLock rwlock = TableLock;
  132.             bool takeAndRelease = !rwlock.IsWriterLockHeld;
  133.            
  134.             RuntimeHelpers.PrepareConstrainedRegions();
  135.             try {
  136.                 if (takeAndRelease)
  137.                     rwlock.AcquireWriterLock(INFINITE);
  138.                 CleanupIdentities(null);
  139.             }
  140.             finally {
  141.                 if (takeAndRelease && rwlock.IsWriterLockHeld) {
  142.                     rwlock.ReleaseWriterLock();
  143.                 }
  144.             }
  145.         }
  146.        
  147.         private IdentityHolder()
  148.         {
  149.             // this is a singleton object. Can't construct it.
  150.         }
  151.        
  152.        
  153.         // Looks up the identity corresponding to a URI.
  154.         //
  155.         static internal Identity ResolveIdentity(string URI)
  156.         {
  157.             if (URI == null)
  158.                 throw new ArgumentNullException("URI");
  159.            
  160.             Identity id;
  161.             // We need to guarantee that finally is not interrupted so that the lock is released.
  162.             // TableLock has a long path without reliability contract. To avoid adding contract on
  163.             // the path, we will use ReaderWriterLock directly.
  164.             ReaderWriterLock rwlock = TableLock;
  165.             bool takeAndRelease = !rwlock.IsReaderLockHeld;
  166.            
  167.             RuntimeHelpers.PrepareConstrainedRegions();
  168.             try {
  169.                 if (takeAndRelease)
  170.                     rwlock.AcquireReaderLock(INFINITE);
  171.                
  172.                 Message.DebugOut("ResolveIdentity:: URI: " + URI + "\n");
  173.                 Message.DebugOut("ResolveIdentity:: table.count: " + URITable.Count + "\n");
  174.                 //Console.WriteLine("\n ResolveID: URI = " + URI);
  175.                 // This may be called both in the client process and the server process (loopback case).
  176.                 id = ResolveReference(URITable[MakeURIKey(URI)]);
  177.             }
  178.             finally {
  179.                 if (takeAndRelease && rwlock.IsReaderLockHeld) {
  180.                     rwlock.ReleaseReaderLock();
  181.                 }
  182.             }
  183.             return id;
  184.         }
  185.         // ResolveIdentity
  186.        
  187.         // If the identity isn't found, this version will just return
  188.         // null instead of asserting (this version doesn't need to
  189.         // take a lock).
  190.         static internal Identity CasualResolveIdentity(string uri)
  191.         {
  192.             if (uri == null)
  193.                 return null;
  194.            
  195.             Identity id = CasualResolveReference(URITable[MakeURIKeyNoLower(uri)]);
  196.             if (id == null) {
  197.                 id = CasualResolveReference(URITable[MakeURIKey(uri)]);
  198.                 if (id == null) {
  199.                     // Check if this a well-known object which needs to be faulted in
  200.                     id = RemotingConfigHandler.CreateWellKnownObject(uri);
  201.                 }
  202.             }
  203.            
  204.             return id;
  205.         }
  206.         // CasualResolveIdentity
  207.        
  208.         private static Identity ResolveReference(object o)
  209.         {
  210.             BCLDebug.Assert(TableLock.IsReaderLockHeld || TableLock.IsWriterLockHeld, "Should have locked the ID Table!");
  211.             WeakReference wr = o as WeakReference;
  212.             if (null != wr) {
  213.                 return ((Identity)wr.Target);
  214.             }
  215.             else {
  216.                 return ((Identity)o);
  217.             }
  218.         }
  219.         // ResolveReference
  220.         private static Identity CasualResolveReference(object o)
  221.         {
  222.             WeakReference wr = o as WeakReference;
  223.             if (null != wr) {
  224.                 return ((Identity)wr.Target);
  225.             }
  226.             else {
  227.                 return ((Identity)o);
  228.             }
  229.         }
  230.         // CasualResolveReference
  231.         //
  232.         //
  233.         // This is typically called when we need to create/establish
  234.         // an identity for a serverObject.
  235.         static internal ServerIdentity FindOrCreateServerIdentity(MarshalByRefObject obj, string objURI, int flags)
  236.         {
  237.             Message.DebugOut("Entered FindOrCreateServerIdentity \n");
  238.            
  239.             ServerIdentity srvID = null;
  240.            
  241.             bool fServer;
  242.             srvID = (ServerIdentity)MarshalByRefObject.GetIdentity(obj, out fServer);
  243.            
  244.             if (srvID == null) {
  245.                 // Create a new server identity and add it to the
  246.                 // table. IdentityHolder will take care of races
  247.                 Context serverCtx = null;
  248.                
  249.                 if (obj is ContextBoundObject) {
  250.                     serverCtx = Thread.CurrentContext;
  251.                 }
  252.                 else {
  253.                     serverCtx = DefaultContext;
  254.                 }
  255.                 BCLDebug.Assert(null != serverCtx, "null != serverCtx");
  256.                
  257.                 ServerIdentity serverID = new ServerIdentity(obj, serverCtx);
  258.                
  259.                 // Set the identity depending on whether we have the server or proxy
  260.                 if (fServer) {
  261.                     srvID = obj.__RaceSetServerIdentity(serverID);
  262.                     BCLDebug.Assert(srvID == MarshalByRefObject.GetIdentity(obj), "Bad ID state!");
  263.                 }
  264.                 else {
  265.                     RealProxy rp = null;
  266.                     rp = RemotingServices.GetRealProxy(obj);
  267.                     BCLDebug.Assert(null != rp, "null != rp");
  268.                    
  269.                     rp.IdentityObject = serverID;
  270.                     srvID = (ServerIdentity)rp.IdentityObject;
  271.                 }
  272.                
  273.                 Message.DebugOut("Created ServerIdentity \n");
  274.             }
  275.            
  276.            
  277.             // NOTE: for purely x-context cases we never execute this ...
  278.             // the server ID is not put in the ID table.
  279.             if (IdOps.bStrongIdentity(flags)) {
  280.                 // We need to guarantee that finally is not interrupted so that the lock is released.
  281.                 // TableLock has a long path without reliability contract. To avoid adding contract on
  282.                 // the path, we will use ReaderWriterLock directly.
  283.                 ReaderWriterLock rwlock = TableLock;
  284.                 bool takeAndRelease = !rwlock.IsWriterLockHeld;
  285.                
  286.                 RuntimeHelpers.PrepareConstrainedRegions();
  287.                 try {
  288.                     if (takeAndRelease)
  289.                         rwlock.AcquireWriterLock(INFINITE);
  290.                    
  291.                     // It is possible that we are marshaling out of this app-domain
  292.                     // for the first time. We need to do two things
  293.                     // (1) If there is no URI associated with the identity then go ahead
  294.                     // and generate one.
  295.                     // (2) Add the identity to the URI -> Identity map if not already present
  296.                     // (For purely x-context cases we don't need the URI)
  297.                     // (3) If the object ref is null, then this object hasn't been
  298.                     // marshalled yet.
  299.                     // (4) if id was created through SetObjectUriForMarshal, it would be
  300.                     // in the ID table
  301.                     if ((srvID.ObjURI == null) || (srvID.IsInIDTable() == false)) {
  302.                         // we are marshalling a server object, so there should not be a
  303.                         // a different identity at this location.
  304.                         SetIdentity(srvID, objURI, DuplicateIdentityOption.Unique);
  305.                     }
  306.                    
  307.                     // If the object is marked as disconnect, mark it as connected
  308.                     if (srvID.IsDisconnected())
  309.                         srvID.SetFullyConnected();
  310.                 }
  311.                 finally {
  312.                     if (takeAndRelease && rwlock.IsWriterLockHeld) {
  313.                         rwlock.ReleaseWriterLock();
  314.                     }
  315.                 }
  316.             }
  317.            
  318.             Message.DebugOut("Leaving FindOrCreateServerIdentity \n");
  319.             BCLDebug.Assert(null != srvID, "null != srvID");
  320.             return srvID;
  321.         }
  322.        
  323.         //
  324.         //
  325.         // This is typically called when we are unmarshaling an objectref
  326.         // in order to create a client side identity for a remote server
  327.         // object.
  328.         static internal Identity FindOrCreateIdentity(string objURI, string URL, ObjRef objectRef)
  329.         {
  330.             Identity idObj = null;
  331.            
  332.             BCLDebug.Assert(null != objURI, "null != objURI");
  333.            
  334.             bool bWellKnown = (URL != null);
  335.            
  336.             // Lookup the object in the identity table
  337.             // for well-known objects we user the URL
  338.             // as the hash-key (instead of just the objUri)
  339.             idObj = ResolveIdentity(bWellKnown ? URL : objURI);
  340.             if (bWellKnown && (idObj != null) && (idObj is ServerIdentity)) {
  341.                 // We are trying to do a connect to a server wellknown object.
  342.                 throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_WellKnown_CantDirectlyConnect"), URL));
  343.             }
  344.            
  345.             if (null == idObj) {
  346.                 // There is no entry for this uri in the IdTable.
  347.                 Message.DebugOut("RemotingService::FindOrCreateIdentity: Creating Identity\n");
  348.                
  349.                 // This identity is being encountered for the first time.
  350.                 // We have to do the following things
  351.                 // (1) Create an identity object for the proxy
  352.                 // (2) Add the identity to the identity table
  353.                 // (3) Create a proxy for the object represented by the objref
  354.                
  355.                 // Create a new identity
  356.                 // Identity should get only one string that is used for everything
  357.                 idObj = new Identity(objURI, URL);
  358.                
  359.                 // We need to guarantee that finally is not interrupted so that the lock is released.
  360.                 // TableLock has a long path without reliability contract. To avoid adding contract on
  361.                 // the path, we will use ReaderWriterLock directly.
  362.                 ReaderWriterLock rwlock = TableLock;
  363.                 bool takeAndRelease = !rwlock.IsWriterLockHeld;
  364.                
  365.                 RuntimeHelpers.PrepareConstrainedRegions();
  366.                 try {
  367.                     // Add it to the identity table
  368.                     if (takeAndRelease)
  369.                         rwlock.AcquireWriterLock(INFINITE);
  370.                    
  371.                     // SetIdentity will give the correct Id if we raced
  372.                     // between the ResolveIdentity call above and now.
  373.                     // (we are unmarshaling, and the server should guarantee
  374.                     // that the uri is unique, so we will use an existing identity
  375.                     // in case of a race)
  376.                     idObj = SetIdentity(idObj, null, DuplicateIdentityOption.UseExisting);
  377.                    
  378.                     idObj.RaceSetObjRef(objectRef);
  379.                 }
  380.                 finally {
  381.                     if (takeAndRelease && rwlock.IsWriterLockHeld) {
  382.                         rwlock.ReleaseWriterLock();
  383.                     }
  384.                 }
  385.             }
  386.             else {
  387.                 Message.DebugOut("RemotingService::FindOrCreateIdentity: Found Identity!\n");
  388.             }
  389.             BCLDebug.Assert(null != idObj, "null != idObj");
  390.             return idObj;
  391.         }
  392.        
  393.        
  394.         // Creates an identity entry.
  395.         // This is used by Unmarshal and Marshal to generate the URI to identity
  396.         // mapping
  397.         //
  398.         //
  399.         private static Identity SetIdentity(Identity idObj, string URI, DuplicateIdentityOption duplicateOption)
  400.         {
  401.             // NOTE: This function assumes that a lock has been taken
  402.             // by the calling function
  403.             // idObj could be for a transparent proxy or a server object
  404.             Message.DebugOut("SetIdentity:: domainid: " + Thread.GetDomainID() + "\n");
  405.             BCLDebug.Assert(null != idObj, "null != idObj");
  406.            
  407.             // WriterLock must already be taken when SetIdentity is called!
  408.             BCLDebug.Assert(TableLock.IsWriterLockHeld, "Should have write-locked the ID Table!");
  409.            
  410.             // flag to denote that the id being set is a ServerIdentity
  411.             bool bServerIDSet = idObj is ServerIdentity;
  412.            
  413.             if (null == idObj.URI) {
  414.                 // No URI has been associated with this identity. It must be a
  415.                 // server identity getting marshaled out of the app domain for
  416.                 // the first time.
  417.                 BCLDebug.Assert(bServerIDSet, "idObj should be ServerIdentity");
  418.                
  419.                 // Set the URI on the idObj (generating one if needed)
  420.                 idObj.SetOrCreateURI(URI);
  421.                
  422.                 // If objectref is non-null make sure both have same URIs
  423.                 // (the URI in the objectRef could have potentially been reset
  424.                 // in a past external call to Disconnect()
  425.                 if (idObj.ObjectRef != null) {
  426.                     idObj.ObjectRef.URI = idObj.URI;
  427.                 }
  428.                 Message.DebugOut("SetIdentity: Generated URI " + URI + " for identity");
  429.             }
  430.            
  431.             // If we have come this far then there is no URI to identity
  432.             // mapping present. Go ahead and create one.
  433.            
  434.             // ID should have a URI by now.
  435.             BCLDebug.Assert(null != idObj.URI, "null != idObj.URI");
  436.            
  437.             // See if this identity is already present in the Uri table
  438.             string uriKey = MakeURIKey(idObj.URI);
  439.             object o = URITable[uriKey];
  440.            
  441.             // flag to denote that the id found in the table is a ServerIdentity
  442.             bool bServerID;
  443.             if (null != o) {
  444.                 // We found an identity (or a WeakRef to one) for the URI provided
  445.                 WeakReference wr = o as WeakReference;
  446.                 Identity idInTable = null;
  447.                 if (wr != null) {
  448.                     // The object we found is a weak referece to an identity
  449.                    
  450.                     // This could be an identity for a client side
  451.                     // proxy
  452.                     // OR
  453.                     // a server identity which has been weakened since its life
  454.                     // is over.
  455.                     idInTable = (Identity)wr.Target;
  456.                    
  457.                     bServerID = idInTable is ServerIdentity;
  458.                    
  459.                     // If we find a weakRef for a ServerId we will be converting
  460.                     // it to a strong one before releasing the IdTable lock.
  461.                     BCLDebug.Assert((idInTable == null) || (!bServerID || idInTable.IsRemoteDisconnected()), "Expect to find WeakRef only for remotely disconnected ids");
  462.                     // We could find a weakRef to a client ID that does not
  463.                     // match the idObj .. but that is a handled race case
  464.                     // during Unmarshaling .. SetIdentity() will return the ID
  465.                     // from the table to the caller.
  466.                 }
  467.                 else {
  468.                     // We found a non-weak (strong) Identity for the URI
  469.                     idInTable = (Identity)o;
  470.                     bServerID = idInTable is ServerIdentity;
  471.                    
  472.                     //We dont put strong refs to client "Identity"s in the table
  473.                     BCLDebug.Assert(bServerID, "Found client side strong ID in the table");
  474.                 }
  475.                
  476.                 if ((idInTable != null) && (idInTable != idObj)) {
  477.                     // We are trying to add another identity for the same URI
  478.                     switch (duplicateOption) {
  479.                         case DuplicateIdentityOption.Unique:
  480.                            
  481.                            
  482.                             {
  483.                                
  484.                                 string tempURI = idObj.URI;
  485.                                
  486.                                 // Throw an exception to indicate the error since this could
  487.                                 // be caused by a user trying to marshal two objects with the same
  488.                                 // URI
  489.                                 throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_URIClash"), tempURI));
  490.                             }
  491.                             break;
  492.                         case DuplicateIdentityOption.UseExisting:
  493.                             // case DuplicateIdentityOption.Unique
  494.                            
  495.                             {
  496.                                 // This would be a case where our thread lost the race
  497.                                 // we will return the one found in the table
  498.                                 idObj = idInTable;
  499.                                 break;
  500.                             }
  501.                             break;
  502.                         default:
  503.                             // case DuplicateIdentityOption.UseExisting:
  504.                            
  505.                             {
  506.                                 BCLDebug.Assert(false, "Invalid DuplicateIdentityOption");
  507.                                 break;
  508.                             }
  509.                             break;
  510.                        
  511.                     }
  512.                     // switch (duplicateOption)
  513.                 }
  514.                 else if (wr != null) {
  515.                     // We come here if we found a weakRef in the table but
  516.                     // the target object had been cleaned up
  517.                     // OR
  518.                     // If there was a weakRef in the table and the target
  519.                     // object matches the idObj just passed in
  520.                    
  521.                     // Strengthen the entry if it a ServerIdentity.
  522.                     if (bServerID) {
  523.                         URITable[uriKey] = idObj;
  524.                     }
  525.                     else {
  526.                         // For client IDs associate the table entry
  527.                         // with the one passed in.
  528.                         // (If target was null we would set it ...
  529.                         // if was non-null then it matches idObj anyway)
  530.                         wr.Target = idObj;
  531.                     }
  532.                 }
  533.             }
  534.             else {
  535.                 // We did not find an identity entry for the URI
  536.                 object addMe = null;
  537.                 if (bServerIDSet) {
  538.                     addMe = idObj;
  539.                     ((ServerIdentity)idObj).SetHandle();
  540.                 }
  541.                 else {
  542.                     addMe = new WeakReference(idObj);
  543.                 }
  544.                
  545.                 // Add the entry into the table
  546.                 URITable.Add(uriKey, addMe);
  547.                 idObj.SetInIDTable();
  548.                
  549.                 // After every fixed number of set-id calls we run through
  550.                 // the table and cleanup if needed.
  551.                 SetIDCount++;
  552.                 if (SetIDCount % CleanUpCountInterval == 0) {
  553.                     // This should be called with the write lock held!
  554.                     // (which is why we assert that at the beginning of this
  555.                     // method)
  556.                     CleanupIdentities(null);
  557.                 }
  558.                
  559.             }
  560.            
  561.             Message.DebugOut("SetIdentity:: Identity::URI: " + idObj.URI + "\n");
  562.             return idObj;
  563.         }
  564.        
  565.        
  566.         static internal void RemoveIdentity(string uri)
  567.         {
  568.             RemoveIdentity(uri, true);
  569.         }
  570.        
  571.         static internal void RemoveIdentity(string uri, bool bResetURI)
  572.         {
  573.             BCLDebug.Assert(uri != null, "Null URI");
  574.             BCLDebug.Trace("REMOTE", "IdentityHolder.WeakenIdentity ", uri, " for context ", Thread.CurrentContext);
  575.            
  576.             Identity id;
  577.             string uriKey = MakeURIKey(uri);
  578.             // We need to guarantee that finally is not interrupted so that the lock is released.
  579.             // TableLock has a long path without reliability contract. To avoid adding contract on
  580.             // the path, we will use ReaderWriterLock directly.
  581.             ReaderWriterLock rwlock = TableLock;
  582.             bool takeAndRelease = !rwlock.IsWriterLockHeld;
  583.            
  584.             RuntimeHelpers.PrepareConstrainedRegions();
  585.             try {
  586.                 if (takeAndRelease)
  587.                     rwlock.AcquireWriterLock(INFINITE);
  588.                
  589.                 object oRef = URITable[uriKey];
  590.                 WeakReference wr = oRef as WeakReference;
  591.                 if (null != wr) {
  592.                     id = (Identity)wr.Target;
  593.                     wr.Target = null;
  594.                 }
  595.                 else {
  596.                     id = (Identity)oRef;
  597.                     if (id != null)
  598.                         ((ServerIdentity)id).ResetHandle();
  599.                 }
  600.                
  601.                 if (id != null) {
  602.                     URITable.Remove(uriKey);
  603.                     // Mark the ID as not present in the ID Table
  604.                     // This will clear its URI & objRef fields
  605.                     id.ResetInIDTable(bResetURI);
  606.                 }
  607.             }
  608.             finally {
  609.                 if (takeAndRelease && rwlock.IsWriterLockHeld) {
  610.                     rwlock.ReleaseWriterLock();
  611.                 }
  612.             }
  613.         }
  614.         // RemoveIdentity
  615.        
  616.         // Support for dynamically registered property sinks
  617.         static internal bool AddDynamicProperty(MarshalByRefObject obj, IDynamicProperty prop)
  618.         {
  619.             if (RemotingServices.IsObjectOutOfContext(obj)) {
  620.                 // We have to add a proxy side property, get the identity
  621.                 RealProxy rp = RemotingServices.GetRealProxy(obj);
  622.                 return rp.IdentityObject.AddProxySideDynamicProperty(prop);
  623.             }
  624.             else {
  625.                 MarshalByRefObject realObj = (MarshalByRefObject)RemotingServices.AlwaysUnwrap((ContextBoundObject)obj);
  626.                 // This is a real object. See if we have an identity for it
  627.                 ServerIdentity srvID = (ServerIdentity)MarshalByRefObject.GetIdentity(realObj);
  628.                 if (srvID != null) {
  629.                     return srvID.AddServerSideDynamicProperty(prop);
  630.                 }
  631.                 else {
  632.                     // identity not found, we can't set a sink for this object.
  633.                     throw new RemotingException(Environment.GetResourceString("Remoting_NoIdentityEntry"));
  634.                    
  635.                 }
  636.             }
  637.         }
  638.        
  639.         static internal bool RemoveDynamicProperty(MarshalByRefObject obj, string name)
  640.         {
  641.             if (RemotingServices.IsObjectOutOfContext(obj)) {
  642.                 // We have to add a proxy side property, get the identity
  643.                 RealProxy rp = RemotingServices.GetRealProxy(obj);
  644.                 return rp.IdentityObject.RemoveProxySideDynamicProperty(name);
  645.             }
  646.             else {
  647.                
  648.                 MarshalByRefObject realObj = (MarshalByRefObject)RemotingServices.AlwaysUnwrap((ContextBoundObject)obj);
  649.                
  650.                 // This is a real object. See if we have an identity for it
  651.                 ServerIdentity srvID = (ServerIdentity)MarshalByRefObject.GetIdentity(realObj);
  652.                 if (srvID != null) {
  653.                     return srvID.RemoveServerSideDynamicProperty(name);
  654.                 }
  655.                 else {
  656.                     // identity not found, we can't set a sink for this object.
  657.                     throw new RemotingException(Environment.GetResourceString("Remoting_NoIdentityEntry"));
  658.                 }
  659.             }
  660.         }
  661.     }
  662.     // class IdentityHolder
  663. }

Developer Fusion