Permalink
Browse files

[WCF]: Implement missing WsdlImporter pieces.

The WsdlImporter can now import Bindings and Endpoints
from the WSDL, currently supporting BasicHttpBinding,
BasicHttpsBinding and NetTcpBinding.

There is also - limited and still experimental - support
for WS-Policy 1.5.  I only did the very basic pieces so
far, for instance things like TransportWithMessageCredentials
are not supported yet.

The policy importer will emit lots of warnings via
`MetadataImporter.Errors` (as warnings, not errors) whenever
it encounters something that it doesn't understand and
is also forgiving towards unknown and/or mal-formed
policy assertions.

This behavior is different from the MS runtime, which is
very strict, but there are simply too many missing pieces
to be more pedentic here.  Check whether Errors.Count == 0
to see whether all policy assertions have been correctly
imported.

There are also a few metadata samples, which are part of the
new nunit tests.  These are currently working:

  BasicHttp.xml, BasicHttp_Mtom.xml, BasicHttp_NtlmAuth.xml,
  BasicHttp_TransportSecurity.xml, BasicHttps.xml,
  BasicHttps_NtlmAuth.xml, NetTcp.xml, NetTcp_TransferMode.xml,
  NetTcp_TransportSecurity.xml

There are a few more in the Tests/MetadataTests/Resources/
directory which demonstrate missing pieces.
  • Loading branch information...
1 parent 8e4dc61 commit cdc98dba1b83341c25a1daab4ae7c217d4961ad1 @baulig baulig committed Nov 27, 2012
@@ -1,9 +1,10 @@
//
// MessageEncodingBindingElementImporter.cs
//
-// Author: Atsushi Enomoto (atsushi@ximian.com)
+// Author:
+// Martin Baulig <martin.baulig@xamarin.com>
@alanmcgovern

alanmcgovern Nov 27, 2012

Contributor

You probably shouldn't remove the attribution for the original author here

//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
@alanmcgovern

alanmcgovern Nov 27, 2012

Contributor

you shouldn't remove the old novell copyright line here. You should just add an additional line with Xamarin on it

@baulig

baulig Nov 27, 2012

Member

That's what I did everywhere, including new files which contain code from existing ones. For instance, BasicHttpsBinding.cs is a new file that I created, but I copied some existing code from BasicHttpBinding.cs, so I copied the file from BasicHttpBinding.cs rather than using my "New File" template to preserve its original author and copyright

However, there were three files - MessageEncodingBindingElementImporter, TransportBindingElementImporter and StandardBindingElementImporter which previously contained not a single line of code, just a stub with [MonoTodo] and NotImplementedException's. None of that remained.

I actually created them as completely new files in my local tree, using my "New File" template, then copied them into the mono tree.

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -39,30 +40,42 @@ namespace System.ServiceModel.Channels
public class MessageEncodingBindingElementImporter
: IWsdlImportExtension, IPolicyImportExtension
{
- [MonoTODO]
void IWsdlImportExtension.BeforeImport (
ServiceDescriptionCollection wsdlDocuments,
XmlSchemaSet xmlSchemas,
ICollection<XmlElement> policy)
{
}
- [MonoTODO]
void IWsdlImportExtension.ImportContract (WsdlImporter importer,
WsdlContractConversionContext context)
{
}
- [MonoTODO]
void IWsdlImportExtension.ImportEndpoint (WsdlImporter importer,
WsdlEndpointConversionContext context)
{
}
- [MonoTODO]
void IPolicyImportExtension.ImportPolicy (MetadataImporter importer,
PolicyConversionContext context)
{
+ var assertions = context.GetBindingAssertions ();
+
+ var mtom = PolicyImportHelper.GetMtomMessageEncodingPolicy (assertions);
+ if (mtom != null) {
+ // http://www.w3.org/Submission/WS-MTOMPolicy/
+ context.BindingElements.Add (new MtomMessageEncodingBindingElement ());
+ return;
+ }
+
+ var binary = PolicyImportHelper.GetBinaryMessageEncodingPolicy (assertions);
+ if (binary != null) {
+ context.BindingElements.Add (new BinaryMessageEncodingBindingElement ());
+ return;
+ }
+
+ context.BindingElements.Add (new TextMessageEncodingBindingElement ());
}
}
}
@@ -0,0 +1,224 @@
+//
+// PolicyImportHelper.cs
+//
+// Author:
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Xml;
+using System.Collections.Generic;
+using System.ServiceModel.Description;
+
+using QName = System.Xml.XmlQualifiedName;
+
+namespace System.ServiceModel.Channels {
+
+ internal static class PolicyImportHelper {
+
+ internal const string SecurityPolicyNS = "http://schemas.xmlsoap.org/ws/2005/07/securitypolicy";
+ internal const string PolicyNS = "http://schemas.xmlsoap.org/ws/2004/09/policy";
+ internal const string MimeSerializationNS = "http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization";
+ internal const string HttpAuthNS = "http://schemas.microsoft.com/ws/06/2004/policy/http";
+
+ internal const string FramingPolicyNS = "http://schemas.microsoft.com/ws/2006/05/framing/policy";
+ internal const string NetBinaryEncodingNS = "http://schemas.microsoft.com/ws/06/2004/mspolicy/netbinary1";
+
+ internal static XmlElement GetTransportBindingPolicy (PolicyAssertionCollection collection)
+ {
+ return FindAndRemove (collection, "TransportBinding", SecurityPolicyNS);
+ }
+
+ internal static XmlElement GetStreamedMessageFramingPolicy (PolicyAssertionCollection collection)
+ {
+ return FindAndRemove (collection, "Streamed", FramingPolicyNS);
+ }
+
+ internal static XmlElement GetBinaryMessageEncodingPolicy (PolicyAssertionCollection collection)
+ {
+ return FindAndRemove (collection, "BinaryEncoding", NetBinaryEncodingNS);
+ }
+
+ internal static XmlElement GetMtomMessageEncodingPolicy (PolicyAssertionCollection collection)
+ {
+ return FindAndRemove (collection, "OptimizedMimeSerialization", MimeSerializationNS);
+ }
+
+ static XmlElement FindAndRemove (PolicyAssertionCollection collection, string name, string ns)
+ {
+ var element = collection.Find (name, ns);
+ if (element != null)
+ collection.Remove (element);
+ return element;
+ }
+
+ internal static List<XmlElement> FindAssertionByNS (
+ PolicyAssertionCollection collection, string ns)
+ {
+ var list = new List<XmlElement> ();
+ foreach (var assertion in collection) {
+ if (assertion.NamespaceURI.Equals (ns))
+ list.Add (assertion);
+ }
+ return list;
+ }
+
+ internal static List<XmlElement> GetPolicyElements (XmlElement root, out bool error)
+ {
+ XmlElement policy = null;
+ var list = new List<XmlElement> ();
+
+ foreach (var node in root.ChildNodes) {
+ var e = node as XmlElement;
+ if (e == null)
+ continue;
+ if (!PolicyNS.Equals (e.NamespaceURI) || !e.LocalName.Equals ("Policy")) {
+ error = true;
+ return list;
+ }
+ if (policy != null) {
+ error = true;
+ return list;
+ }
+ policy = e;
+ }
+
+ if (policy == null) {
+ error = true;
+ return list;
+ }
+
+ foreach (var node in policy.ChildNodes) {
+ var e = node as XmlElement;
+ if (e != null)
+ list.Add (e);
+ }
+
+ error = false;
+ return list;
+ }
+
+ internal static bool FindPolicyElement (MetadataImporter importer, XmlElement root,
+ QName name, bool required, bool removeWhenFound,
+ out XmlElement element)
+ {
+ if (!FindPolicyElement (root, name, removeWhenFound, out element)) {
+ importer.AddWarning ("Invalid policy element: {0}", root.OuterXml);
+ return false;
+ }
+ if (required && (element == null)) {
+ importer.AddWarning ("Did not find policy element `{0}'.", name);
+ return false;
+ }
+ return true;
+ }
+
+ internal static bool FindPolicyElement (XmlElement root, QName name,
+ bool removeWhenFound, out XmlElement element)
+ {
+ XmlElement policy = null;
+ foreach (var node in root.ChildNodes) {
+ var e = node as XmlElement;
+ if (e == null)
+ continue;
+ if (!PolicyNS.Equals (e.NamespaceURI) || !e.LocalName.Equals ("Policy")) {
+ element = null;
+ return false;
+ }
+ if (policy != null) {
+ element = null;
+ return false;
+ }
+ policy = e;
+ }
+
+ if (policy == null) {
+ element = null;
+ return true;
+ }
+
+ element = null;
+ foreach (var node in policy.ChildNodes) {
+ var e = node as XmlElement;
+ if (e == null)
+ continue;
+ if (!name.Namespace.Equals (e.NamespaceURI) || !name.Name.Equals (e.LocalName))
+ continue;
+
+ element = e;
+ break;
+ }
+
+ if (!removeWhenFound || (element == null))
+ return true;
+
+ policy.RemoveChild (element);
+
+ bool foundAnother = false;
+ foreach (var node in policy.ChildNodes) {
+ var e = node as XmlElement;
+ if (e != null) {
+ foundAnother = true;
+ break;
+ }
+ }
+
+ if (!foundAnother)
+ root.RemoveChild (policy);
+ return true;
+ }
+
+ internal static XmlElement GetElement (MetadataImporter importer,
+ XmlElement root, string name, string ns)
+ {
+ return GetElement (importer, root, name, ns, false);
+ }
+
+ internal static XmlElement GetElement (MetadataImporter importer,
+ XmlElement root, string name, string ns,
+ bool required)
+ {
+ return GetElement (importer, root, new QName (name, ns), required);
+ }
+
+ internal static XmlElement GetElement (MetadataImporter importer,
+ XmlElement root, QName name, bool required)
+ {
+ var list = root.GetElementsByTagName (name.Name, name.Namespace);
+ if (list.Count < 1) {
+ if (required)
+ importer.AddWarning ("Did not find required policy element `{0}'", name);
+ return null;
+ }
+
+ if (list.Count > 1) {
+ importer.AddWarning ("Found duplicate policy element `{0}'", name);
+ return null;
+ }
+
+ var element = list [0] as XmlElement;
+ if (required && (element == null))
+ importer.AddWarning ("Did not find required policy element `{0}'", name);
+ return element;
+ }
+ }
+}
+
Oops, something went wrong.

0 comments on commit cdc98db

Please sign in to comment.