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 Identity identity = proxy.ObjectIdentity;
146 if (identity != null)
148 if (identity.ObjectType.IsContextful && identity.ObjectUri == null)
150 // Unregistered contextbound object. Register now.
151 if (uri == null) uri = NewUri();
152 identity.ObjectUri = uri;
153 RegisterServerIdentity ((ServerIdentity) identity);
154 ((ServerIdentity)identity).StartTrackingLifetime();
156 else if (uri != null)
157 throw new RemotingException ("It is not possible marshal a proxy of a remote object");
159 return proxy.ObjectIdentity.CreateObjRef(requested_type);
163 if (requested_type == null) requested_type = obj.GetType();
168 CreateClientActivatedServerIdentity (obj, requested_type, uri);
172 ClientActivatedIdentity identity = uri_hash [uri] as ClientActivatedIdentity;
173 if (identity == null || obj != identity.GetServerObject())
174 CreateClientActivatedServerIdentity (obj, requested_type, uri);
177 return obj.CreateObjRef(requested_type);
180 static string NewUri ()
182 return app_id + Environment.TickCount + "_" + next_id++;
185 public static RealProxy GetRealProxy (object proxy)
187 if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy");
188 return (RealProxy)((TransparentProxy)proxy)._rp;
191 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
193 Type type = Type.GetType (msg.TypeName);
195 throw new RemotingException ("Type '" + msg.TypeName + "' not found!");
197 BindingFlags bflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
198 if (msg.MethodSignature == null)
199 return type.GetMethod (msg.MethodName, bflags);
201 return type.GetMethod (msg.MethodName, bflags, null, (Type[]) msg.MethodSignature, null);
204 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
206 if (obj == null) throw new ArgumentNullException ("obj");
208 ObjRef oref = Marshal ((MarshalByRefObject)obj);
209 oref.GetObjectData (info, context);
212 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
214 Identity ident = GetObjectIdentity(obj);
215 if (ident == null) return null;
216 else return ident.CreateObjRef(null);
220 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
222 throw new NotImplementedException ();
225 public static bool IsMethodOverloaded(IMethodMessage msg)
227 Type type = msg.MethodBase.DeclaringType;
228 MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
229 return members.Length > 1;
232 public static bool IsObjectOutOfAppDomain(object tp)
234 Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
235 if (ident != null) return !ident.IsFromThisAppDomain;
239 public static bool IsObjectOutOfContext(object tp)
241 ServerIdentity ident = GetObjectIdentity((MarshalByRefObject)tp) as ServerIdentity;
242 if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
246 public static bool IsOneWay(MethodBase method)
248 object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
249 return atts.Length > 0;
252 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
254 if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
258 #region Internal Methods
260 internal static object CreateClientProxy (ActivatedClientTypeEntry entry)
262 string activationUrl = entry.ApplicationUrl + "/RemoteActivationService.rem";
265 IMessageSink sink = GetClientChannelSinkChain (activationUrl, null, out objectUri);
267 RemotingProxy proxy = new RemotingProxy (entry.ObjectType, activationUrl, sink);
268 return proxy.GetTransparentProxy();
271 internal static object CreateClientProxy (WellKnownClientTypeEntry entry)
273 return Connect (entry.ObjectType, entry.ObjectUrl);
276 internal static object CreateClientProxyForContextBound (Type type)
278 RemotingProxy proxy = new RemotingProxy (type, ChannelServices.CrossContextUrl, ChannelServices.CrossContextChannel);
279 return proxy.GetTransparentProxy();
282 internal static Identity GetIdentityForUri (string uri)
286 return (Identity)uri_hash [uri];
290 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
292 if (IsTransparentProxy(obj))
293 return GetRealProxy (obj).ObjectIdentity;
295 return obj.ObjectIdentity;
298 internal static ClientIdentity GetOrCreateClientIdentity(ObjRef objRef, RealProxy proxyToAttach)
300 // This method looks for an identity for the given url.
301 // If an identity is not found, it creates the identity and
302 // assigns it a proxy to the remote object.
304 // Creates the client sink chain for the given url or channelData.
305 // It will also get the object uri from the url.
307 object channelData = objRef.ChannelInfo != null ? objRef.ChannelInfo.ChannelData : null;
308 string url = (channelData == null) ? objRef.URI : null;
311 IMessageSink sink = GetClientChannelSinkChain (url, channelData, out objectUri);
313 if (objectUri == null) objectUri = objRef.URI;
317 ClientIdentity identity = uri_hash [objRef.URI] as ClientIdentity;
318 if (identity != null)
319 return identity; // Object already registered
321 // Creates an identity and a proxy for the remote object
323 identity = new ClientIdentity (objectUri, objRef);
324 identity.ChannelSink = sink;
326 if (proxyToAttach == null) proxyToAttach = new RemotingProxy (Type.GetType (objRef.TypeInfo.TypeName), identity);
327 identity.ClientProxy = (MarshalByRefObject) proxyToAttach.GetTransparentProxy();
329 // Registers the identity
330 uri_hash [objRef.URI] = identity;
335 static IMessageSink GetClientChannelSinkChain(string url, object channelData, out string objectUri)
337 IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
342 string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url);
343 throw new RemotingException (msg);
347 string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url);
348 throw new RemotingException (msg);
354 internal static ClientActivatedIdentity CreateContextBoundObjectIdentity(Type objectType)
356 ClientActivatedIdentity identity = new ClientActivatedIdentity (null, objectType);
357 identity.ChannelSink = ChannelServices.CrossContextChannel;
361 internal static ClientActivatedIdentity CreateClientActivatedServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri)
363 ClientActivatedIdentity identity = new ClientActivatedIdentity (objectUri, objectType);
364 identity.AttachServerObject (realObject, Context.DefaultContext);
365 RegisterServerIdentity (identity);
366 identity.StartTrackingLifetime();
370 internal static ServerIdentity CreateWellKnownServerIdentity(Type objectType, string objectUri, WellKnownObjectMode mode)
372 ServerIdentity identity;
374 if (mode == WellKnownObjectMode.SingleCall)
375 identity = new SingleCallIdentity(objectUri, Context.DefaultContext, objectType);
377 identity = new SingletonIdentity(objectUri, Context.DefaultContext, objectType);
379 RegisterServerIdentity (identity);
383 private static void RegisterServerIdentity(ServerIdentity identity)
387 if (uri_hash.ContainsKey (identity.ObjectUri))
388 throw new RemotingException ("Uri already in use: " + identity.ObjectUri);
390 uri_hash[identity.ObjectUri] = identity;
394 internal static object GetRemoteObject(ObjRef objRef)
396 ClientIdentity id = GetOrCreateClientIdentity (objRef, null);
397 return id.ClientProxy;
400 internal static object GetDomainProxy(AppDomain domain)
402 ObjRef appRef = null;
404 // Make sure that the channels is active in this domain
405 RegisterInternalChannels();
407 // this should use contexts in the future
408 AppDomain currentDomain = AppDomain.InternalSetDomain (domain);
411 // Make sure that our new domain also has the internal channels
412 RegisterInternalChannels();
414 appRef = RemotingServices.Marshal(domain, null, null);
418 AppDomain.InternalSetDomain (currentDomain);
421 return (AppDomain) RemotingServices.Unmarshal(appRef);
424 private static void RegisterInternalChannels()
426 CrossAppDomainChannel.RegisterCrossAppDomainChannel();
429 internal static void DisposeIdentity (Identity ident)
431 uri_hash.Remove (ident.ObjectUri);
434 internal static Identity GetMessageTargetIdentity (IMessage msg)
436 // Returns the identity where the message is sent
438 if (msg is IInternalMessage)
439 return ((IInternalMessage)msg).TargetIdentity;
443 return uri_hash [((IMethodMessage)msg).Uri] as ServerIdentity;
447 internal static void SetMessageTargetIdentity (IMessage msg, Identity ident)
449 if (msg is IInternalMessage)
450 ((IInternalMessage)msg).TargetIdentity = ident;