2 // System.Runtime.Remoting.RemotingServices.cs
5 // Dietmar Maurer (dietmar@ximian.com)
6 // Lluis Sanchez Gual (lluis@ideary.com)
9 // (C) 2001 Ximian, Inc. http://www.ximian.com
13 using System.Reflection;
14 using System.Threading;
15 using System.Collections;
16 using System.Runtime.Remoting.Messaging;
17 using System.Runtime.Remoting.Proxies;
18 using System.Runtime.Remoting.Channels;
19 using System.Runtime.Remoting.Contexts;
20 using System.Runtime.Remoting.Activation;
21 using System.Runtime.Remoting.Lifetime;
22 using System.Runtime.CompilerServices;
23 using System.Runtime.Serialization;
25 namespace System.Runtime.Remoting
27 public sealed class RemotingServices
29 // Holds the identities of the objects, using uri as index
30 static Hashtable uri_hash = new Hashtable ();
32 internal static string app_id;
33 static int next_id = 1;
35 static RemotingServices ()
37 app_id = "/" + Guid.NewGuid().ToString().Replace('-', '_') + "/";
39 CreateWellKnownServerIdentity (typeof(RemoteActivator), "RemoteActivationService.rem", WellKnownObjectMode.Singleton);
42 private RemotingServices () {}
44 [MethodImplAttribute(MethodImplOptions.InternalCall)]
45 internal extern static object InternalExecute (MonoMethod method, Object obj,
46 Object[] parameters, out object [] out_args);
48 [MethodImplAttribute(MethodImplOptions.InternalCall)]
49 public extern static bool IsTransparentProxy (object proxy);
51 internal static IMethodReturnMessage InternalExecuteMessage (
52 MarshalByRefObject target, IMethodCallMessage reqMsg)
56 MonoMethod method = (MonoMethod)reqMsg.MethodBase;
60 object rval = InternalExecute (method, target, reqMsg.Args, out out_args);
61 result = new ReturnMessage (rval, out_args, out_args.Length,
62 reqMsg.LogicalCallContext, reqMsg);
64 } catch (Exception e) {
65 result = new ReturnMessage (e, reqMsg);
71 public static IMethodReturnMessage ExecuteMessage (
72 MarshalByRefObject target, IMethodCallMessage reqMsg)
74 if (IsTransparentProxy(target))
76 // Message must go through all chain of sinks
77 RealProxy rp = GetRealProxy (target);
78 return (IMethodReturnMessage) rp.Invoke (reqMsg);
81 return InternalExecuteMessage (target, reqMsg);
84 public static object Connect (Type classToProxy, string url)
86 ObjRef objRef = new ObjRef (classToProxy, url, null);
87 return GetRemoteObject(objRef);
90 public static object Connect (Type classToProxy, string url, object data)
92 ObjRef objRef = new ObjRef (classToProxy, url, data);
93 return GetRemoteObject(objRef);
96 public static Type GetServerTypeForUri (string uri)
98 Identity ident = GetIdentityForUri (uri);
99 if (ident == null) return null;
100 return ident.ObjectType;
103 public static string GetObjectUri (MarshalByRefObject obj)
105 Identity ident = GetObjectIdentity(obj);
106 if (ident != null) return ident.ObjectUri;
110 public static object Unmarshal (ObjRef objref)
112 return Unmarshal(objref, false);
115 public static object Unmarshal (ObjRef objref, bool fRefine)
117 // FIXME: use type name when fRefine==true
119 if (objref.IsReferenceToWellKnow)
120 return GetRemoteObject(objref);
123 ClientActivatedIdentity identity = uri_hash [objref.URI] as ClientActivatedIdentity;
124 if (identity != null) return identity.GetServerObject ();
125 else return GetRemoteObject (objref);
129 public static ObjRef Marshal (MarshalByRefObject obj)
131 return Marshal (obj, null, null);
134 public static ObjRef Marshal (MarshalByRefObject obj, string uri)
136 return Marshal (obj, uri, null);
139 public static ObjRef Marshal (MarshalByRefObject obj, string uri, Type requested_type)
141 if (IsTransparentProxy (obj))
143 RealProxy proxy = RemotingServices.GetRealProxy(obj);
144 if (proxy != null && proxy.ObjectIdentity != null)
147 throw new RemotingException ("It is not possible marshal a proxy of a remote object");
149 return proxy.ObjectIdentity.CreateObjRef(requested_type);
153 if (requested_type == null) requested_type = obj.GetType();
157 uri = app_id + Environment.TickCount + "_" + next_id++;
158 CreateClientActivatedServerIdentity (obj, requested_type, uri);
162 ClientActivatedIdentity identity = uri_hash [uri] as ClientActivatedIdentity;
163 if (identity == null || obj != identity.GetServerObject())
164 CreateClientActivatedServerIdentity (obj, requested_type, uri);
167 return obj.CreateObjRef(requested_type);
170 public static RealProxy GetRealProxy (object proxy)
172 if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy");
173 return (RealProxy)((TransparentProxy)proxy)._rp;
176 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
178 Type type = Type.GetType (msg.TypeName);
180 throw new RemotingException ("Type '" + msg.TypeName + "' not found!");
182 BindingFlags bflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
183 if (msg.MethodSignature == null)
184 return type.GetMethod (msg.MethodName, bflags);
186 return type.GetMethod (msg.MethodName, bflags, null, (Type[]) msg.MethodSignature, null);
189 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
191 if (obj == null) throw new ArgumentNullException ("obj");
193 MarshalByRefObject mbr = (MarshalByRefObject)obj;
196 Identity ident = GetObjectIdentity(mbr);
199 oref = ident.CreateObjRef(null);
201 oref = Marshal (mbr);
203 oref.GetObjectData (info, context);
206 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
208 Identity ident = GetObjectIdentity(obj);
209 if (ident == null) return null;
210 else return ident.CreateObjRef(null);
214 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
216 throw new NotImplementedException ();
219 public static bool IsMethodOverloaded(IMethodMessage msg)
221 Type type = msg.MethodBase.DeclaringType;
222 MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
223 return members.Length > 1;
226 public static bool IsObjectOutOfAppDomain(object tp)
228 Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
229 if (ident != null) return !ident.IsFromThisAppDomain;
233 public static bool IsObjectOutOfContext(object tp)
235 ServerIdentity ident = GetObjectIdentity((MarshalByRefObject)tp) as ServerIdentity;
236 if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
240 public static bool IsOneWay(MethodBase method)
242 object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
243 return atts.Length > 0;
246 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
248 if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
252 #region Internal Methods
254 internal static Identity GetIdentityForUri (string uri)
258 return (Identity)uri_hash [uri];
262 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
264 if (IsTransparentProxy(obj))
265 return GetRealProxy (obj).ObjectIdentity;
267 return obj.ObjectIdentity;
270 private static ClientIdentity GetOrCreateClientIdentity(ObjRef objRef)
272 // This method looks for an identity for the given url.
273 // If an identity is not found, it creates the identity and
274 // assigns it a proxy to the remote object.
276 // Creates the client sink chain for the given url or channelData.
277 // It will also get the object uri from the url.
279 object channelData = objRef.ChannelInfo != null ? objRef.ChannelInfo.ChannelData : null;
280 string url = (channelData == null) ? objRef.URI : null;
283 IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
287 string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url);
288 throw new RemotingException (msg);
291 string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url);
292 throw new RemotingException (msg);
296 if (objectUri == null) objectUri = objRef.URI;
300 ClientIdentity identity = uri_hash [objRef.URI] as ClientIdentity;
301 if (identity != null)
302 return identity; // Object already registered
304 // Creates an identity and a proxy for the remote object
306 identity = new ClientIdentity (objectUri, objRef);
307 identity.ClientSink = sink;
309 RemotingProxy proxy = new RemotingProxy (Type.GetType (objRef.TypeInfo.TypeName), identity);
310 identity.ClientProxy = (MarshalByRefObject) proxy.GetTransparentProxy();
312 // Registers the identity
313 uri_hash [objRef.URI] = identity;
318 internal static ClientActivatedIdentity CreateClientActivatedServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri)
320 ClientActivatedIdentity identity = new ClientActivatedIdentity (objectUri, Context.DefaultContext, objectType);
321 identity.AttachServerObject (realObject);
322 RegisterServerIdentity (identity);
326 internal static ServerIdentity CreateWellKnownServerIdentity(Type objectType, string objectUri, WellKnownObjectMode mode)
328 ServerIdentity identity;
330 if (mode == WellKnownObjectMode.SingleCall)
331 identity = new SingleCallIdentity(objectUri, Context.DefaultContext, objectType);
333 identity = new SingletonIdentity(objectUri, Context.DefaultContext, objectType);
335 RegisterServerIdentity (identity);
339 private static void RegisterServerIdentity(Identity identity)
343 if (uri_hash.ContainsKey (identity.ObjectUri))
344 throw new RemotingException ("Uri already in use: " + identity.ObjectUri);
346 uri_hash[identity.ObjectUri] = identity;
350 internal static object GetRemoteObject(ObjRef objRef)
352 ClientIdentity id = GetOrCreateClientIdentity (objRef);
353 return id.ClientProxy;
356 internal static object GetDomainProxy(AppDomain domain)
358 ObjRef appRef = null;
360 // Make sure that the channels is active in this domain
361 RegisterInternalChannels();
363 // this should use contexts in the future
364 AppDomain currentDomain = AppDomain.InternalSetDomain (domain);
367 // Make sure that our new domain also has the internal channels
368 RegisterInternalChannels();
370 appRef = RemotingServices.Marshal(domain, null, null);
374 AppDomain.InternalSetDomain (currentDomain);
377 return (AppDomain) RemotingServices.Unmarshal(appRef);
380 private static void RegisterInternalChannels()
382 CrossAppDomainChannel.RegisterCrossAppDomainChannel();
385 internal static void DisposeIdentity (Identity ident)
387 uri_hash.Remove (ident.ObjectUri);
390 internal static ServerIdentity GetMessageTargetIdentity (IMessage msg)
392 // Returns the identity where the message is sent
393 // TODO: check for identity embedded in MethodCall
397 return uri_hash [((IMethodMessage)msg).Uri] as ServerIdentity;