2 // System.Web.Services.Description.ProtocolReflector.cs
5 // Tim Coleman (tim@timcoleman.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
8 // Copyright (C) Tim Coleman, 2002
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.
32 using System.Web.Services;
33 using System.Web.Services.Protocols;
34 using System.Xml.Serialization;
36 using System.Xml.Schema;
37 using System.Collections;
39 namespace System.Web.Services.Description {
40 public abstract class ProtocolReflector {
45 string defaultNamespace;
46 MessageCollection headerMessages;
48 LogicalMethodInfo[] methods;
50 OperationBinding operationBinding;
51 Message outputMessage;
55 XmlSchemaExporter schemaExporter;
57 ServiceDescription serviceDescription;
60 SoapSchemaExporter soapSchemaExporter;
61 MethodStubInfo methodStubInfo;
62 TypeStubInfo typeInfo;
63 ArrayList extensionReflectors;
64 ServiceDescriptionReflector serviceReflector;
66 XmlReflectionImporter reflectionImporter;
67 SoapReflectionImporter soapReflectionImporter;
69 CodeIdentifiers portNames;
75 protected ProtocolReflector ()
77 defaultNamespace = WebServiceAttribute.DefaultNamespace;
78 extensionReflectors = ExtensionManager.BuildExtensionReflectors ();
81 #endregion // Constructors
85 internal ServiceDescriptionReflector Parent {
86 get { return serviceReflector; }
89 public Binding Binding {
90 get { return binding; }
93 public string DefaultNamespace {
94 get { return defaultNamespace; }
97 public MessageCollection HeaderMessages {
98 get { return headerMessages; } // TODO: set
101 public Message InputMessage {
102 get { return inputMessage; }
105 public LogicalMethodInfo Method {
106 get { return methodStubInfo.MethodInfo; }
109 public WebMethodAttribute MethodAttribute {
110 get { return methodStubInfo.MethodAttribute; }
113 public LogicalMethodInfo[] Methods {
114 get { return typeInfo.LogicalType.LogicalMethods; }
117 public Operation Operation {
118 get { return operation; }
121 public OperationBinding OperationBinding {
122 get { return operationBinding; }
125 public Message OutputMessage {
126 get { return outputMessage; }
133 public PortType PortType {
134 get { return portType; }
137 public abstract string ProtocolName {
141 public XmlReflectionImporter ReflectionImporter
145 if (reflectionImporter == null) {
146 reflectionImporter = typeInfo.XmlImporter;
147 if (reflectionImporter == null)
148 reflectionImporter = new XmlReflectionImporter();
150 return reflectionImporter;
154 internal SoapReflectionImporter SoapReflectionImporter
158 if (soapReflectionImporter == null) {
159 soapReflectionImporter = typeInfo.SoapImporter;
160 if (soapReflectionImporter == null)
161 soapReflectionImporter = new SoapReflectionImporter();
163 return soapReflectionImporter;
167 public XmlSchemaExporter SchemaExporter {
168 get { return schemaExporter; }
171 internal SoapSchemaExporter SoapSchemaExporter {
172 get { return soapSchemaExporter; }
175 public XmlSchemas Schemas {
176 get { return serviceReflector.Schemas; }
179 public Service Service {
180 get { return service; }
183 public ServiceDescription ServiceDescription {
184 get { return serviceDescription; }
187 public ServiceDescriptionCollection ServiceDescriptions {
188 get { return serviceReflector.ServiceDescriptions; }
191 public Type ServiceType {
192 get { return serviceType; }
195 public string ServiceUrl {
196 get { return serviceUrl; }
199 internal MethodStubInfo MethodStubInfo {
200 get { return methodStubInfo; }
203 internal TypeStubInfo TypeInfo {
204 get { return typeInfo; }
207 #endregion // Properties
211 internal void Reflect (ServiceDescriptionReflector serviceReflector, Type type, string url, XmlSchemaExporter xxporter, SoapSchemaExporter sxporter)
213 portNames = new CodeIdentifiers ();
214 this.serviceReflector = serviceReflector;
218 schemaExporter = xxporter;
219 soapSchemaExporter = sxporter;
221 typeInfo = TypeStubManager.GetTypeStub (type, ProtocolName);
223 ServiceDescription desc = ServiceDescriptions [typeInfo.LogicalType.WebServiceNamespace];
227 desc = new ServiceDescription ();
228 desc.TargetNamespace = typeInfo.LogicalType.WebServiceNamespace;
229 desc.Name = typeInfo.LogicalType.WebServiceName;
230 ServiceDescriptions.Add (desc);
233 ImportService (desc, typeInfo, url);
236 void ImportService (ServiceDescription desc, TypeStubInfo typeInfo, string url)
238 service = desc.Services [typeInfo.LogicalType.WebServiceName];
241 service = new Service ();
242 service.Name = typeInfo.LogicalType.WebServiceName;
243 service.Documentation = typeInfo.LogicalType.Description;
244 desc.Services.Add (service);
247 foreach (BindingInfo binfo in typeInfo.Bindings)
248 ImportBinding (desc, service, typeInfo, url, binfo);
251 void ImportBinding (ServiceDescription desc, Service service, TypeStubInfo typeInfo, string url, BindingInfo binfo)
254 port.Name = portNames.AddUnique (binfo.Name, port);
255 bool bindingFull = true;
257 if (binfo.Namespace != desc.TargetNamespace)
259 if (binfo.Location == null || binfo.Location == string.Empty)
261 ServiceDescription newDesc = new ServiceDescription();
262 newDesc.TargetNamespace = binfo.Namespace;
263 newDesc.Name = binfo.Name;
264 bindingFull = ImportBindingContent (newDesc, typeInfo, url, binfo);
266 int id = ServiceDescriptions.Add (newDesc);
267 AddImport (desc, binfo.Namespace, GetWsdlUrl (url,id));
271 AddImport (desc, binfo.Namespace, binfo.Location);
276 bindingFull = ImportBindingContent (desc, typeInfo, url, binfo);
280 port.Binding = new XmlQualifiedName (binding.Name, binfo.Namespace);
283 string name = binfo.Name;
288 foreach (Port p in service.Ports)
289 if (p.Name == name) { found = true; n++; name = binfo.Name + n; break; }
293 service.Ports.Add (port);
296 if (binfo.WebServiceBindingAttribute != null && binfo.WebServiceBindingAttribute.ConformsTo != WsiProfiles.None && String.IsNullOrEmpty (binfo.WebServiceBindingAttribute.Name)) {
297 BasicProfileViolationCollection violations = new BasicProfileViolationCollection ();
298 desc.Types.Schemas.Add (Schemas);
299 ServiceDescriptionCollection col = new ServiceDescriptionCollection ();
301 ConformanceCheckContext ctx = new ConformanceCheckContext (col, violations);
302 ctx.ServiceDescription = desc;
303 ConformanceChecker[] checkers = WebServicesInteroperability.GetCheckers (binfo.WebServiceBindingAttribute.ConformsTo);
304 foreach (ConformanceChecker checker in checkers) {
305 ctx.Checker = checker;
306 WebServicesInteroperability.Check (ctx, checker, binding);
307 if (violations.Count > 0)
308 throw new InvalidOperationException (violations [0].ToString ());
313 bool ImportBindingContent (ServiceDescription desc, TypeStubInfo typeInfo, string url, BindingInfo binfo)
315 serviceDescription = desc;
317 // Look for an unused name
320 string name = binfo.Name;
325 foreach (Binding bi in desc.Bindings)
326 if (bi.Name == name) { found = true; n++; name = binfo.Name+n; break; }
330 // Create the binding
332 binding = new Binding ();
334 binding.Type = new XmlQualifiedName (binding.Name, binfo.Namespace);
335 if (binfo.WebServiceBindingAttribute != null && binfo.WebServiceBindingAttribute.EmitConformanceClaims) {
336 XmlDocument doc = new XmlDocument ();
337 XmlElement docElement = doc.CreateElement ("wsdl", "documentation", "http://schemas.xmlsoap.org/wsdl/");
338 XmlElement claimsElement = doc.CreateElement ("wsi", "Claim", "http://ws-i.org/schemas/conformanceClaim/");
339 claimsElement.Attributes.Append (doc.CreateAttribute ("conformsTo")).Value = "http://ws-i.org/profiles/basic/1.1";
340 docElement.AppendChild (claimsElement);
341 binding.DocumentationElement = docElement;
344 portType = new PortType ();
345 portType.Name = binding.Name;
349 foreach (SoapExtensionReflector reflector in extensionReflectors)
351 reflector.ReflectionContext = this;
352 reflector.ReflectDescription ();
355 foreach (MethodStubInfo method in typeInfo.Methods)
357 methodStubInfo = method;
359 string metBinding = ReflectMethodBinding ();
360 if (typeInfo.GetBinding (metBinding) != binfo) continue;
362 operation = new Operation ();
363 operation.Name = method.OperationName;
364 operation.Documentation = method.MethodAttribute.Description;
366 // FIXME: SOAP 1.1 and SOAP 1.2 should share
367 // the same message definitions.
369 inputMessage = new Message ();
370 inputMessage.Name = method.Name + ProtocolName + "In";
371 ServiceDescription.Messages.Add (inputMessage);
373 outputMessage = new Message ();
374 outputMessage.Name = method.Name + ProtocolName + "Out";
375 ServiceDescription.Messages.Add (outputMessage);
377 OperationInput inOp = new OperationInput ();
378 if (method.Name != method.OperationName) inOp.Name = method.Name;
379 Operation.Messages.Add (inOp);
380 inOp.Message = new XmlQualifiedName (inputMessage.Name, ServiceDescription.TargetNamespace);
382 OperationOutput outOp = new OperationOutput ();
383 if (method.Name != method.OperationName) outOp.Name = method.Name;
384 Operation.Messages.Add (outOp);
385 outOp.Message = new XmlQualifiedName (outputMessage.Name, ServiceDescription.TargetNamespace);
387 portType.Operations.Add (operation);
388 ImportOperationBinding ();
390 if (!ReflectMethod ()) {
391 // (It is somewhat hacky) If we don't
392 // add input/output Messages, update
393 // portType/input/@message and
394 // porttype/output/@message.
395 Message dupIn = Parent.MappedMessagesIn [method.MethodInfo];
396 ServiceDescription.Messages.Remove (inputMessage);
397 inOp.Message = new XmlQualifiedName (dupIn.Name, ServiceDescription.TargetNamespace);
398 Message dupOut = Parent.MappedMessagesOut [method.MethodInfo];
399 ServiceDescription.Messages.Remove (outputMessage);
400 outOp.Message = new XmlQualifiedName (dupOut.Name, ServiceDescription.TargetNamespace);
403 foreach (SoapExtensionReflector reflector in extensionReflectors)
405 reflector.ReflectionContext = this;
406 reflector.ReflectMethod ();
412 if (portType.Operations.Count > 0)
414 desc.Bindings.Add (binding);
415 desc.PortTypes.Add (portType);
422 void ImportOperationBinding ()
424 operationBinding = new OperationBinding ();
425 operationBinding.Name = methodStubInfo.OperationName;
427 InputBinding inOp = new InputBinding ();
428 operationBinding.Input = inOp;
430 OutputBinding outOp = new OutputBinding ();
431 operationBinding.Output = outOp;
433 if (methodStubInfo.OperationName != methodStubInfo.Name)
434 inOp.Name = outOp.Name = methodStubInfo.Name;
436 binding.Operations.Add (operationBinding);
439 internal static void AddImport (ServiceDescription desc, string ns, string location)
441 Import im = new Import();
443 im.Location = location;
444 desc.Imports.Add (im);
447 string GetWsdlUrl (string baseUrl, int id)
449 return baseUrl + "?wsdl=" + id;
452 protected virtual void BeginClass ()
456 protected virtual void EndClass ()
460 public ServiceDescription GetServiceDescription (string ns)
462 return ServiceDescriptions [ns];
465 protected abstract bool ReflectMethod ();
467 protected virtual string ReflectMethodBinding ()
472 [MonoNotSupported("Not Implemented")]
473 protected virtual void ReflectDescription ()
475 throw new NotImplementedException ();