2 // System.Web.Services.Description.BasicProfileChecker.cs
5 // Lluis Sanchez (lluis@novell.com)
7 // Copyright (C) Novell, Inc., 2004
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.
33 using System
.Xml
.Schema
;
35 using System
.Collections
;
37 namespace System
.Web
.Services
.Description
39 internal class BasicProfileChecker
: ConformanceChecker
41 public static BasicProfileChecker Instance
= new BasicProfileChecker ();
43 public override WsiClaims Claims
{
44 get { return WsiClaims.BP10; }
47 public override void Check (ConformanceCheckContext ctx
, Import
value)
49 if (value.Location
== "" || value.Location
== null) {
50 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2007
);
54 object doc
= ctx
.GetDocument (value.Location
);
55 if (doc
== null) ctx
.ReportError (value, "Document '" + value.Location
+ "' not found");
58 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2002
);
60 ServiceDescription imported
= doc
as ServiceDescription
;
61 if (imported
== null) {
62 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2001
);
68 if (imported
.TargetNamespace
!= value.Namespace
)
69 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2005
);
72 public override void Check (ConformanceCheckContext ctx
, ServiceDescription
value)
77 public override void Check (ConformanceCheckContext ctx
, ServiceDescriptionFormatExtension
value)
80 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2026
);
83 public override void Check (ConformanceCheckContext ctx
, MessagePart
value)
85 CheckWsdlQName (ctx
, value, value.Type
);
86 CheckWsdlQName (ctx
, value, value.Element
);
88 if (value.DefinedByElement
&& value.Element
.Namespace
== XmlSchema
.Namespace
)
89 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2206
);
92 public override void Check (ConformanceCheckContext ctx
, Types
value)
96 public override void Check (ConformanceCheckContext ctx
, Message
value)
101 public override void Check (ConformanceCheckContext ctx
, Binding
value)
103 SoapBinding sb
= (SoapBinding
) value.Extensions
.Find (typeof(SoapBinding
));
104 if (sb
== null || sb
.Transport
== null || sb
.Transport
== "") {
105 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2701
);
109 if (sb
.Transport
!= "http://schemas.xmlsoap.org/soap/http")
110 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2702
);
112 LiteralType type
= GetLiteralBindingType (value);
113 if (type
== LiteralType
.NotLiteral
)
114 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2706
);
115 else if (type
== LiteralType
.Inconsistent
)
116 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2705
);
118 // Collect all parts referenced from this type
120 Hashtable parts
= new Hashtable ();
121 PortType port
= ctx
.Services
.GetPortType (value.Type
);
122 foreach (Operation op
in port
.Operations
) {
123 foreach (OperationMessage om
in op
.Messages
) {
124 Message msg
= ctx
.Services
.GetMessage (om
.Message
);
125 foreach (MessagePart part
in msg
.Parts
)
126 parts
.Add (part
,part
);
130 foreach (OperationBinding ob
in value.Operations
) {
131 if (ob
.Input
!= null) CheckMessageBinding (ctx
, parts
, ob
.Input
);
132 if (ob
.Output
!= null) CheckMessageBinding (ctx
, parts
, ob
.Output
);
133 foreach (FaultBinding fb
in ob
.Faults
)
134 CheckMessageBinding (ctx
, parts
, fb
);
138 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2209
);
141 public override void Check (ConformanceCheckContext ctx
, OperationBinding ob
)
145 void CheckMessageBinding (ConformanceCheckContext ctx
, Hashtable portParts
, MessageBinding
value)
147 SoapBodyBinding sbb
= (SoapBodyBinding
) value.Extensions
.Find (typeof(SoapBodyBinding
));
148 Message msg
= FindMessage (ctx
, value);
149 LiteralType bt
= GetLiteralBindingType (value.OperationBinding
.Binding
);
153 if (bt
== LiteralType
.Document
)
155 if (sbb
.Parts
!= null && sbb
.Parts
.Length
> 1)
156 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2201
);
158 if (sbb
.Parts
== null) {
159 if (msg
.Parts
!= null && msg
.Parts
.Count
> 1)
160 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2210
);
161 if (msg
.Parts
.Count
== 1)
162 portParts
.Remove (msg
.Parts
[0]);
165 if (sbb
.Parts
.Length
== 0 && msg
.Parts
.Count
== 1) {
166 portParts
.Remove (msg
.Parts
[0]);
168 foreach (string part
in sbb
.Parts
) {
169 MessagePart mp
= msg
.FindPartByName (part
);
170 portParts
.Remove (mp
);
171 if (!mp
.DefinedByElement
)
172 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2204
);
177 else if (bt
== LiteralType
.Rpc
)
179 if (sbb
.Parts
!= null) {
180 foreach (string part
in sbb
.Parts
) {
181 MessagePart mp
= msg
.FindPartByName (part
);
182 portParts
.Remove (mp
);
183 if (!mp
.DefinedByType
)
184 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2203
);
190 SoapHeaderBinding shb
= (SoapHeaderBinding
) value.Extensions
.Find (typeof(SoapHeaderBinding
));
192 Message hm
= ctx
.Services
.GetMessage (shb
.Message
);
193 MessagePart mp
= hm
.FindPartByName (shb
.Part
);
194 portParts
.Remove (mp
);
195 if (mp
!= null && !mp
.DefinedByElement
)
196 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2205
);
199 SoapHeaderFaultBinding shfb
= (SoapHeaderFaultBinding
) value.Extensions
.Find (typeof(SoapHeaderFaultBinding
));
201 Message hm
= ctx
.Services
.GetMessage (shfb
.Message
);
202 MessagePart mp
= hm
.FindPartByName (shfb
.Part
);
203 portParts
.Remove (mp
);
204 if (mp
!= null && !mp
.DefinedByElement
)
205 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2205
);
208 // TODO: SoapFaultBinding ??
211 Message
FindMessage (ConformanceCheckContext ctx
, MessageBinding mb
)
213 PortType pt
= ctx
.Services
.GetPortType (mb
.OperationBinding
.Binding
.Type
);
214 foreach (Operation op
in pt
.Operations
)
215 if (op
.IsBoundBy (mb
.OperationBinding
)) {
217 if (mb
is InputBinding
) om
= op
.Messages
.Input
;
218 else if (mb
is OutputBinding
) om
= op
.Messages
.Output
;
219 else if (mb
is FaultBinding
) om
= op
.Messages
.Fault
;
221 return ctx
.Services
.GetMessage (om
.Message
);
226 public override void Check (ConformanceCheckContext ctx
, Operation
value) { }
227 public override void Check (ConformanceCheckContext ctx
, OperationMessage
value) { }
228 public override void Check (ConformanceCheckContext ctx
, Port
value) { }
229 public override void Check (ConformanceCheckContext ctx
, PortType
value) { }
230 public override void Check (ConformanceCheckContext ctx
, Service
value) { }
232 public override void Check (ConformanceCheckContext ctx
, XmlSchema s
)
234 if (s
.TargetNamespace
== null || s
.TargetNamespace
== "") {
235 foreach (XmlSchemaObject ob
in s
.Items
)
236 if (!(ob
is XmlSchemaImport
) && !(ob
is XmlSchemaAnnotation
)) {
237 ctx
.ReportRuleViolation (s
, BasicProfileRules
.R2105
);
243 public override void Check (ConformanceCheckContext ctx
, XmlSchemaImport
value)
245 XmlSchema doc
= ctx
.GetDocument (value.SchemaLocation
) as XmlSchema
;
246 if (doc
== null) ctx
.ReportError (value, "Schema '" + value.SchemaLocation
+ "' not found");
249 public override void Check (ConformanceCheckContext ctx
, XmlSchemaAttribute
value)
251 CheckSchemaQName (ctx
, value, value.RefName
);
252 CheckSchemaQName (ctx
, value, value.SchemaTypeName
);
254 XmlAttribute
[] uatts
= value.UnhandledAttributes
;
256 foreach (XmlAttribute at
in uatts
)
257 if (at
.LocalName
== "arrayType" && at
.NamespaceURI
== "http://schemas.xmlsoap.org/wsdl/")
258 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2111
);
262 public override void Check (ConformanceCheckContext ctx
, XmlSchemaAttributeGroupRef
value)
264 CheckSchemaQName (ctx
, value, value.RefName
);
267 public override void Check (ConformanceCheckContext ctx
, XmlSchemaComplexContentExtension
value)
269 CheckSchemaQName (ctx
, value, value.BaseTypeName
);
270 if (value.BaseTypeName
.Namespace
== "http://schemas.xmlsoap.org/soap/encoding/" && value.BaseTypeName
.Name
== "Array")
271 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2110
);
274 public override void Check (ConformanceCheckContext ctx
, XmlSchemaComplexContentRestriction
value)
276 CheckSchemaQName (ctx
, value, value.BaseTypeName
);
277 if (value.BaseTypeName
.Namespace
== "http://schemas.xmlsoap.org/soap/encoding/" && value.BaseTypeName
.Name
== "Array")
278 ctx
.ReportRuleViolation (value, BasicProfileRules
.R2110
);
281 public override void Check (ConformanceCheckContext ctx
, XmlSchemaElement
value)
283 CheckSchemaQName (ctx
, value, value.RefName
);
284 CheckSchemaQName (ctx
, value, value.SubstitutionGroup
);
285 CheckSchemaQName (ctx
, value, value.SchemaTypeName
);
288 public override void Check (ConformanceCheckContext ctx
, XmlSchemaGroupRef
value)
290 CheckSchemaQName (ctx
, value, value.RefName
);
293 public override void Check (ConformanceCheckContext ctx
, XmlSchemaKeyref
value)
295 CheckSchemaQName (ctx
, value, value.Refer
);
298 public override void Check (ConformanceCheckContext ctx
, XmlSchemaSimpleContentExtension
value)
300 CheckSchemaQName (ctx
, value, value.BaseTypeName
);
303 public override void Check (ConformanceCheckContext ctx
, XmlSchemaSimpleContentRestriction
value)
305 CheckSchemaQName (ctx
, value, value.BaseTypeName
);
308 public override void Check (ConformanceCheckContext ctx
, XmlSchemaSimpleTypeList
value)
310 CheckSchemaQName (ctx
, value, value.ItemTypeName
);
313 public override void Check (ConformanceCheckContext ctx
, XmlSchemaSimpleTypeRestriction
value)
315 CheckSchemaQName (ctx
, value, value.BaseTypeName
);
318 public override void Check (ConformanceCheckContext ctx
, XmlSchemaSimpleTypeUnion
value)
320 foreach (XmlQualifiedName name
in value.MemberTypes
)
321 CheckSchemaQName (ctx
, value, name
);
326 void CheckWsdlQName (ConformanceCheckContext ctx
, object element
, XmlQualifiedName name
)
328 if (name
== null || name
== XmlQualifiedName
.Empty
) return;
329 if (name
.Namespace
== "" || name
.Namespace
== XmlSchema
.Namespace
) return;
331 if (ctx
.ServiceDescription
.Types
!= null && ctx
.ServiceDescription
.Types
.Schemas
!= null)
333 foreach (XmlSchema s
in ctx
.ServiceDescription
.Types
.Schemas
)
335 if (s
.TargetNamespace
== name
.Namespace
) return;
336 foreach (XmlSchemaObject i
in s
.Includes
)
337 if ((i
is XmlSchemaImport
) && ((XmlSchemaImport
)i
).Namespace
== name
.Namespace
) return;
340 ctx
.ReportRuleViolation (element
, BasicProfileRules
.R2101
);
343 void CheckSchemaQName (ConformanceCheckContext ctx
, object element
, XmlQualifiedName name
)
345 if (name
== null || name
== XmlQualifiedName
.Empty
) return;
346 if (name
.Namespace
== "" || name
.Namespace
== XmlSchema
.Namespace
) return;
347 if (ctx
.CurrentSchema
.TargetNamespace
== name
.Namespace
) return;
349 foreach (XmlSchemaObject i
in ctx
.CurrentSchema
.Includes
)
350 if ((i
is XmlSchemaImport
) && ((XmlSchemaImport
)i
).Namespace
== name
.Namespace
) return;
352 ctx
.ReportRuleViolation (element
, BasicProfileRules
.R2102
);
355 LiteralType
GetLiteralBindingType (Binding b
)
357 SoapBinding sb
= (SoapBinding
) b
.Extensions
.Find (typeof(SoapBinding
));
358 SoapBindingStyle style
= (sb
!= null) ? sb
.Style
: SoapBindingStyle
.Document
;
359 if (style
== SoapBindingStyle
.Default
) style
= SoapBindingStyle
.Document
;
361 foreach (OperationBinding ob
in b
.Operations
) {
362 SoapOperationBinding sob
= (SoapOperationBinding
) ob
.Extensions
.Find (typeof(SoapOperationBinding
));
363 if (sob
.Style
!= SoapBindingStyle
.Default
&& sob
.Style
!= style
)
364 return LiteralType
.Inconsistent
;
365 if (ob
.Input
!= null) {
366 SoapBodyBinding sbb
= (SoapBodyBinding
) ob
.Input
.Extensions
.Find (typeof(SoapBodyBinding
));
367 if (sbb
!= null && sbb
.Use
!= SoapBindingUse
.Literal
) return LiteralType
.NotLiteral
;
368 SoapFaultBinding sfb
= (SoapFaultBinding
) ob
.Input
.Extensions
.Find (typeof(SoapFaultBinding
));
369 if (sfb
!= null && sfb
.Use
!= SoapBindingUse
.Literal
) return LiteralType
.NotLiteral
;
370 SoapHeaderBinding shb
= (SoapHeaderBinding
) ob
.Input
.Extensions
.Find (typeof(SoapHeaderBinding
));
371 if (shb
!= null && shb
.Use
!= SoapBindingUse
.Literal
) return LiteralType
.NotLiteral
;
372 SoapHeaderFaultBinding shfb
= (SoapHeaderFaultBinding
) ob
.Input
.Extensions
.Find (typeof(SoapHeaderFaultBinding
));
373 if (shfb
!= null && shfb
.Use
!= SoapBindingUse
.Literal
) return LiteralType
.NotLiteral
;
375 if (ob
.Output
!= null) {
376 SoapBodyBinding sbb
= (SoapBodyBinding
) ob
.Output
.Extensions
.Find (typeof(SoapBodyBinding
));
377 if (sbb
!= null && sbb
.Use
!= SoapBindingUse
.Literal
) return LiteralType
.NotLiteral
;
378 SoapFaultBinding sfb
= (SoapFaultBinding
) ob
.Input
.Extensions
.Find (typeof(SoapFaultBinding
));
379 if (sfb
!= null && sfb
.Use
!= SoapBindingUse
.Literal
) return LiteralType
.NotLiteral
;
380 SoapHeaderBinding shb
= (SoapHeaderBinding
) ob
.Input
.Extensions
.Find (typeof(SoapHeaderBinding
));
381 if (shb
!= null && shb
.Use
!= SoapBindingUse
.Literal
) return LiteralType
.NotLiteral
;
382 SoapHeaderFaultBinding shfb
= (SoapHeaderFaultBinding
) ob
.Input
.Extensions
.Find (typeof(SoapHeaderFaultBinding
));
383 if (shfb
!= null && shfb
.Use
!= SoapBindingUse
.Literal
) return LiteralType
.NotLiteral
;
386 if (style
== SoapBindingStyle
.Document
) return LiteralType
.Document
;
387 else return LiteralType
.Rpc
;
398 internal class BasicProfileRules
401 // 3.2 Conformance of Services, Consumers and Registries
403 // Can't check: R0001
405 // 3.3 Conformance Annotation in Descriptions
407 // Can't check: R0002, R0003
409 // 3.4 Conformance Annotation in Messages
411 // Can't check: R0004, R0005, R0006, R0007
413 // 3.5 Conformance Annotation in Registry Data
415 // UDDI related: R3020, R3030, R3021, R3005, R3004.
417 // 4.1 XML Representation of SOAP Messages
419 // Rules not related to service description
421 // 4.2 SOAP Processing Model
423 // Rules not related to service description
425 // 4.3 Use of SOAP in HTTP
427 // Rules not related to service description
429 // 5.1 Document structure
431 public static readonly ConformanceRule R2001
= new ConformanceRule (
433 "A DESCRIPTION MUST only use the WSDL \"import\" statement to import another WSDL description",
436 public static readonly ConformanceRule R2002
= new ConformanceRule (
438 "To import XML Schema Definitions, a DESCRIPTION MUST use the XML Schema \"import\" statement",
441 public static readonly ConformanceRule R2007
= new ConformanceRule (
443 "A DESCRIPTION MUST specify a non-empty location attribute on the wsdl:import element",
446 public static readonly ConformanceRule R2005
= new ConformanceRule (
448 "The targetNamespace attribute on the wsdl:definitions element of a description that is being imported MUST have same the value as the namespace attribute on the wsdl:import element in the importing DESCRIPTION",
451 public static readonly ConformanceRule R2026
= new ConformanceRule (
453 "A DESCRIPTION SHOULD NOT include extension elements with a wsdl:required attribute value of \"true\" on any WSDL construct (wsdl:binding, wsdl:portType, wsdl:message, wsdl:types or wsdl:import) that claims conformance to the Profile",
458 public static readonly ConformanceRule R2101
= new ConformanceRule (
460 "A DESCRIPTION MUST NOT use QName references to elements in namespaces that have been neither imported, nor defined in the referring WSDL document",
463 public static readonly ConformanceRule R2102
= new ConformanceRule (
465 "A QName reference to a Schema component in a DESCRIPTION MUST use the namespace defined in the targetNamespace attribute on the xsd:schema element, or to a namespace defined in the namespace attribute on an xsd:import element within the xsd:schema element",
468 public static readonly ConformanceRule R2105
= new ConformanceRule (
470 "All xsd:schema elements contained in a wsdl:types element of a DESCRIPTION MUST have a targetNamespace attribute with a valid and non-null value, UNLESS the xsd:schema element has xsd:import and/or xsd:annotation as its only child element(s)",
473 public static readonly ConformanceRule R2110
= new ConformanceRule (
475 "In a DESCRIPTION, array declarations MUST NOT extend or restrict the soapenc:Array type",
478 public static readonly ConformanceRule R2111
= new ConformanceRule (
480 "In a DESCRIPTION, array declarations MUST NOT use wsdl:arrayType attribute in the type declaration",
483 // R2112: Suggestion.
484 // R2113: Not related to servide description
485 // R2114: Suggestion.
489 public static readonly ConformanceRule R2201
= new ConformanceRule (
491 "A document-literal binding in a DESCRIPTION MUST, in each of its soapbind:body element(s), have at most one part listed in the parts attribute, if the parts attribute is specified",
494 public static readonly ConformanceRule R2210
= new ConformanceRule (
496 "If a document-literal binding in a DESCRIPTION does not specify the parts attribute on a soapbind:body element, the corresponding abstract wsdl:message MUST define zero or one wsdl:parts",
499 public static readonly ConformanceRule R2203
= new ConformanceRule (
501 "An rpc-literal binding in a DESCRIPTION MUST refer, in its soapbind:body element(s), only to wsdl:part element(s) that have been defined using the type attribute",
504 public static readonly ConformanceRule R2204
= new ConformanceRule (
506 "A document-literal binding in a DESCRIPTION MUST refer, in each of its soapbind:body element(s), only to wsdl:part element(s) that have been defined using the element attribute",
509 public static readonly ConformanceRule R2205
= new ConformanceRule (
511 "A wsdl:binding in a DESCRIPTION MUST refer, in each of its soapbind:header, soapbind:headerfault and soapbind:fault elements, only to wsdl:part element(s) that have been defined using the element attribute",
514 public static readonly ConformanceRule R2209
= new ConformanceRule (
516 "A wsdl:binding in a DESCRIPTION SHOULD bind every wsdl:part of a wsdl:message in the wsdl:portType to which it refers to one of soapbind:body, soapbind:header, soapbind:fault or soapbind:headerfault",
519 public static readonly ConformanceRule R2206
= new ConformanceRule (
521 "A wsdl:message in a DESCRIPTION containing a wsdl:part that uses the element attribute MUST refer, in that attribute, to a global element declaration",
524 // R2211: Related to message structure
525 // R2202: Suggestion.
539 public static readonly ConformanceRule R2701
= new ConformanceRule (
541 "The wsdl:binding element in a DESCRIPTION MUST be constructed so that its soapbind:binding child element specifies the transport attribute",
544 public static readonly ConformanceRule R2702
= new ConformanceRule (
546 "A wsdl:binding element in a DESCRIPTION MUST specify the HTTP transport protocol with SOAP binding. Specifically, the transport attribute of its soapbind:binding child MUST have the value \"http://schemas.xmlsoap.org/soap/http\"",
549 public static readonly ConformanceRule R2705
= new ConformanceRule (
551 "A wsdl:binding in a DESCRIPTION MUST use either be a rpc-literal binding or a document-literal binding",
554 public static readonly ConformanceRule R2706
= new ConformanceRule (
556 "A wsdl:binding in a DESCRIPTION MUST use the value of \"literal\" for the use attribute in all soapbind:body, soapbind:fault, soapbind:header and soapbind:headerfault elements",
559 // R2707: Interpretation rule: A wsdl:binding in a DESCRIPTION that contains one or more soapbind:body, soapbind:fault, soapbind:header or soapbind:headerfault elements that do not specify the use attribute MUST be interpreted as though the value "literal" had been specified in each case
560 // R2709: Suggestion.
566 The following rules cannot be checked:
567 R2002, R2003, R4004, R4003, R2022, R2023, R2004, R2010, R2011
568 There is no access to the unerlying xml
570 The following are suggestions:
573 The following are optional
574 R4002, R2020, R2021, R2024, R2114