2 // DefaultMessageOperationFormatter.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
6 // Eyal Alaluf <eyala@mainsoft.com>
8 // Copyright (C) 2005-2007 Novell, Inc. http://www.novell.com
9 // Copyright (C) 2008 Mainsoft Co. http://www.mainsoft.com
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections.Generic;
32 using System.Reflection;
33 using System.Runtime.Serialization;
34 using System.ServiceModel;
35 using System.ServiceModel.Channels;
36 using System.ServiceModel.Description;
39 using System.Xml.Serialization;
41 namespace System.ServiceModel.Dispatcher
43 internal abstract class BaseMessagesFormatter
44 : IDispatchMessageFormatter, IClientMessageFormatter
46 MessageDescriptionCollection messages;
48 ParameterInfo [] requestMethodParams;
49 ParameterInfo [] replyMethodParams;
51 public BaseMessagesFormatter (MessageDescriptionCollection messages)
53 this.messages = messages;
56 public BaseMessagesFormatter (OperationDescription desc)
57 : this (desc.Messages)
59 if (desc.SyncMethod != null)
62 requestMethodParams = replyMethodParams = desc.SyncMethod.GetParameters ();
66 ParameterInfo [] methodParams = desc.BeginMethod.GetParameters ();
67 requestMethodParams = new ParameterInfo [methodParams.Length - 2];
68 Array.Copy (methodParams, requestMethodParams, requestMethodParams.Length);
69 methodParams = desc.EndMethod.GetParameters ();
70 replyMethodParams = new ParameterInfo [methodParams.Length - 1];
71 Array.Copy (methodParams, replyMethodParams, replyMethodParams.Length);
74 public static BaseMessagesFormatter Create (OperationDescription desc)
76 MethodInfo attrProvider = desc.SyncMethod ?? desc.BeginMethod;
79 attrs = attrProvider.GetCustomAttributes (typeof (XmlSerializerFormatAttribute), false);
80 if (attrs != null && attrs.Length > 0)
81 return new XmlMessagesFormatter (desc, (XmlSerializerFormatAttribute) attrs [0]);
84 attrs = attrProvider.GetCustomAttributes (typeof (DataContractFormatAttribute), false);
85 DataContractFormatAttribute dataAttr = null;
86 if (attrs != null && attrs.Length > 0)
87 dataAttr = (DataContractFormatAttribute) attrs [0];
88 return new DataContractMessagesFormatter (desc, dataAttr);
91 protected abstract Message PartsToMessage (
92 MessageDescription md, MessageVersion version, string action, object [] parts);
93 protected abstract object [] MessageToParts (MessageDescription md, Message message);
95 public Message SerializeRequest (
96 MessageVersion version, object [] parameters)
98 MessageDescription md = null;
99 foreach (MessageDescription mdi in messages)
100 if (mdi.Direction == MessageDirection.Input)
103 object [] parts = CreatePartsArray (md.Body);
104 if (md.MessageType != null)
105 MessageObjectToParts (md, parameters [0], parts);
108 foreach (ParameterInfo pi in requestMethodParams)
110 parts [index++] = parameters [pi.Position];
112 return PartsToMessage (md, version, md.Action, parts);
115 public Message SerializeReply (
116 MessageVersion version, object [] parameters, object result)
118 // use_response_converter
120 MessageDescription md = null;
121 foreach (MessageDescription mdi in messages)
122 if (mdi.Direction == MessageDirection.Output)
125 object [] parts = CreatePartsArray (md.Body);
126 if (md.MessageType != null)
127 MessageObjectToParts (md, result, parts);
129 if (HasReturnValue (md.Body))
131 int index = ParamsOffset (md.Body);
132 foreach (ParameterInfo pi in replyMethodParams)
133 if (pi.IsOut || pi.ParameterType.IsByRef)
134 parts [index++] = parameters [pi.Position];
136 string action = version.Addressing == AddressingVersion.None ? null : md.Action;
137 return PartsToMessage (md, version, action, parts);
140 public void DeserializeRequest (Message message, object [] parameters)
142 string action = message.Headers.Action;
143 MessageDescription md = messages.Find (action);
145 throw new ActionNotSupportedException (String.Format ("Action '{0}' is not supported by this operation.", action));
147 object [] parts = MessageToParts (md, message);
148 if (md.MessageType != null) {
149 parameters [0] = Activator.CreateInstance (md.MessageType, true);
150 PartsToMessageObject (md, parts, parameters [0]);
155 foreach (ParameterInfo pi in requestMethodParams)
157 parameters [pi.Position] = parts [index++];
161 public object DeserializeReply (Message message, object [] parameters)
163 MessageDescription md = null;
164 foreach (MessageDescription mdi in messages)
165 if (mdi.Direction == MessageDirection.Output)
168 object [] parts = MessageToParts (md, message);
169 if (md.MessageType != null) {
170 object msgObject = Activator.CreateInstance (md.MessageType, true);
171 PartsToMessageObject (md, parts, msgObject);
175 int index = ParamsOffset (md.Body);
176 foreach (ParameterInfo pi in requestMethodParams)
177 if (pi.IsOut || pi.ParameterType.IsByRef)
178 parameters [pi.Position] = parts [index++];
179 return HasReturnValue (md.Body) ? parts [0] : null;
183 void PartsToMessageObject (MessageDescription md, object [] parts, object msgObject)
185 foreach (MessagePartDescription partDesc in md.Body.Parts)
186 if (partDesc.MemberInfo is FieldInfo)
187 ((FieldInfo) partDesc.MemberInfo).SetValue (msgObject, parts [partDesc.Index]);
189 ((PropertyInfo) partDesc.MemberInfo).SetValue (msgObject, parts [partDesc.Index], null);
192 void MessageObjectToParts (MessageDescription md, object msgObject, object [] parts)
194 foreach (MessagePartDescription partDesc in md.Body.Parts)
195 if (partDesc.MemberInfo is FieldInfo)
196 parts [partDesc.Index] = ((FieldInfo) partDesc.MemberInfo).GetValue (msgObject);
198 parts [partDesc.Index] = ((PropertyInfo) partDesc.MemberInfo).GetValue (msgObject, null);
201 internal static bool HasReturnValue (MessageBodyDescription desc)
203 return desc.ReturnValue != null && desc.ReturnValue.Type != typeof (void);
206 protected static int ParamsOffset (MessageBodyDescription desc)
208 return HasReturnValue (desc) ? 1 : 0;
211 protected static object [] CreatePartsArray (MessageBodyDescription desc)
213 if (HasReturnValue (desc))
214 return new object [desc.Parts.Count + 1];
215 return new object [desc.Parts.Count];
220 class XmlMessagesFormatter : BaseMessagesFormatter
222 XmlSerializerFormatAttribute attr;
223 Dictionary<MessageBodyDescription,XmlSerializer> bodySerializers
224 = new Dictionary<MessageBodyDescription,XmlSerializer> ();
226 public XmlMessagesFormatter (OperationDescription desc, XmlSerializerFormatAttribute attr)
232 public XmlMessagesFormatter (MessageDescriptionCollection messages, XmlSerializerFormatAttribute attr)
238 private XmlReflectionMember CreateReflectionMember (MessagePartDescription partDesc, bool isReturnValue)
240 XmlReflectionMember m = new XmlReflectionMember ();
241 m.IsReturnValue = isReturnValue;
242 m.MemberName = partDesc.Name;
243 m.MemberType = partDesc.Type;
247 protected override Message PartsToMessage (
248 MessageDescription md, MessageVersion version, string action, object [] parts)
250 return Message.CreateMessage (version, action, new XmlBodyWriter (GetSerializer (md.Body), parts));
253 protected override object [] MessageToParts (MessageDescription md, Message message)
258 XmlDictionaryReader r = message.GetReaderAtBodyContents ();
259 return (object []) GetSerializer (md.Body).Deserialize (r);
262 // FIXME: Handle ServiceKnownTypes
263 XmlSerializer GetSerializer (MessageBodyDescription desc)
265 if (bodySerializers.ContainsKey (desc))
266 return bodySerializers [desc];
268 int count = desc.Parts.Count + (HasReturnValue (desc) ? 1 : 0);
269 XmlReflectionMember [] members = new XmlReflectionMember [count];
272 if (HasReturnValue (desc))
273 members [ind++] = CreateReflectionMember (desc.ReturnValue, true);
275 foreach (MessagePartDescription partDesc in desc.Parts)
276 members [ind++] = CreateReflectionMember (partDesc, false);
278 // FIXME: Register known types into xmlImporter.
279 XmlReflectionImporter xmlImporter = new XmlReflectionImporter ();
280 XmlMembersMapping [] partsMapping = new XmlMembersMapping [1];
281 partsMapping [0] = xmlImporter.ImportMembersMapping (desc.WrapperName, desc.WrapperNamespace, members, true);
282 bodySerializers [desc] = XmlSerializer.FromMappings (partsMapping) [0];
283 return bodySerializers [desc];
286 class XmlBodyWriter : BodyWriter
288 XmlSerializer serializer;
291 public XmlBodyWriter (XmlSerializer serializer, object parts)
294 this.serializer = serializer;
299 protected override BodyWriter OnCreateBufferedCopy (int maxBufferSize)
301 throw new NotSupportedException ();
304 protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
306 serializer.Serialize (writer, body);
312 class DataContractMessagesFormatter : BaseMessagesFormatter
314 DataContractFormatAttribute attr;
316 public DataContractMessagesFormatter (OperationDescription desc, DataContractFormatAttribute attr)
322 public DataContractMessagesFormatter (MessageDescriptionCollection messages, DataContractFormatAttribute attr)
328 Dictionary<MessagePartDescription, XmlObjectSerializer> serializers
329 = new Dictionary<MessagePartDescription,XmlObjectSerializer> ();
331 protected override Message PartsToMessage (
332 MessageDescription md, MessageVersion version, string action, object [] parts)
334 return Message.CreateMessage (version, action, new DataContractBodyWriter (md.Body, this, parts));
337 protected override object [] MessageToParts (
338 MessageDescription md, Message message)
343 int offset = ParamsOffset (md.Body);
344 object [] parts = CreatePartsArray (md.Body);
346 XmlDictionaryReader r = message.GetReaderAtBodyContents ();
347 if (md.Body.WrapperName != null)
348 r.ReadStartElement (md.Body.WrapperName, md.Body.WrapperNamespace);
350 for (r.MoveToContent (); r.NodeType == XmlNodeType.Element; r.MoveToContent ()) {
351 XmlQualifiedName key = new XmlQualifiedName (r.LocalName, r.NamespaceURI);
352 MessagePartDescription rv = md.Body.ReturnValue;
353 if (rv != null && rv.Name == key.Name && rv.Namespace == key.Namespace)
354 parts [0] = GetSerializer (md.Body.ReturnValue).ReadObject (r);
355 else if (md.Body.Parts.Contains (key)) {
356 MessagePartDescription p = md.Body.Parts [key];
357 parts [p.Index + offset] = GetSerializer (p).ReadObject (r);
359 else // Skip unknown elements
363 if (md.Body.WrapperName != null && !r.EOF)
369 // FIXME: Handle ServiceKnownTypes
370 XmlObjectSerializer GetSerializer (MessagePartDescription partDesc)
372 if (!serializers.ContainsKey (partDesc))
373 serializers [partDesc] = new DataContractSerializer (
374 partDesc.Type, partDesc.Name, partDesc.Namespace);
375 return serializers [partDesc];
378 class DataContractBodyWriter : BodyWriter
380 MessageBodyDescription desc;
382 DataContractMessagesFormatter parent;
384 public DataContractBodyWriter (MessageBodyDescription desc, DataContractMessagesFormatter parent, object [] parts)
388 this.parent = parent;
392 protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
394 int offset = HasReturnValue (desc) ? 1 : 0;
395 if (desc.WrapperName != null)
396 writer.WriteStartElement (desc.WrapperName, desc.WrapperNamespace);
397 if (HasReturnValue (desc))
398 WriteMessagePart (writer, desc, desc.ReturnValue, parts [0]);
399 foreach (MessagePartDescription partDesc in desc.Parts)
400 WriteMessagePart (writer, desc, partDesc, parts [partDesc.Index + offset]);
401 if (desc.WrapperName != null)
402 writer.WriteEndElement ();
405 void WriteMessagePart (
406 XmlDictionaryWriter writer, MessageBodyDescription desc, MessagePartDescription partDesc, object obj)
408 parent.GetSerializer (partDesc).WriteObject (writer, obj);