2 // System.Runtime.Remoting.MessageFormatter.cs
4 // Author: Lluis Sanchez Gual (lluis@ideary.com)
6 // (C) 2003, Lluis Sanchez Gual
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Reflection;
\r
35 using System.Collections;
\r
36 using System.Runtime.Remoting;
\r
37 using System.Runtime.Serialization;
\r
38 using System.Runtime.Remoting.Messaging;
\r
40 namespace System.Runtime.Serialization.Formatters.Binary
\r
42 internal class MessageFormatter
\r
44 public static void WriteMethodCall (BinaryWriter writer, object obj, Header[] headers, ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat, FormatterTypeStyle typeFormat)
\r
46 IMethodCallMessage call = (IMethodCallMessage)obj;
\r
47 writer.Write ((byte) BinaryElement.MethodCall);
\r
49 MethodFlags methodFlags;
\r
50 int infoArraySize = 0;
\r
52 object[] extraProperties = null;
\r
54 if (call.LogicalCallContext != null && call.LogicalCallContext.HasInfo)
\r
56 methodFlags = MethodFlags.IncludesLogicalCallContext;
\r
60 methodFlags = MethodFlags.ExcludeLogicalCallContext;
\r
62 if (RemotingServices.IsMethodOverloaded (call))
\r
65 methodFlags |= MethodFlags.IncludesSignature;
\r
68 if (call.Properties.Count > MethodCallDictionary.InternalKeys.Length)
\r
70 extraProperties = GetExtraProperties (call.Properties, MethodCallDictionary.InternalKeys);
\r
74 if (call.ArgCount == 0)
\r
75 methodFlags |= MethodFlags.NoArguments;
\r
77 if (AllTypesArePrimitive (call.Args))
\r
78 methodFlags |= MethodFlags.PrimitiveArguments;
\r
80 if (infoArraySize == 0)
\r
81 methodFlags |= MethodFlags.ArgumentsInSimpleArray;
\r
83 methodFlags |= MethodFlags.ArgumentsInMultiArray;
\r
89 writer.Write ((byte) (methodFlags));
\r
91 // FIXME: what are the following 3 bytes for?
\r
92 writer.Write ((byte) 0);
\r
93 writer.Write ((byte) 0);
\r
94 writer.Write ((byte) 0);
\r
97 writer.Write ((byte) BinaryTypeCode.String);
\r
98 writer.Write (call.MethodName);
\r
101 writer.Write ((byte) BinaryTypeCode.String);
\r
102 writer.Write (call.TypeName);
\r
106 if ((methodFlags & MethodFlags.PrimitiveArguments) > 0)
\r
108 writer.Write ((uint)call.Args.Length);
\r
109 for (int n=0; n<call.ArgCount; n++)
\r
111 object arg = call.GetArg(n);
\r
113 writer.Write (BinaryCommon.GetTypeCode (arg.GetType()));
\r
114 ObjectWriter.WritePrimitiveValue (writer, arg);
\r
117 writer.Write ((byte)BinaryTypeCode.Null);
\r
121 if ( infoArraySize > 0)
\r
123 object[] ainfo = new object[infoArraySize];
\r
125 if ((methodFlags & MethodFlags.ArgumentsInMultiArray) > 0) ainfo[n++] = call.Args;
\r
126 if ((methodFlags & MethodFlags.IncludesSignature) > 0) ainfo[n++] = call.MethodSignature;
\r
127 if ((methodFlags & MethodFlags.IncludesLogicalCallContext) > 0) ainfo[n++] = call.LogicalCallContext;
\r
128 if (extraProperties != null) ainfo[n++] = extraProperties;
\r
131 else if ((methodFlags & MethodFlags.ArgumentsInSimpleArray) > 0)
\r
136 ObjectWriter objectWriter = new ObjectWriter (surrogateSelector, context, assemblyFormat, typeFormat);
\r
137 objectWriter.WriteObjectGraph (writer, info, headers);
\r
140 writer.Write ((byte) BinaryElement.End);
\r
143 public static void WriteMethodResponse (BinaryWriter writer, object obj, Header[] headers, ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat, FormatterTypeStyle typeFormat)
\r
145 IMethodReturnMessage resp = (IMethodReturnMessage)obj;
\r
146 writer.Write ((byte) BinaryElement.MethodResponse);
\r
148 string[] internalProperties = MethodReturnDictionary.InternalReturnKeys;
\r
150 int infoArrayLength = 0;
\r
151 object info = null;
\r
152 object[] extraProperties = null;
\r
154 // Type of return value
\r
156 ReturnTypeTag returnTypeTag;
\r
158 if (resp.Exception != null) {
\r
159 returnTypeTag = ReturnTypeTag.Exception | ReturnTypeTag.Null;
\r
160 info = new object[] {resp.Exception};
\r
161 internalProperties = MethodReturnDictionary.InternalExceptionKeys;
\r
163 else if (resp.ReturnValue == null) {
\r
164 returnTypeTag = ReturnTypeTag.Null;
\r
166 else if (IsMethodPrimitive(resp.ReturnValue.GetType())) {
\r
167 returnTypeTag = ReturnTypeTag.PrimitiveType;
\r
170 returnTypeTag = ReturnTypeTag.ObjectType;
\r
176 MethodFlags contextFlag;
\r
177 MethodFlags formatFlag;
\r
179 if ((resp.LogicalCallContext != null) && resp.LogicalCallContext.HasInfo && ((returnTypeTag & ReturnTypeTag.Exception) == 0))
\r
181 contextFlag = MethodFlags.IncludesLogicalCallContext;
\r
185 contextFlag = MethodFlags.ExcludeLogicalCallContext;
\r
187 if (resp.Properties.Count > internalProperties.Length && ((returnTypeTag & ReturnTypeTag.Exception) == 0))
\r
189 extraProperties = GetExtraProperties (resp.Properties, internalProperties);
\r
193 if (resp.OutArgCount == 0)
\r
194 formatFlag = MethodFlags.NoArguments;
\r
197 if (AllTypesArePrimitive (resp.Args))
\r
198 formatFlag = MethodFlags.PrimitiveArguments;
\r
201 if (infoArrayLength == 0)
\r
202 formatFlag = MethodFlags.ArgumentsInSimpleArray;
\r
204 formatFlag = MethodFlags.ArgumentsInMultiArray;
\r
210 writer.Write ((byte) (contextFlag | formatFlag));
\r
211 writer.Write ((byte) returnTypeTag);
\r
213 // FIXME: what are the following 2 bytes for?
\r
214 writer.Write ((byte) 0);
\r
215 writer.Write ((byte) 0);
\r
219 if (returnTypeTag == ReturnTypeTag.PrimitiveType)
\r
221 writer.Write (BinaryCommon.GetTypeCode (resp.ReturnValue.GetType()));
\r
222 ObjectWriter.WritePrimitiveValue (writer, resp.ReturnValue);
\r
225 if (formatFlag == MethodFlags.PrimitiveArguments)
\r
227 writer.Write ((uint)resp.ArgCount);
\r
228 for (int n=0; n<resp.ArgCount; n++)
\r
230 object val = resp.GetArg(n);
\r
232 writer.Write (BinaryCommon.GetTypeCode (val.GetType()));
\r
233 ObjectWriter.WritePrimitiveValue (writer, val);
\r
236 writer.Write ((byte)BinaryTypeCode.Null);
\r
240 if (infoArrayLength > 0)
\r
242 object[] infoArray = new object[infoArrayLength];
\r
245 if (formatFlag == MethodFlags.ArgumentsInMultiArray)
\r
246 infoArray[n++] = resp.Args;
\r
248 if (returnTypeTag == ReturnTypeTag.ObjectType)
\r
249 infoArray[n++] = resp.ReturnValue;
\r
251 if (contextFlag == MethodFlags.IncludesLogicalCallContext)
\r
252 infoArray[n++] = resp.LogicalCallContext;
\r
254 if (extraProperties != null)
\r
255 infoArray[n++] = extraProperties;
\r
259 else if ((formatFlag & MethodFlags.ArgumentsInSimpleArray) > 0)
\r
264 ObjectWriter objectWriter = new ObjectWriter (surrogateSelector, context, assemblyFormat, typeFormat);
\r
265 objectWriter.WriteObjectGraph (writer, info, headers);
\r
268 writer.Write ((byte) BinaryElement.End);
\r
271 public static object ReadMethodCall (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, BinaryFormatter formatter)
\r
273 BinaryElement elem = (BinaryElement)reader.ReadByte(); // The element code
\r
274 if (elem != BinaryElement.MethodCall) throw new SerializationException("Invalid format. Expected BinaryElement.MethodCall, found " + elem);
\r
276 MethodFlags flags = (MethodFlags) reader.ReadByte();
\r
278 // FIXME: find a meaning for those 3 bytes
\r
283 if (((BinaryTypeCode)reader.ReadByte()) != BinaryTypeCode.String) throw new SerializationException ("Invalid format");
\r
284 string methodName = reader.ReadString();
\r
286 if (((BinaryTypeCode)reader.ReadByte()) != BinaryTypeCode.String) throw new SerializationException ("Invalid format");
\r
287 string className = reader.ReadString();
\r
289 //bool hasContextInfo = (flags & MethodFlags.IncludesLogicalCallContext) > 0;
291 object[] arguments = null;
292 object methodSignature = null;
293 object callContext = null;
294 object[] extraProperties = null;
295 Header[] headers = null;
297 if ((flags & MethodFlags.PrimitiveArguments) > 0)
299 uint count = reader.ReadUInt32();
300 arguments = new object[count];
301 for (int n=0; n<count; n++)
303 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
304 arguments[n] = ObjectReader.ReadPrimitiveTypeValue (reader, type);
308 if ((flags & MethodFlags.NeedsInfoArrayMask) > 0)
\r
310 ObjectReader objectReader = new ObjectReader (formatter);
\r
313 objectReader.ReadObjectGraph (reader, hasHeaders, out result, out headers);
\r
314 object[] msgInfo = (object[]) result;
\r
316 if ((flags & MethodFlags.ArgumentsInSimpleArray) > 0) {
\r
317 arguments = msgInfo;
\r
322 if ((flags & MethodFlags.ArgumentsInMultiArray) > 0) {
\r
323 if (msgInfo.Length > 1) arguments = (object[]) msgInfo[n++];
\r
324 else arguments = new object[0];
\r
327 if ((flags & MethodFlags.IncludesSignature) > 0)
\r
328 methodSignature = msgInfo[n++];
\r
330 if ((flags & MethodFlags.IncludesLogicalCallContext) > 0)
\r
331 callContext = msgInfo[n++];
\r
333 if (n < msgInfo.Length)
\r
334 extraProperties = (object[]) msgInfo[n];
\r
338 reader.ReadByte (); // Reads the stream ender
\r
341 if (arguments == null) arguments = new object[0];
\r
344 if (headerHandler != null)
\r
345 uri = headerHandler(headers) as string;
\r
347 Header[] methodInfo = new Header[6];
\r
348 methodInfo[0] = new Header("__MethodName", methodName);
349 methodInfo[1] = new Header("__MethodSignature", methodSignature);
350 methodInfo[2] = new Header("__TypeName", className);
351 methodInfo[3] = new Header("__Args", arguments);
352 methodInfo[4] = new Header("__CallContext", callContext);
353 methodInfo[5] = new Header("__Uri", uri);
355 MethodCall call = new MethodCall (methodInfo);
357 if (extraProperties != null) {
358 foreach (DictionaryEntry entry in extraProperties)
359 call.Properties [(string)entry.Key] = entry.Value;
365 public static object ReadMethodResponse (BinaryReader reader, bool hasHeaders, HeaderHandler headerHandler, IMethodCallMessage methodCallMessage, BinaryFormatter formatter)
\r
367 BinaryElement elem = (BinaryElement)reader.ReadByte(); // The element code
\r
368 if (elem != BinaryElement.MethodResponse) throw new SerializationException("Invalid format. Expected BinaryElement.MethodResponse, found " + elem);
\r
370 MethodFlags flags = (MethodFlags) reader.ReadByte ();
\r
371 ReturnTypeTag typeTag = (ReturnTypeTag) reader.ReadByte ();
\r
372 bool hasContextInfo = (flags & MethodFlags.IncludesLogicalCallContext) > 0;
374 // FIXME: find a meaning for those 2 bytes
\r
378 object returnValue = null;
\r
379 object[] outArgs = null;
\r
380 LogicalCallContext callContext = null;
\r
381 Exception exception = null;
\r
382 object[] extraProperties = null;
383 Header[] headers = null;
385 if ((typeTag & ReturnTypeTag.PrimitiveType) > 0)
387 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
388 returnValue = ObjectReader.ReadPrimitiveTypeValue (reader, type);
\r
391 if ((flags & MethodFlags.PrimitiveArguments) > 0)
393 uint count = reader.ReadUInt32();
394 outArgs = new object[count];
395 for (int n=0; n<count; n++) {
396 Type type = BinaryCommon.GetTypeFromCode (reader.ReadByte());
397 outArgs[n] = ObjectReader.ReadPrimitiveTypeValue (reader, type);
401 if (hasContextInfo || (typeTag & ReturnTypeTag.ObjectType) > 0 ||
\r
402 (typeTag & ReturnTypeTag.Exception) > 0 ||
\r
403 (flags & MethodFlags.ArgumentsInSimpleArray) > 0 ||
\r
404 (flags & MethodFlags.ArgumentsInMultiArray) > 0)
\r
406 // There objects that need to be deserialized using an ObjectReader
\r
408 ObjectReader objectReader = new ObjectReader (formatter);
\r
410 objectReader.ReadObjectGraph (reader, hasHeaders, out result, out headers);
\r
411 object[] msgInfo = (object[]) result;
\r
413 if ((typeTag & ReturnTypeTag.Exception) > 0) {
\r
414 exception = (Exception) msgInfo[0];
\r
416 else if ((flags & MethodFlags.NoArguments) > 0 || (flags & MethodFlags.PrimitiveArguments) > 0) {
\r
418 if ((typeTag & ReturnTypeTag.ObjectType) > 0) returnValue = msgInfo [n++];
\r
419 if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n++];
\r
420 if (n < msgInfo.Length) extraProperties = (object[]) msgInfo[n];
\r
422 else if ((flags & MethodFlags.ArgumentsInSimpleArray) > 0) {
\r
427 outArgs = (object[]) msgInfo[n++];
\r
428 if ((typeTag & ReturnTypeTag.ObjectType) > 0) returnValue = msgInfo[n++];
\r
429 if (hasContextInfo) callContext = (LogicalCallContext)msgInfo[n++];
\r
430 if (n < msgInfo.Length) extraProperties = (object[]) msgInfo[n];
\r
434 reader.ReadByte (); // Reads the stream ender
\r
437 if (headerHandler != null)
\r
438 headerHandler(headers);
\r
440 if (exception != null)
\r
441 return new ReturnMessage (exception, methodCallMessage);
\r
444 int argCount = (outArgs!=null) ? outArgs.Length : 0;
\r
445 ReturnMessage result = new ReturnMessage (returnValue, outArgs, argCount, callContext, methodCallMessage);
\r
447 if (extraProperties != null) {
448 foreach (DictionaryEntry entry in extraProperties)
449 result.Properties [(string)entry.Key] = entry.Value;
456 private static bool AllTypesArePrimitive(object[] objects)
\r
458 foreach (object ob in objects)
\r
460 if (ob != null && !IsMethodPrimitive(ob.GetType()))
\r
466 // When serializing methods, string are considered primitive types
\r
467 public static bool IsMethodPrimitive (Type type)
\r
469 return type.IsPrimitive || type == typeof(string) || type == typeof (DateTime) || type == typeof (Decimal);
\r
472 static object[] GetExtraProperties (IDictionary properties, string[] internalKeys)
\r
474 object[] extraProperties = new object [properties.Count - internalKeys.Length];
\r
477 IDictionaryEnumerator e = properties.GetEnumerator();
\r
478 while (e.MoveNext())
\r
479 if (!IsInternalKey ((string) e.Entry.Key, internalKeys)) extraProperties [n++] = e.Entry;
\r
481 return extraProperties;
\r
484 static bool IsInternalKey (string key, string[] internalKeys)
\r
486 foreach (string ikey in internalKeys)
\r
487 if (key == ikey) return true;
\r