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
);
297 if (binfo
.WebServiceBindingAttribute
!= null && binfo
.WebServiceBindingAttribute
.ConformsTo
!= WsiProfiles
.None
&& String
.IsNullOrEmpty (binfo
.WebServiceBindingAttribute
.Name
)) {
298 BasicProfileViolationCollection violations
= new BasicProfileViolationCollection ();
299 desc
.Types
.Schemas
.Add (Schemas
);
300 ServiceDescriptionCollection col
= new ServiceDescriptionCollection ();
302 ConformanceCheckContext ctx
= new ConformanceCheckContext (col
, violations
);
303 ctx
.ServiceDescription
= desc
;
304 ConformanceChecker
[] checkers
= WebServicesInteroperability
.GetCheckers (binfo
.WebServiceBindingAttribute
.ConformsTo
);
305 foreach (ConformanceChecker checker
in checkers
) {
306 ctx
.Checker
= checker
;
307 WebServicesInteroperability
.Check (ctx
, checker
, binding
);
308 if (violations
.Count
> 0)
309 throw new InvalidOperationException (violations
[0].ToString ());
315 bool ImportBindingContent (ServiceDescription desc
, TypeStubInfo typeInfo
, string url
, BindingInfo binfo
)
317 serviceDescription
= desc
;
319 // Look for an unused name
322 string name
= binfo
.Name
;
327 foreach (Binding bi
in desc
.Bindings
)
328 if (bi
.Name
== name
) { found = true; n++; name = binfo.Name+n; break; }
332 // Create the binding
334 binding
= new Binding ();
336 binding
.Type
= new XmlQualifiedName (binding
.Name
, binfo
.Namespace
);
338 if (binfo
.WebServiceBindingAttribute
!= null && binfo
.WebServiceBindingAttribute
.EmitConformanceClaims
) {
339 XmlDocument doc
= new XmlDocument ();
340 XmlElement docElement
= doc
.CreateElement ("wsdl", "documentation", "http://schemas.xmlsoap.org/wsdl/");
341 XmlElement claimsElement
= doc
.CreateElement ("wsi", "Claim", "http://ws-i.org/schemas/conformanceClaim/");
342 claimsElement
.Attributes
.Append (doc
.CreateAttribute ("conformsTo")).Value
= "http://ws-i.org/profiles/basic/1.1";
343 docElement
.AppendChild (claimsElement
);
344 binding
.DocumentationElement
= docElement
;
348 portType
= new PortType ();
349 portType
.Name
= binding
.Name
;
353 foreach (SoapExtensionReflector reflector
in extensionReflectors
)
355 reflector
.ReflectionContext
= this;
356 reflector
.ReflectDescription ();
359 foreach (MethodStubInfo method
in typeInfo
.Methods
)
361 methodStubInfo
= method
;
363 string metBinding
= ReflectMethodBinding ();
364 if (typeInfo
.GetBinding (metBinding
) != binfo
) continue;
366 operation
= new Operation ();
367 operation
.Name
= method
.OperationName
;
368 operation
.Documentation
= method
.MethodAttribute
.Description
;
370 // FIXME: SOAP 1.1 and SOAP 1.2 should share
371 // the same message definitions.
373 inputMessage
= new Message ();
374 inputMessage
.Name
= method
.Name
+ ProtocolName
+ "In";
375 ServiceDescription
.Messages
.Add (inputMessage
);
377 outputMessage
= new Message ();
378 outputMessage
.Name
= method
.Name
+ ProtocolName
+ "Out";
379 ServiceDescription
.Messages
.Add (outputMessage
);
381 OperationInput inOp
= new OperationInput ();
382 if (method
.Name
!= method
.OperationName
) inOp
.Name
= method
.Name
;
383 Operation
.Messages
.Add (inOp
);
384 inOp
.Message
= new XmlQualifiedName (inputMessage
.Name
, ServiceDescription
.TargetNamespace
);
386 OperationOutput outOp
= new OperationOutput ();
387 if (method
.Name
!= method
.OperationName
) outOp
.Name
= method
.Name
;
388 Operation
.Messages
.Add (outOp
);
389 outOp
.Message
= new XmlQualifiedName (outputMessage
.Name
, ServiceDescription
.TargetNamespace
);
391 portType
.Operations
.Add (operation
);
392 ImportOperationBinding ();
394 if (!ReflectMethod ()) {
396 // (It is somewhat hacky) If we don't
397 // add input/output Messages, update
398 // portType/input/@message and
399 // porttype/output/@message.
400 Message dupIn
= Parent
.MappedMessagesIn
[method
.MethodInfo
];
401 ServiceDescription
.Messages
.Remove (inputMessage
);
402 inOp
.Message
= new XmlQualifiedName (dupIn
.Name
, ServiceDescription
.TargetNamespace
);
403 Message dupOut
= Parent
.MappedMessagesOut
[method
.MethodInfo
];
404 ServiceDescription
.Messages
.Remove (outputMessage
);
405 outOp
.Message
= new XmlQualifiedName (dupOut
.Name
, ServiceDescription
.TargetNamespace
);
409 foreach (SoapExtensionReflector reflector
in extensionReflectors
)
411 reflector
.ReflectionContext
= this;
412 reflector
.ReflectMethod ();
418 if (portType
.Operations
.Count
> 0)
420 desc
.Bindings
.Add (binding
);
421 desc
.PortTypes
.Add (portType
);
428 void ImportOperationBinding ()
430 operationBinding
= new OperationBinding ();
431 operationBinding
.Name
= methodStubInfo
.OperationName
;
433 InputBinding inOp
= new InputBinding ();
434 operationBinding
.Input
= inOp
;
436 OutputBinding outOp
= new OutputBinding ();
437 operationBinding
.Output
= outOp
;
439 if (methodStubInfo
.OperationName
!= methodStubInfo
.Name
)
440 inOp
.Name
= outOp
.Name
= methodStubInfo
.Name
;
442 binding
.Operations
.Add (operationBinding
);
445 internal static void AddImport (ServiceDescription desc
, string ns
, string location
)
447 Import im
= new Import();
449 im
.Location
= location
;
450 desc
.Imports
.Add (im
);
453 string GetWsdlUrl (string baseUrl
, int id
)
455 return baseUrl
+ "?wsdl=" + id
;
458 protected virtual void BeginClass ()
462 protected virtual void EndClass ()
466 public ServiceDescription
GetServiceDescription (string ns
)
468 return ServiceDescriptions
[ns
];
471 protected abstract bool ReflectMethod ();
473 protected virtual string ReflectMethodBinding ()
479 [MonoNotSupported("Not Implemented")]
480 protected virtual void ReflectDescription ()
482 throw new NotImplementedException ();