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 CreateServerIdentity (null, typeof(RemoteActivator), "RemoteActivationService.rem", ServiceType.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 return GetRemoteObject(classToProxy, url, null, null);
89 public static object Connect (Type classToProxy, string url, object data)
91 return GetRemoteObject (classToProxy, url, data, null);
94 public static Type GetServerTypeForUri (string uri)
96 Identity ident = GetIdentityForUri (uri);
97 if (ident == null) return null;
98 return ident.ObjectType;
101 public static string GetObjectUri (MarshalByRefObject obj)
103 Identity ident = GetObjectIdentity(obj);
104 if (ident != null) return ident.ObjectUri;
108 public static object Unmarshal (ObjRef objref)
110 return Unmarshal(objref, false);
113 public static object Unmarshal (ObjRef objref, bool fRefine)
115 // FIXME: use type name when fRefine==true
116 Type requiredType = Type.GetType(objref.TypeInfo.TypeName);
117 return GetRemoteObject(requiredType, null, objref.ChannelInfo.ChannelData, objref.URI);
120 public static ObjRef Marshal (MarshalByRefObject obj)
122 return Marshal (obj, null, null);
125 public static ObjRef Marshal (MarshalByRefObject obj, string uri)
127 return Marshal (obj, uri, null);
130 public static ObjRef Marshal (MarshalByRefObject obj, string uri, Type requested_type)
132 if (IsTransparentProxy (obj))
134 RealProxy proxy = RemotingServices.GetRealProxy(obj);
135 if (proxy != null && proxy.ObjectIdentity != null)
138 throw new RemotingException ("It is not possible marshal a proxy of a remote object");
140 return proxy.ObjectIdentity.CreateObjRef(requested_type);
144 if (requested_type == null) requested_type = obj.GetType();
145 if (uri == null) uri = app_id + Environment.TickCount + "_" + next_id++;
147 CreateServerIdentity (obj, requested_type, uri, ServiceType.ClientActivated);
148 return obj.CreateObjRef(requested_type);
151 public static RealProxy GetRealProxy (object proxy)
153 if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy");
154 return (RealProxy)((TransparentProxy)proxy)._rp;
157 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
159 Type type = Type.GetType (msg.TypeName);
161 throw new RemotingException ("Type '" + msg.TypeName + "' not found!");
163 BindingFlags bflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
164 if (msg.MethodSignature == null)
165 return type.GetMethod (msg.MethodName, bflags);
167 return type.GetMethod (msg.MethodName, bflags, null, (Type[]) msg.MethodSignature, null);
170 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
172 if (obj == null) throw new ArgumentNullException ("obj");
174 MarshalByRefObject mbr = (MarshalByRefObject)obj;
177 Identity ident = GetObjectIdentity(mbr);
180 oref = mbr.CreateObjRef(null);
182 oref = Marshal (mbr);
184 oref.GetObjectData (info, context);
187 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
189 Identity ident = GetObjectIdentity(obj);
190 if (ident == null) return null;
191 else return ident.CreateObjRef(null);
195 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
197 throw new NotImplementedException ();
200 public static bool IsMethodOverloaded(IMethodMessage msg)
202 Type type = msg.MethodBase.DeclaringType;
203 MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
\r
204 return members.Length > 1;
\r
207 public static bool IsObjectOutOfAppDomain(object tp)
209 Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
210 if (ident != null) return !ident.IsFromThisAppDomain;
214 public static bool IsObjectOutOfContext(object tp)
216 Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
217 if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
221 public static bool IsOneWay(MethodBase method)
223 object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
224 return atts.Length > 0;
227 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
229 if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
233 #region Internal Methods
235 internal static Identity GetIdentityForUri (string uri)
239 return (Identity)uri_hash [uri];
243 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
245 if (IsTransparentProxy(obj))
246 return GetRealProxy (obj).ObjectIdentity;
248 return obj.ObjectIdentity;
251 private static Identity GetClientIdentity(Type requiredType, string url, object channelData, string remotedObjectUri)
253 // This method looks for an identity for the given url.
254 // If an identity is not found, it creates the identity and
255 // assigns it a proxy to the remote object.
257 // Creates the client sink chain for the given url or channelData.
258 // It will also get the object uri from the url.
261 IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
265 string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url);
266 throw new RemotingException (msg);
269 string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url);
270 throw new RemotingException (msg);
274 if (objectUri == null) objectUri = remotedObjectUri;
278 Identity identity = (Identity)uri_hash [objectUri];
279 if (identity != null)
280 return identity; // Object already registered
282 // Creates an identity and a proxy for the remote object
284 identity = new Identity (objectUri, null, requiredType, ServiceType.ClientProxy);
285 identity.ClientSink = sink;
287 RemotingProxy proxy = new RemotingProxy (requiredType, identity);
289 identity.RealObject = (MarshalByRefObject) proxy.GetTransparentProxy();
291 // Registers the identity
292 uri_hash [objectUri] = identity;
297 internal static Identity CreateServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri, ServiceType serviceType)
299 // This method looks for an identity for the given object.
300 // If an identity is not found, it creates the identity and
301 // assigns it to the given object
305 Identity identity = (Identity)uri_hash [objectUri];
306 if (identity != null)
308 if (realObject != identity.RealObject)
309 throw new RemotingException ("Uri already in use: " + objectUri);
311 return identity; // Object already registered
314 identity = new Identity (objectUri, Context.DefaultContext, objectType, serviceType);
315 identity.RealObject = realObject;
317 // Registers the identity
318 uri_hash[objectUri] = identity;
320 if (realObject != null)
321 realObject.ObjectIdentity = identity;
323 LifetimeServices.TrackLifetime (identity);
329 internal static object GetRemoteObject(Type requiredType, string url, object channelData, string remotedObjectUri)
331 Identity id = GetClientIdentity(requiredType, url, channelData, remotedObjectUri);
332 return id.RealObject;
335 internal static object GetDomainProxy(AppDomain domain)
\r
337 ObjRef appRef = null;
\r
339 // Make sure that the channels is active in this domain
\r
340 RegisterInternalChannels();
\r
342 // this should use contexts in the future
\r
343 AppDomain currentDomain = AppDomain.InternalSetDomain (domain);
\r
346 // Make sure that our new domain also has the internal channels
\r
347 RegisterInternalChannels();
\r
349 appRef = RemotingServices.Marshal(domain, null, null);
\r
353 AppDomain.InternalSetDomain (currentDomain);
\r
356 return (AppDomain) RemotingServices.Unmarshal(appRef);
\r
360 private static void RegisterInternalChannels()
\r
362 CrossAppDomainChannel.RegisterCrossAppDomainChannel();
\r
366 internal static void DisposeObject (MarshalByRefObject obj)
368 IDisposable disp = obj as IDisposable;
369 if (disp != null) disp.Dispose ();
371 Identity ident = GetObjectIdentity (obj);
372 if (ident == null) return;
373 else uri_hash.Remove (ident.ObjectUri);