2 // StandardBindingImporter.cs
5 // Martin Baulig <martin.baulig@xamarin.com>
7 // Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 using System.Xml.Schema;
31 using System.Collections.Generic;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
34 using System.ServiceModel.Description;
36 using WS = System.Web.Services.Description;
37 using QName = System.Xml.XmlQualifiedName;
39 namespace System.ServiceModel.Channels {
41 public class StandardBindingImporter : IWsdlImportExtension {
42 #region IWsdlImportExtension implementation
44 public void BeforeImport (WS.ServiceDescriptionCollection wsdlDocuments, XmlSchemaSet xmlSchemas,
45 ICollection<XmlElement> policy)
49 public void ImportContract (WsdlImporter importer, WsdlContractConversionContext contractContext)
53 WS.Port LookupPort (WsdlImporter importer, QName name)
55 foreach (WS.ServiceDescription doc in importer.WsdlDocuments) {
56 foreach (WS.Service service in doc.Services) {
57 foreach (WS.Port port in service.Ports) {
58 if (!name.Namespace.Equals (port.Binding.Namespace))
60 if (!name.Name.Equals (port.Binding.Name))
70 public void ImportEndpoint (WsdlImporter importer, WsdlEndpointConversionContext context)
72 var custom = context.Endpoint.Binding as CustomBinding;
76 var soapHttp = GetHttpSoapBinding (context.WsdlBinding);
77 if (soapHttp != null) {
78 ImportBasicHttpBinding (importer, context, custom, soapHttp);
82 var soapTcp = GetTcpSoapBinding (context.WsdlBinding);
83 if (soapTcp != null) {
84 ImportNetTcpBinding (importer, context, custom, soapTcp);
89 internal static WS.SoapBinding GetHttpSoapBinding (WS.Binding binding)
91 WS.SoapBinding soap = null;
92 foreach (var extension in binding.Extensions) {
93 var check = extension as WS.SoapBinding;
102 if (soap.Transport != WS.SoapBinding.HttpTransport)
104 if (soap.Style != WS.SoapBindingStyle.Document)
109 const string TcpTransport = "http://schemas.microsoft.com/soap/tcp";
111 internal static WS.Soap12Binding GetTcpSoapBinding (WS.Binding binding)
113 WS.Soap12Binding soap = null;
114 foreach (var extension in binding.Extensions) {
115 var check = extension as WS.Soap12Binding;
124 if (soap.Transport != TcpTransport)
126 if (soap.Style != WS.SoapBindingStyle.Document)
131 bool ImportBasicHttpBinding (
132 WsdlImporter importer, WsdlEndpointConversionContext context,
133 CustomBinding custom, WS.SoapBinding soap)
135 TransportBindingElement transportElement = null;
136 MtomMessageEncodingBindingElement mtomElement = null;
137 TextMessageEncodingBindingElement textElement = null;
138 bool foundUnknownElement = false;
140 foreach (var element in custom.Elements) {
141 if (element is TransportBindingElement)
142 transportElement = (TransportBindingElement)element;
143 else if (element is MtomMessageEncodingBindingElement)
144 mtomElement = (MtomMessageEncodingBindingElement)element;
145 else if (element is TextMessageEncodingBindingElement)
146 textElement = (TextMessageEncodingBindingElement)element;
148 importer.AddWarning (
149 "Found unknown binding element `{0}' while attempting " +
150 "to import binding `{0}'.", element.GetType (),
152 foundUnknownElement = true;
156 if (foundUnknownElement)
159 if ((mtomElement != null) && (textElement != null)) {
160 // FIXME: Should never happen
161 importer.AddWarning (
162 "Found both MtomMessageEncodingBindingElement and " +
163 "TextMessageEncodingBindingElement while attempting to " +
164 "import binding `{0}'.", custom.Name);
168 BasicHttpBinding httpBinding;
169 AuthenticationSchemes authScheme;
172 * FIXME: Maybe make the BasicHttpBinding use the transport element
173 * that we created with the TransportBindingElementImporter ?
175 * There seems to be no public API to do that, so maybe add a private .ctor ?
179 var httpsTransport = transportElement as HttpsTransportBindingElement;
180 var httpTransport = transportElement as HttpTransportBindingElement;
182 if (httpsTransport != null) {
183 httpBinding = new BasicHttpBinding (BasicHttpSecurityMode.Transport);
184 authScheme = httpsTransport.AuthenticationScheme;
185 } else if (httpTransport != null) {
186 authScheme = httpTransport.AuthenticationScheme;
187 if ((authScheme != AuthenticationSchemes.None) &&
188 (authScheme != AuthenticationSchemes.Anonymous))
189 httpBinding = new BasicHttpBinding (
190 BasicHttpSecurityMode.TransportCredentialOnly);
192 httpBinding = new BasicHttpBinding ();
194 httpBinding = new BasicHttpBinding ();
195 authScheme = AuthenticationSchemes.Anonymous;
198 if (mtomElement != null)
199 httpBinding.MessageEncoding = WSMessageEncoding.Mtom;
200 else if (textElement != null)
201 httpBinding.MessageEncoding = WSMessageEncoding.Text;
203 importer.AddWarning (
204 "Found neither MtomMessageEncodingBindingElement nor " +
205 "TextMessageEncodingBindingElement while attempting to " +
206 "import binding `{0}'.", custom.Name);
210 httpBinding.Name = context.Endpoint.Binding.Name;
211 httpBinding.Namespace = context.Endpoint.Binding.Namespace;
213 switch (authScheme) {
214 case AuthenticationSchemes.None:
215 case AuthenticationSchemes.Anonymous:
216 httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
218 case AuthenticationSchemes.Basic:
219 httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
221 case AuthenticationSchemes.Digest:
222 httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Digest;
224 case AuthenticationSchemes.Ntlm:
225 httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
227 case AuthenticationSchemes.Negotiate:
228 httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
231 importer.AddWarning ("Invalid auth scheme: {0}", authScheme);
235 if ((httpsTransport != null) && httpsTransport.RequireClientCertificate) {
236 if (httpBinding.Security.Transport.ClientCredentialType != HttpClientCredentialType.None) {
237 importer.AddWarning ("Cannot use both client certificate and explicit auth type.");
240 httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
243 context.Endpoint.Binding = httpBinding;
247 bool ImportNetTcpBinding (
248 WsdlImporter importer, WsdlEndpointConversionContext context,
249 CustomBinding custom, WS.Soap12Binding soap)
251 TcpTransportBindingElement transportElement = null;
252 BinaryMessageEncodingBindingElement binaryElement = null;
253 TransactionFlowBindingElement transactionFlowElement = null;
254 WindowsStreamSecurityBindingElement windowsStreamElement = null;
255 SslStreamSecurityBindingElement sslStreamElement = null;
256 bool foundUnknownElement = false;
258 foreach (var element in custom.Elements) {
259 if (element is TcpTransportBindingElement)
260 transportElement = (TcpTransportBindingElement)element;
261 else if (element is BinaryMessageEncodingBindingElement)
262 binaryElement = (BinaryMessageEncodingBindingElement)element;
263 else if (element is TransactionFlowBindingElement)
264 transactionFlowElement = (TransactionFlowBindingElement)element;
265 else if (element is WindowsStreamSecurityBindingElement)
266 windowsStreamElement = (WindowsStreamSecurityBindingElement)element;
267 else if (element is SslStreamSecurityBindingElement)
268 sslStreamElement = (SslStreamSecurityBindingElement)element;
270 importer.AddWarning (
271 "Found unknown binding element `{0}' while importing " +
272 "binding `{1}'.", element.GetType (), custom.Name);
273 foundUnknownElement = true;
277 if (foundUnknownElement)
280 if (transportElement == null) {
281 importer.AddWarning (
282 "Missing TcpTransportBindingElement while importing " +
283 "binding `{0}'.", custom.Name);
286 if (binaryElement == null) {
287 importer.AddWarning (
288 "Missing BinaryMessageEncodingBindingElement while importing " +
289 "binding `{0}'.", custom.Name);
293 if ((windowsStreamElement != null) && (sslStreamElement != null)) {
294 importer.AddWarning (
295 "Found both WindowsStreamSecurityBindingElement and " +
296 "SslStreamSecurityBindingElement while importing binding `{0}.",
301 NetTcpSecurity security;
302 if (windowsStreamElement != null) {
303 security = new NetTcpSecurity (SecurityMode.Transport);
304 security.Transport.ProtectionLevel = windowsStreamElement.ProtectionLevel;
305 } else if (sslStreamElement != null) {
306 security = new NetTcpSecurity (SecurityMode.TransportWithMessageCredential);
308 security = new NetTcpSecurity (SecurityMode.None);
311 var netTcp = new NetTcpBinding (transportElement, security, false);
313 netTcp.Name = context.Endpoint.Binding.Name;
314 netTcp.Namespace = context.Endpoint.Binding.Namespace;
316 context.Endpoint.Binding = netTcp;