2 // DataContractSerializerMessageContractImporter.cs
4 // Author: Atsushi Enomoto (atsushi@ximian.com)
5 // Ankit Jain (jankit@novell.com)
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.Runtime.Serialization;
33 using System.ServiceModel;
34 using System.ServiceModel.Channels;
35 using System.ServiceModel.Dispatcher;
37 using System.Web.Services.Description;
39 using System.Xml.Schema;
40 using System.Xml.Serialization;
42 using QName = System.Xml.XmlQualifiedName;
43 using WSDL = System.Web.Services.Description.ServiceDescription;
44 using Message = System.Web.Services.Description.Message;
46 namespace System.ServiceModel.Description
48 public class DataContractSerializerMessageContractImporter
49 : IWsdlImportExtension
51 MessageContractImporterInternal impl = new DataContractMessageContractImporterInternal ();
55 get { return enabled; }
56 set { enabled = value; }
59 void IWsdlImportExtension.BeforeImport (
60 ServiceDescriptionCollection wsdlDocuments,
61 XmlSchemaSet xmlSchemas,
62 ICollection<XmlElement> policy)
67 impl.BeforeImport (wsdlDocuments, xmlSchemas, policy);
70 void IWsdlImportExtension.ImportContract (WsdlImporter importer,
71 WsdlContractConversionContext context)
76 impl.ImportContract (importer, context);
79 void IWsdlImportExtension.ImportEndpoint (WsdlImporter importer,
80 WsdlEndpointConversionContext context)
85 impl.ImportEndpoint (importer, context);
89 abstract class MessageContractImporterInternal : IWsdlImportExtension
91 public void ImportContract (WsdlImporter importer,
92 WsdlContractConversionContext context)
95 throw new ArgumentNullException ("importer");
97 throw new ArgumentNullException ("context");
98 if (this.importer != null || this.context != null)
99 throw new SystemException ("INTERNAL ERROR: unexpected recursion of ImportContract method call");
101 schema_set_in_use = new XmlSchemaSet ();
102 schema_set_in_use.Add (importer.XmlSchemas);
103 foreach (WSDL wsdl in importer.WsdlDocuments)
104 foreach (XmlSchema xs in wsdl.Types.Schemas)
105 schema_set_in_use.Add (xs);
107 schema_set_in_use.Compile ();
109 this.importer = importer;
110 this.context = context;
114 this.importer = null;
119 internal WsdlImporter importer;
120 WsdlContractConversionContext context;
122 internal XmlSchemaSet schema_set_in_use;
124 public void BeforeImport (
125 ServiceDescriptionCollection wsdlDocuments,
126 XmlSchemaSet xmlSchemas,
127 ICollection<XmlElement> policy)
131 void DoImportContract ()
133 PortType port_type = context.WsdlPortType;
134 ContractDescription contract = context.Contract;
136 List<MessagePartDescription> parts = new List<MessagePartDescription> ();
139 foreach (Operation op in port_type.Operations) {
140 OperationDescription opdescr = contract.Operations [i];
141 if (IsOperationImported (port_type, op))
143 if (!CanImportOperation (port_type, op))
147 foreach (OperationMessage opmsg in op.Messages) {
148 //SM.MessageDescription
149 MessageDescription msgdescr = opdescr.Messages [j];
151 //OpMsg's corresponding WSMessage
152 Message msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
154 msgdescr.Body.WrapperNamespace = port_type.ServiceDescription.TargetNamespace;
156 if (opmsg is OperationOutput) {
158 msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
160 resolveMessage (msg, msgdescr.Body, parts);
161 if (parts.Count > 0) {
162 msgdescr.Body.ReturnValue = parts [0];
170 /* Parts, MessagePartDescription */
171 resolveMessage (msg, msgdescr.Body, parts);
172 foreach (MessagePartDescription p in parts)
173 msgdescr.Body.Parts.Add (p);
179 OnOperationImported (opdescr);
187 bool IsOperationImported (PortType pt, Operation op)
189 foreach (OperationMessage opmsg in op.Messages) {
190 var parts = context.GetMessageDescription (opmsg).Body.Parts;
191 foreach (var part in parts)
192 if (part.DataContractImporter != null || part.XmlSerializationImporter != null)
198 void resolveMessage (Message msg, MessageBodyDescription body, List<MessagePartDescription> parts)
200 foreach (MessagePart part in msg.Parts) {
201 if (part.Name == "parameters") {
202 if (!part.Element.IsEmpty) {
203 body.WrapperName = part.Element.Name;
204 ImportPartsBySchemaElement (part.Element, parts, msg, part);
206 body.WrapperName = part.Type.Name;
207 ResolveType (part.Type, parts, body.WrapperNamespace);
211 throw new InvalidOperationException ("Only 'parameters' element in message part is supported"); // this should have been rejected by CanImportOperation().
215 public void ImportEndpoint (WsdlImporter importer,
216 WsdlEndpointConversionContext context)
220 protected abstract void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart part);
222 protected abstract void ResolveType (QName qname, List<MessagePartDescription> parts, string ns);
224 protected abstract bool CanImportOperation (PortType portType, Operation op);
226 protected abstract void OnOperationImported (OperationDescription od);
229 class DataContractMessageContractImporterInternal : MessageContractImporterInternal
231 XsdDataContractImporter dc_importer = new XsdDataContractImporter ();
233 protected override void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart part)
235 XmlSchemaElement element = (XmlSchemaElement) schema_set_in_use.GlobalElements [qname];
237 throw new InvalidOperationException ("Could not resolve : " + qname.ToString ()); // this should have been rejected by CanImportOperation().
239 var ct = element.ElementSchemaType as XmlSchemaComplexType;
240 if (ct == null) // simple type
241 parts.Add (CreateMessagePart (element, msg, part));
243 foreach (var elem in GetElementsInParticle (ct.ContentTypeParticle))
244 parts.Add (CreateMessagePart (elem, msg, part));
247 IEnumerable<XmlSchemaElement> GetElementsInParticle (XmlSchemaParticle p)
249 if (p is XmlSchemaElement) {
250 yield return (XmlSchemaElement) p;
252 var gb = p as XmlSchemaGroupBase;
254 foreach (XmlSchemaParticle pp in gb.Items)
255 foreach (var e in GetElementsInParticle (pp))
260 MessagePartDescription CreateMessagePart (XmlSchemaElement elem, Message msg, MessagePart msgPart)
262 var part = new MessagePartDescription (elem.QualifiedName.Name, elem.QualifiedName.Namespace);
263 part.DataContractImporter = dc_importer;
264 if (dc_importer.CanImport (schema_set_in_use, elem)) {
265 var typeQName = dc_importer.Import (schema_set_in_use, elem);
266 part.CodeTypeReference = dc_importer.GetCodeTypeReference (elem.ElementSchemaType.QualifiedName, elem);
271 protected override void ResolveType (QName qname, List<MessagePartDescription> parts, string ns)
273 /*foreach (XmlSchema xs in importer.Schemas)
274 if (xs.Types [qname] != null)
275 return resolveParameters ((XmlSchemaElement) xs.Types [qname]., msgdescr, importer);
277 //FIXME: What to do here?
278 throw new Exception ("Could not resolve : " + qname.ToString ());*/
279 throw new NotImplementedException ();
282 Message FindMessage (OperationMessage om)
284 foreach (WSDL sd in importer.WsdlDocuments)
285 if (sd.TargetNamespace == om.Message.Namespace)
286 foreach (Message msg in sd.Messages)
287 if (msg.Name == om.Message.Name)
292 protected override bool CanImportOperation (PortType portType, Operation op)
294 foreach (OperationMessage om in op.Messages) {
295 var msg = FindMessage (om);
298 foreach (MessagePart part in msg.Parts) {
299 if (part.Name == "parameters" && !part.Element.IsEmpty) {
300 var xe = schema_set_in_use.GlobalElements [part.Element] as XmlSchemaElement;
301 if (xe == null || !dc_importer.CanImport (schema_set_in_use, xe))
311 protected override void OnOperationImported (OperationDescription od)
317 class XmlSerializerMessageContractImporterInternal : MessageContractImporterInternal
319 CodeCompileUnit ccu = new CodeCompileUnit ();
320 XmlSchemaSet schema_set_cache;
321 XmlSchemaImporter schema_importer;
322 XmlCodeExporter code_exporter;
324 public CodeCompileUnit CodeCompileUnit {
328 protected override void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart msgPart)
330 if (schema_set_cache != schema_set_in_use) {
331 schema_set_cache = schema_set_in_use;
332 var xss = new XmlSchemas ();
333 foreach (XmlSchema xs in schema_set_cache.Schemas ())
335 schema_importer = new XmlSchemaImporter (xss);
336 if (ccu.Namespaces.Count == 0)
337 ccu.Namespaces.Add (new CodeNamespace ());
338 var cns = ccu.Namespaces [0];
339 code_exporter = new XmlCodeExporter (cns, ccu);
342 var part = new MessagePartDescription (qname.Name, qname.Namespace);
343 part.XmlSerializationImporter = this;
344 var mbrNS = msg.ServiceDescription.TargetNamespace;
345 var xmm = schema_importer.ImportMembersMapping (qname);
346 code_exporter.ExportMembersMapping (xmm);
347 // FIXME: use of ElementName is a hack!
348 part.CodeTypeReference = new CodeTypeReference (xmm.ElementName);
352 protected override void ResolveType (QName qname, List<MessagePartDescription> parts, string ns)
354 throw new NotImplementedException ();
357 protected override bool CanImportOperation (PortType portType, Operation op)
363 protected override void OnOperationImported (OperationDescription od)
365 od.Behaviors.Add (new XmlSerializerMappingBehavior ());
369 // just a marker behavior
370 class XmlSerializerMappingBehavior : IOperationBehavior
372 public void AddBindingParameters (OperationDescription operationDescription, BindingParameterCollection bindingParameters)
376 public void ApplyClientBehavior (OperationDescription operationDescription, ClientOperation clientOperation)
380 public void ApplyDispatchBehavior (OperationDescription operationDescription, DispatchOperation dispatchOperation)
384 public void Validate (OperationDescription operationDescription)