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 Console.WriteLine("Marshal() TP RealProxy -> uri = " + proxy.ObjectIdentity.ObjectUri);
151 ObjRef o = proxy.ObjectIdentity.CreateObjRef(requested_type);
153 Console.WriteLine("Marshal() channel data = " + o.ChannelInfo);
159 if (requested_type == null) requested_type = obj.GetType();
163 uri = app_id + Environment.TickCount + "_" + next_id++;
164 CreateClientActivatedServerIdentity (obj, requested_type, uri);
168 ClientActivatedIdentity identity = uri_hash [uri] as ClientActivatedIdentity;
169 if (identity == null || obj != identity.GetServerObject())
170 CreateClientActivatedServerIdentity (obj, requested_type, uri);
173 return obj.CreateObjRef(requested_type);
176 public static RealProxy GetRealProxy (object proxy)
178 if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy");
179 return (RealProxy)((TransparentProxy)proxy)._rp;
182 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
184 Type type = Type.GetType (msg.TypeName);
186 throw new RemotingException ("Type '" + msg.TypeName + "' not found!");
188 BindingFlags bflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
189 if (msg.MethodSignature == null)
190 return type.GetMethod (msg.MethodName, bflags);
192 return type.GetMethod (msg.MethodName, bflags, null, (Type[]) msg.MethodSignature, null);
195 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
197 if (obj == null) throw new ArgumentNullException ("obj");
199 ObjRef oref = Marshal ((MarshalByRefObject)obj);
200 oref.GetObjectData (info, context);
203 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
205 Identity ident = GetObjectIdentity(obj);
206 if (ident == null) return null;
207 else return ident.CreateObjRef(null);
211 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
213 throw new NotImplementedException ();
216 public static bool IsMethodOverloaded(IMethodMessage msg)
218 Type type = msg.MethodBase.DeclaringType;
219 MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
220 return members.Length > 1;
223 public static bool IsObjectOutOfAppDomain(object tp)
225 Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
226 if (ident != null) return !ident.IsFromThisAppDomain;
230 public static bool IsObjectOutOfContext(object tp)
232 ServerIdentity ident = GetObjectIdentity((MarshalByRefObject)tp) as ServerIdentity;
233 if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
237 public static bool IsOneWay(MethodBase method)
239 object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
240 return atts.Length > 0;
243 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
245 if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
249 #region Internal Methods
251 internal static Identity GetIdentityForUri (string uri)
255 return (Identity)uri_hash [uri];
259 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
261 if (IsTransparentProxy(obj))
262 return GetRealProxy (obj).ObjectIdentity;
264 return obj.ObjectIdentity;
267 private static ClientIdentity GetOrCreateClientIdentity(ObjRef objRef)
269 // This method looks for an identity for the given url.
270 // If an identity is not found, it creates the identity and
271 // assigns it a proxy to the remote object.
273 // Creates the client sink chain for the given url or channelData.
274 // It will also get the object uri from the url.
276 object channelData = objRef.ChannelInfo != null ? objRef.ChannelInfo.ChannelData : null;
277 string url = (channelData == null) ? objRef.URI : null;
280 IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
284 string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url);
285 throw new RemotingException (msg);
288 string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url);
289 throw new RemotingException (msg);
293 if (objectUri == null) objectUri = objRef.URI;
297 ClientIdentity identity = uri_hash [objRef.URI] as ClientIdentity;
298 if (identity != null)
299 return identity; // Object already registered
301 // Creates an identity and a proxy for the remote object
303 identity = new ClientIdentity (objectUri, objRef);
304 identity.ClientSink = sink;
306 RemotingProxy proxy = new RemotingProxy (Type.GetType (objRef.TypeInfo.TypeName), identity);
307 identity.ClientProxy = (MarshalByRefObject) proxy.GetTransparentProxy();
309 // Registers the identity
310 uri_hash [objRef.URI] = identity;
315 internal static ClientActivatedIdentity CreateClientActivatedServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri)
317 ClientActivatedIdentity identity = new ClientActivatedIdentity (objectUri, Context.DefaultContext, objectType);
318 identity.AttachServerObject (realObject);
319 RegisterServerIdentity (identity);
323 internal static ServerIdentity CreateWellKnownServerIdentity(Type objectType, string objectUri, WellKnownObjectMode mode)
325 ServerIdentity identity;
327 if (mode == WellKnownObjectMode.SingleCall)
328 identity = new SingleCallIdentity(objectUri, Context.DefaultContext, objectType);
330 identity = new SingletonIdentity(objectUri, Context.DefaultContext, objectType);
332 RegisterServerIdentity (identity);
336 private static void RegisterServerIdentity(Identity identity)
340 if (uri_hash.ContainsKey (identity.ObjectUri))
341 throw new RemotingException ("Uri already in use: " + identity.ObjectUri);
343 uri_hash[identity.ObjectUri] = identity;
347 internal static object GetRemoteObject(ObjRef objRef)
349 ClientIdentity id = GetOrCreateClientIdentity (objRef);
350 return id.ClientProxy;
353 internal static object GetDomainProxy(AppDomain domain)
355 ObjRef appRef = null;
357 // Make sure that the channels is active in this domain
358 RegisterInternalChannels();
360 // this should use contexts in the future
361 AppDomain currentDomain = AppDomain.InternalSetDomain (domain);
364 // Make sure that our new domain also has the internal channels
365 RegisterInternalChannels();
367 appRef = RemotingServices.Marshal(domain, null, null);
371 AppDomain.InternalSetDomain (currentDomain);
374 return (AppDomain) RemotingServices.Unmarshal(appRef);
377 private static void RegisterInternalChannels()
379 CrossAppDomainChannel.RegisterCrossAppDomainChannel();
382 internal static void DisposeIdentity (Identity ident)
384 uri_hash.Remove (ident.ObjectUri);
387 internal static ServerIdentity GetMessageTargetIdentity (IMessage msg)
389 // Returns the identity where the message is sent
390 // TODO: check for identity embedded in MethodCall
394 return uri_hash [((IMethodMessage)msg).Uri] as ServerIdentity;