From 7341a6939638beee17a8a780273523662224ef15 Mon Sep 17 00:00:00 2001 From: bbaia Date: Tue, 5 Aug 2008 08:19:48 +0000 Subject: [PATCH] Removed WebServiceProxyFactory.ClientProtocolType property (obsolete) [SPRNET-811] --- .../Web/Services/WebServiceProxyFactory.cs | 2339 ++++++++--------- 1 file changed, 1163 insertions(+), 1176 deletions(-) diff --git a/src/Spring/Spring.Services/Web/Services/WebServiceProxyFactory.cs b/src/Spring/Spring.Services/Web/Services/WebServiceProxyFactory.cs index 84b92ac2..11c6c5c0 100644 --- a/src/Spring/Spring.Services/Web/Services/WebServiceProxyFactory.cs +++ b/src/Spring/Spring.Services/Web/Services/WebServiceProxyFactory.cs @@ -1,1184 +1,1171 @@ -#region License - -/* - * Copyright © 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -#region Imports - -using System; -using System.Collections; -using System.Globalization; -using System.Xml; -using System.Xml.Schema; -using System.Xml.Serialization; -using System.Net; -using System.Reflection; -using System.Reflection.Emit; -using System.Web.Services; -using System.Web.Services.Description; -using System.Web.Services.Protocols; -using System.Web.Services.Discovery; - -using Spring.Core; -using Spring.Objects.Factory; -using Spring.Objects.Factory.Config; -using Spring.Proxy; -using Spring.Util; -using Spring.Objects; -using Spring.Core.IO; -using Spring.Expressions; - -#endregion - -namespace Spring.Web.Services -{ - /// - /// Factory Object that dynamically implements service interface for web service. - /// - /// - ///

- /// This factory object should be used to obtain reference to a web service - /// that can be safely cast to a service interface, which allows client code to code - /// against interface, and not directly against the web service. - ///

- ///

- /// The WSDL contract needs to conform to WS-I Basic Profiles. - ///

- ///
- /// Bruno Baia - /// Aleksandar Seovic - public class WebServiceProxyFactory : IConfigurableFactoryObject, IInitializingObject - { - #region Logging - - private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(WebServiceProxyFactory)); - - #endregion - - #region Fields - - private IObjectDefinition _productTemplate; - private Type _webServiceProxyBaseType = typeof(SoapHttpClientProtocol); - private IResource _serviceUri; - private Type _proxyType; - private Type _serviceInterface; - private NetworkCredential _credential; - private string _proxyUrl; - private NetworkCredential _proxyCredential; - private string _bindingName; - private IList _typeAttributes = new ArrayList(); - private IDictionary _memberAttributes = new Hashtable(); - - /// - /// The web service proxy default constructor. - /// - protected ConstructorInfo proxyConstructor; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public WebServiceProxyFactory() - { - } - - #endregion - - #region Properties - - /// - /// Gets or sets the base type that web service proxy should inherit. - /// - /// - /// Default is - /// - [Obsolete("This property is obsolete, it has been replaced by WebServiceProxyBaseType")] - public Type ClientProtocolType - { - get { return _webServiceProxyBaseType; } - set { _webServiceProxyBaseType = value; } - } - - /// - /// Gets or sets the base type that web service proxy should inherit. - /// - /// - /// Default is - /// - public Type WebServiceProxyBaseType - { - get { return _webServiceProxyBaseType; } - set { _webServiceProxyBaseType = value; } - } - - /// - /// Gets or sets the URI for an - /// that contains the web service description (WSDL). - /// - public IResource ServiceUri - { - get { return _serviceUri; } - set { _serviceUri = value; } - } - - /// - /// Gets or sets type of the proxy class to wrap. - /// - public Type ProxyType - { - get { return _proxyType; } - set { _proxyType = value; } - } - - /// - /// Gets or sets service interface that proxy should implement. - /// - public Type ServiceInterface - { - get { return _serviceInterface; } - set { _serviceInterface = value; } - } - - /// - /// Gets or sets the instance - /// to use when connecting to a server that requires authentication. - /// - public NetworkCredential Credential - { - get { return _credential; } - set { _credential = value; } - } - - /// - /// Gets or sets the url of the proxy server to use for retrieving the WSDL. - /// - /// - ///

- /// This only applies when using an as uri. - ///

- ///

- /// The default is to use the system proxy setting. - ///

- ///
- public string ProxyUrl - { - get { return _proxyUrl; } - set { _proxyUrl = value; } - } - - /// - /// Gets or sets the instance - /// to use when connecting to a proxy server that requires authentication. - /// - /// - ///

- /// This only applies when using an as uri. - ///

- ///
- public NetworkCredential ProxyCredential - { - get { return _proxyCredential; } - set { _proxyCredential = value; } - } - - /// - /// Gets or sets the web service binding name to use for the proxy. - /// - public string BindingName - { - get { return _bindingName; } - set { _bindingName = value; } - } - - /// - /// Gets or sets a list of custom attributes - /// that should be applied to a proxy class. - /// - public IList TypeAttributes - { - get { return _typeAttributes; } - set { _typeAttributes = value; } - } - - /// - /// Gets or sets a dictionary of custom attributes - /// that should be applied to web service members. - /// - /// - /// Dictionary key is an expression that members can be matched against. - /// Value is a list of attributes that should be applied - /// to each member that matches expression. - /// - public IDictionary MemberAttributes - { - get { return _memberAttributes; } - set { _memberAttributes = value; } - } - - #endregion - - #region IConfigurableFactoryObject Members - - /// - /// Returns type of the web service proxy. - /// - public virtual Type ObjectType - { - get { return (proxyConstructor != null ? proxyConstructor.DeclaringType : ServiceInterface); } - } - - /// - /// Creates new instance of the web service proxy. - /// - /// New instance of the web service proxy. - public virtual object GetObject() - { - if (proxyConstructor == null) - { - GenerateProxy(); - } - - return ObjectUtils.InstantiateType(proxyConstructor, ObjectUtils.EmptyObjects); - } - - /// - /// Always returns false. - /// - public virtual bool IsSingleton - { - get { return false; } - } - - /// - /// Gets or sets the template object definition - /// that should be used to configure proxy instance. - /// - public virtual IObjectDefinition ProductTemplate - { - get { return _productTemplate; } - set { _productTemplate = value; } - } - - #endregion - - #region IInitializingObject Members - - /// - /// Initializes factory object. - /// - public virtual void AfterPropertiesSet() - { - ValidateConfiguration(); - } - - #endregion - - #region Protected Methods - - /// - /// Validates the configuration. - /// - protected virtual void ValidateConfiguration() - { - if (ServiceUri == null && ProxyType == null) - { - throw new ArgumentException("ServiceUri or ProxyType property is required."); - } - if (ServiceInterface == null) - { - throw new ArgumentException("The ServiceInterface property is required."); - } - if (!ServiceInterface.IsInterface) - { - throw new ArgumentException("ServiceInterface must be an interface"); - } - if (WebServiceProxyBaseType.IsSealed) - { - throw new ArgumentException("Web service client proxy cannot be created for a sealed class [" + WebServiceProxyBaseType.FullName + "]"); - } - } - - /// - /// Generates the web service proxy type. - /// - protected virtual void GenerateProxy() - { - IProxyTypeBuilder builder; - if (ProxyType != null) - { - // Wrap .NET generated proxy class or another - builder = new WebServiceProxyProxyTypeBuilder(); - builder.TargetType = ProxyType; - } - else - { - // Dynamically generates proxy class from WSDL - builder = new SoapHttpClientProxyTypeBuilder( - ServiceUri, GetWsDocuments(ServiceUri), BindingName); - builder.BaseType = WebServiceProxyBaseType; - } - - builder.Interfaces = ReflectionUtils.ToInterfaceArray(ServiceInterface); - builder.TypeAttributes = TypeAttributes; - builder.MemberAttributes = MemberAttributes; - - Type wrapper = builder.BuildProxyType(); - - proxyConstructor = wrapper.GetConstructor(Type.EmptyTypes); - - #region Instrumentation - - if (LOG.IsDebugEnabled) - { - if (ServiceUri != null) - { - LOG.Debug( - String.Format("Generated client proxy type [{0}] for web service [{1}]", wrapper.FullName, - ServiceUri.Description)); - } - else if (ProxyType != null) - { - LOG.Debug( - String.Format("Generated client proxy type [{0}] for web service based on provided proxy type [{1}]", wrapper.FullName, - ProxyType.FullName)); - } - } - - #endregion - } - - #endregion - - #region Private Methods - - /// - /// Gets XML Web Services documents from a Spring resource. - /// - private DiscoveryClientDocumentCollection GetWsDocuments(IResource resource) - { - try - { - if (ServiceUri is UrlResource || - ServiceUri is FileSystemResource) - { - DiscoveryClientProtocol dcProtocol = new DiscoveryClientProtocol(); - dcProtocol.AllowAutoRedirect = true; - dcProtocol.Credentials = CreateCredentials(); - dcProtocol.Proxy = ConfigureProxy(); - dcProtocol.DiscoverAny(resource.Uri.AbsoluteUri); - dcProtocol.ResolveAll(); - - return dcProtocol.Documents; - } - else - { - DiscoveryClientDocumentCollection dcdc = new DiscoveryClientDocumentCollection(); - dcdc[resource.Description] = ServiceDescription.Read(resource.InputStream); - return dcdc; - } - } - catch (Exception ex) - { - throw new ArgumentException(String.Format("Couldn't retrieve the description of the web service located at '{0}'.", resource.Description), ex); - } - } - - private IWebProxy ConfigureProxy() - { - IWebProxy webProxy = null; - if (ProxyUrl != null) - { - webProxy = new WebProxy(ProxyUrl); - } - if (ProxyCredential != null) - { - if (webProxy == null) - { -#if !NET_2_0 - webProxy = GlobalProxySelection.Select; -#else - webProxy = WebRequest.DefaultWebProxy; -#endif - } - webProxy.Credentials = ProxyCredential; - } - - return webProxy; - } - - private ICredentials CreateCredentials() - { - if (Credential != null) - { - CredentialCache credentialCache = new CredentialCache(); - - Uri wsUri = new Uri(ServiceUri.Uri.AbsoluteUri.Substring(0, ServiceUri.Uri.AbsoluteUri.Length - ServiceUri.Uri.AbsolutePath.Length)); - IEnumerator enumerator = AuthenticationManager.RegisteredModules; - while (enumerator.MoveNext()) - { - credentialCache.Add(wsUri, ((IAuthenticationModule)enumerator.Current).AuthenticationType, Credential); - } - - return credentialCache; - } - else - { - return CredentialCache.DefaultCredentials; - } - } - - #endregion - - #region SoapHttpClientProxyTypeBuilder inner class implementation - - /// - /// Proxy type builder that can be used to create a proxy for - /// derived classes. - /// - private sealed class SoapHttpClientProxyTypeBuilder : AbstractProxyTypeBuilder - { - #region Logging - - private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(SoapHttpClientProxyTypeBuilder)); - - #endregion - - #region Fields - - // Binding/Type related - private IResource serviceUri; - private ServiceDescriptionCollection wsDescriptions; - private XmlSchemaImporter schemaImporter; - private Binding wsBinding; - private string wsUrl; - - // Operation/Method related - private Operation operation; - private OperationBinding operationBinding; - private SoapOperationBinding soapOperationBinding; - private XmlMembersMapping inputMembersMapping; - private XmlMembersMapping outputMembersMapping; - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// The URI that contains the Web Service meta info (WSDL). - /// The XML Web Service documents to use to create the proxy. - /// The name of the Web Service binding to use. - public SoapHttpClientProxyTypeBuilder(IResource serviceUri, - DiscoveryClientDocumentCollection wsDocuments, string bindingName) - { - this.serviceUri = serviceUri; - - Name = "SoapHttpClientProxy"; - ProxyTargetAttributes = false; - - Initialize(wsDocuments, bindingName); - } - - #endregion - - #region IProxyTypeBuilder Members - - /// - /// Creates the proxy type. - /// - /// The generated proxy class. - public override Type BuildProxyType() - { - if (Interfaces == null || Interfaces.Length == 0) - { - throw new ArgumentException( - "Web service client proxy must implement at least one interface."); - } - - TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); - - // apply custom attributes to the proxy type. - ApplyTypeAttributes(typeBuilder, TargetType); - - // create constructors - ImplementConstructors(typeBuilder); - - // implement service interfaces - foreach (Type intf in Interfaces) - { - ImplementInterface(typeBuilder, - new SoapHttpClientProxyMethodBuilder(typeBuilder, this), - intf, TargetType); - } - - return typeBuilder.CreateType(); - } - - #endregion - - #region IProxyTypeGenerator Members - - /// - /// Generates the IL instructions that pushes - /// the target instance on which calls should be delegated to. - /// - /// The IL generator to use. - public override void PushTarget(ILGenerator il) - { - PushProxy(il); - } - - #endregion - - #region Protected Methods - - /// - /// Implements constructors for the proxy class. - /// - /// - /// The to use. - /// - protected override void ImplementConstructors(TypeBuilder builder) - { - MethodAttributes attributes = MethodAttributes.Public | - MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - ConstructorBuilder cb = builder.DefineConstructor(attributes, - CallingConventions.Standard, Type.EmptyTypes); - - ILGenerator il = cb.GetILGenerator(); - - PushProxy(il); - il.Emit(OpCodes.Call, this.BaseType.GetConstructor(Type.EmptyTypes)); - - // Set Url Property - PushProxy(il); - il.Emit(OpCodes.Ldstr, this.wsUrl); - il.Emit(OpCodes.Call, this.BaseType.GetMethod("set_Url", BindingFlags.Public | BindingFlags.Instance)); - - il.Emit(OpCodes.Ret); - } - - protected override void ApplyMethodAttributes( - MethodBuilder methodBuilder, MethodInfo targetMethod) - { - MoveToMethod(targetMethod); - - base.ApplyMethodAttributes(methodBuilder, targetMethod); - } - - protected override IList GetTypeAttributes(Type type) - { - IList attrs = base.GetTypeAttributes(type); - - // Add the WebServiceBindingAttribute - attrs.Add(CreateWebServiceBindingAttribute(this.wsBinding)); - - return attrs; - } - - protected override IList GetMethodAttributes(MethodInfo method) - { - IList attrs = base.GetMethodAttributes(method); - - // Add the SoapMethodAttribute - attrs.Add(CreateSoapMethodAttribute( - operation, operationBinding, soapOperationBinding, inputMembersMapping, outputMembersMapping)); - - return attrs; - } - -#if NET_2_0 - protected override IList GetMethodReturnTypeAttributes(MethodInfo method) - { - IList attrs = base.GetMethodReturnTypeAttributes(method); - - // Add the XmlElementAttribute if needed - if (operation.Messages.Output != null) - { - if (method.ReturnType != typeof(void)) - { - if (outputMembersMapping.Count > 0) - { - XmlMemberMapping outMemberMapping = outputMembersMapping[0]; - bool useMemberName = (outMemberMapping.MemberName != operation.Name + "Result"); - bool useNamespace = outMemberMapping.Namespace != outputMembersMapping.Namespace; - if (useMemberName || useNamespace) - { +#region License + +/* + * Copyright © 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +#region Imports + +using System; +using System.Collections; +using System.Globalization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using System.Net; +using System.Reflection; +using System.Reflection.Emit; +using System.Web.Services; +using System.Web.Services.Description; +using System.Web.Services.Protocols; +using System.Web.Services.Discovery; + +using Spring.Core; +using Spring.Objects.Factory; +using Spring.Objects.Factory.Config; +using Spring.Proxy; +using Spring.Util; +using Spring.Objects; +using Spring.Core.IO; +using Spring.Expressions; + +#endregion + +namespace Spring.Web.Services +{ + /// + /// Factory Object that dynamically implements service interface for web service. + /// + /// + ///

+ /// This factory object should be used to obtain reference to a web service + /// that can be safely cast to a service interface, which allows client code to code + /// against interface, and not directly against the web service. + ///

+ ///

+ /// The WSDL contract needs to conform to WS-I Basic Profiles. + ///

+ ///
+ /// Bruno Baia + /// Aleksandar Seovic + public class WebServiceProxyFactory : IConfigurableFactoryObject, IInitializingObject + { + #region Logging + + private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(WebServiceProxyFactory)); + + #endregion + + #region Fields + + private IObjectDefinition _productTemplate; + private Type _webServiceProxyBaseType = typeof(SoapHttpClientProtocol); + private IResource _serviceUri; + private Type _proxyType; + private Type _serviceInterface; + private NetworkCredential _credential; + private string _proxyUrl; + private NetworkCredential _proxyCredential; + private string _bindingName; + private IList _typeAttributes = new ArrayList(); + private IDictionary _memberAttributes = new Hashtable(); + + /// + /// The web service proxy default constructor. + /// + protected ConstructorInfo proxyConstructor; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public WebServiceProxyFactory() + { + } + + #endregion + + #region Properties + + /// + /// Gets or sets the base type that web service proxy should inherit. + /// + /// + /// Default is + /// + public Type WebServiceProxyBaseType + { + get { return _webServiceProxyBaseType; } + set { _webServiceProxyBaseType = value; } + } + + /// + /// Gets or sets the URI for an + /// that contains the web service description (WSDL). + /// + public IResource ServiceUri + { + get { return _serviceUri; } + set { _serviceUri = value; } + } + + /// + /// Gets or sets type of the proxy class to wrap. + /// + public Type ProxyType + { + get { return _proxyType; } + set { _proxyType = value; } + } + + /// + /// Gets or sets service interface that proxy should implement. + /// + public Type ServiceInterface + { + get { return _serviceInterface; } + set { _serviceInterface = value; } + } + + /// + /// Gets or sets the instance + /// to use when connecting to a server that requires authentication. + /// + public NetworkCredential Credential + { + get { return _credential; } + set { _credential = value; } + } + + /// + /// Gets or sets the url of the proxy server to use for retrieving the WSDL. + /// + /// + ///

+ /// This only applies when using an as uri. + ///

+ ///

+ /// The default is to use the system proxy setting. + ///

+ ///
+ public string ProxyUrl + { + get { return _proxyUrl; } + set { _proxyUrl = value; } + } + + /// + /// Gets or sets the instance + /// to use when connecting to a proxy server that requires authentication. + /// + /// + ///

+ /// This only applies when using an as uri. + ///

+ ///
+ public NetworkCredential ProxyCredential + { + get { return _proxyCredential; } + set { _proxyCredential = value; } + } + + /// + /// Gets or sets the web service binding name to use for the proxy. + /// + public string BindingName + { + get { return _bindingName; } + set { _bindingName = value; } + } + + /// + /// Gets or sets a list of custom attributes + /// that should be applied to a proxy class. + /// + public IList TypeAttributes + { + get { return _typeAttributes; } + set { _typeAttributes = value; } + } + + /// + /// Gets or sets a dictionary of custom attributes + /// that should be applied to web service members. + /// + /// + /// Dictionary key is an expression that members can be matched against. + /// Value is a list of attributes that should be applied + /// to each member that matches expression. + /// + public IDictionary MemberAttributes + { + get { return _memberAttributes; } + set { _memberAttributes = value; } + } + + #endregion + + #region IConfigurableFactoryObject Members + + /// + /// Returns type of the web service proxy. + /// + public virtual Type ObjectType + { + get { return (proxyConstructor != null ? proxyConstructor.DeclaringType : ServiceInterface); } + } + + /// + /// Creates new instance of the web service proxy. + /// + /// New instance of the web service proxy. + public virtual object GetObject() + { + if (proxyConstructor == null) + { + GenerateProxy(); + } + + return ObjectUtils.InstantiateType(proxyConstructor, ObjectUtils.EmptyObjects); + } + + /// + /// Always returns false. + /// + public virtual bool IsSingleton + { + get { return false; } + } + + /// + /// Gets or sets the template object definition + /// that should be used to configure proxy instance. + /// + public virtual IObjectDefinition ProductTemplate + { + get { return _productTemplate; } + set { _productTemplate = value; } + } + + #endregion + + #region IInitializingObject Members + + /// + /// Initializes factory object. + /// + public virtual void AfterPropertiesSet() + { + ValidateConfiguration(); + } + + #endregion + + #region Protected Methods + + /// + /// Validates the configuration. + /// + protected virtual void ValidateConfiguration() + { + if (ServiceUri == null && ProxyType == null) + { + throw new ArgumentException("ServiceUri or ProxyType property is required."); + } + if (ServiceInterface == null) + { + throw new ArgumentException("The ServiceInterface property is required."); + } + if (!ServiceInterface.IsInterface) + { + throw new ArgumentException("ServiceInterface must be an interface"); + } + if (WebServiceProxyBaseType.IsSealed) + { + throw new ArgumentException("Web service client proxy cannot be created for a sealed class [" + WebServiceProxyBaseType.FullName + "]"); + } + } + + /// + /// Generates the web service proxy type. + /// + protected virtual void GenerateProxy() + { + IProxyTypeBuilder builder; + if (ProxyType != null) + { + // Wrap .NET generated proxy class or another + builder = new WebServiceProxyProxyTypeBuilder(); + builder.TargetType = ProxyType; + } + else + { + // Dynamically generates proxy class from WSDL + builder = new SoapHttpClientProxyTypeBuilder( + ServiceUri, GetWsDocuments(ServiceUri), BindingName); + builder.BaseType = WebServiceProxyBaseType; + } + + builder.Interfaces = ReflectionUtils.ToInterfaceArray(ServiceInterface); + builder.TypeAttributes = TypeAttributes; + builder.MemberAttributes = MemberAttributes; + + Type wrapper = builder.BuildProxyType(); + + proxyConstructor = wrapper.GetConstructor(Type.EmptyTypes); + + #region Instrumentation + + if (LOG.IsDebugEnabled) + { + if (ServiceUri != null) + { + LOG.Debug( + String.Format("Generated client proxy type [{0}] for web service [{1}]", wrapper.FullName, + ServiceUri.Description)); + } + else if (ProxyType != null) + { + LOG.Debug( + String.Format("Generated client proxy type [{0}] for web service based on provided proxy type [{1}]", wrapper.FullName, + ProxyType.FullName)); + } + } + + #endregion + } + + #endregion + + #region Private Methods + + /// + /// Gets XML Web Services documents from a Spring resource. + /// + private DiscoveryClientDocumentCollection GetWsDocuments(IResource resource) + { + try + { + if (ServiceUri is UrlResource || + ServiceUri is FileSystemResource) + { + DiscoveryClientProtocol dcProtocol = new DiscoveryClientProtocol(); + dcProtocol.AllowAutoRedirect = true; + dcProtocol.Credentials = CreateCredentials(); + dcProtocol.Proxy = ConfigureProxy(); + dcProtocol.DiscoverAny(resource.Uri.AbsoluteUri); + dcProtocol.ResolveAll(); + + return dcProtocol.Documents; + } + else + { + DiscoveryClientDocumentCollection dcdc = new DiscoveryClientDocumentCollection(); + dcdc[resource.Description] = ServiceDescription.Read(resource.InputStream); + return dcdc; + } + } + catch (Exception ex) + { + throw new ArgumentException(String.Format("Couldn't retrieve the description of the web service located at '{0}'.", resource.Description), ex); + } + } + + private IWebProxy ConfigureProxy() + { + IWebProxy webProxy = null; + if (ProxyUrl != null) + { + webProxy = new WebProxy(ProxyUrl); + } + if (ProxyCredential != null) + { + if (webProxy == null) + { +#if !NET_2_0 + webProxy = GlobalProxySelection.Select; +#else + webProxy = WebRequest.DefaultWebProxy; +#endif + } + webProxy.Credentials = ProxyCredential; + } + + return webProxy; + } + + private ICredentials CreateCredentials() + { + if (Credential != null) + { + CredentialCache credentialCache = new CredentialCache(); + + Uri wsUri = new Uri(ServiceUri.Uri.AbsoluteUri.Substring(0, ServiceUri.Uri.AbsoluteUri.Length - ServiceUri.Uri.AbsolutePath.Length)); + IEnumerator enumerator = AuthenticationManager.RegisteredModules; + while (enumerator.MoveNext()) + { + credentialCache.Add(wsUri, ((IAuthenticationModule)enumerator.Current).AuthenticationType, Credential); + } + + return credentialCache; + } + else + { + return CredentialCache.DefaultCredentials; + } + } + + #endregion + + #region SoapHttpClientProxyTypeBuilder inner class implementation + + /// + /// Proxy type builder that can be used to create a proxy for + /// derived classes. + /// + private sealed class SoapHttpClientProxyTypeBuilder : AbstractProxyTypeBuilder + { + #region Logging + + private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(SoapHttpClientProxyTypeBuilder)); + + #endregion + + #region Fields + + // Binding/Type related + private IResource serviceUri; + private ServiceDescriptionCollection wsDescriptions; + private XmlSchemaImporter schemaImporter; + private Binding wsBinding; + private string wsUrl; + + // Operation/Method related + private Operation operation; + private OperationBinding operationBinding; + private SoapOperationBinding soapOperationBinding; + private XmlMembersMapping inputMembersMapping; + private XmlMembersMapping outputMembersMapping; + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + /// The URI that contains the Web Service meta info (WSDL). + /// The XML Web Service documents to use to create the proxy. + /// The name of the Web Service binding to use. + public SoapHttpClientProxyTypeBuilder(IResource serviceUri, + DiscoveryClientDocumentCollection wsDocuments, string bindingName) + { + this.serviceUri = serviceUri; + + Name = "SoapHttpClientProxy"; + ProxyTargetAttributes = false; + + Initialize(wsDocuments, bindingName); + } + + #endregion + + #region IProxyTypeBuilder Members + + /// + /// Creates the proxy type. + /// + /// The generated proxy class. + public override Type BuildProxyType() + { + if (Interfaces == null || Interfaces.Length == 0) + { + throw new ArgumentException( + "Web service client proxy must implement at least one interface."); + } + + TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType); + + // apply custom attributes to the proxy type. + ApplyTypeAttributes(typeBuilder, TargetType); + + // create constructors + ImplementConstructors(typeBuilder); + + // implement service interfaces + foreach (Type intf in Interfaces) + { + ImplementInterface(typeBuilder, + new SoapHttpClientProxyMethodBuilder(typeBuilder, this), + intf, TargetType); + } + + return typeBuilder.CreateType(); + } + + #endregion + + #region IProxyTypeGenerator Members + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + public override void PushTarget(ILGenerator il) + { + PushProxy(il); + } + + #endregion + + #region Protected Methods + + /// + /// Implements constructors for the proxy class. + /// + /// + /// The to use. + /// + protected override void ImplementConstructors(TypeBuilder builder) + { + MethodAttributes attributes = MethodAttributes.Public | + MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + ConstructorBuilder cb = builder.DefineConstructor(attributes, + CallingConventions.Standard, Type.EmptyTypes); + + ILGenerator il = cb.GetILGenerator(); + + PushProxy(il); + il.Emit(OpCodes.Call, this.BaseType.GetConstructor(Type.EmptyTypes)); + + // Set Url Property + PushProxy(il); + il.Emit(OpCodes.Ldstr, this.wsUrl); + il.Emit(OpCodes.Call, this.BaseType.GetMethod("set_Url", BindingFlags.Public | BindingFlags.Instance)); + + il.Emit(OpCodes.Ret); + } + + protected override void ApplyMethodAttributes( + MethodBuilder methodBuilder, MethodInfo targetMethod) + { + MoveToMethod(targetMethod); + + base.ApplyMethodAttributes(methodBuilder, targetMethod); + } + + protected override IList GetTypeAttributes(Type type) + { + IList attrs = base.GetTypeAttributes(type); + + // Add the WebServiceBindingAttribute + attrs.Add(CreateWebServiceBindingAttribute(this.wsBinding)); + + return attrs; + } + + protected override IList GetMethodAttributes(MethodInfo method) + { + IList attrs = base.GetMethodAttributes(method); + + // Add the SoapMethodAttribute + attrs.Add(CreateSoapMethodAttribute( + operation, operationBinding, soapOperationBinding, inputMembersMapping, outputMembersMapping)); + + return attrs; + } + +#if NET_2_0 + protected override IList GetMethodReturnTypeAttributes(MethodInfo method) + { + IList attrs = base.GetMethodReturnTypeAttributes(method); + + // Add the XmlElementAttribute if needed + if (operation.Messages.Output != null) + { + if (method.ReturnType != typeof(void)) + { + if (outputMembersMapping.Count > 0) + { + XmlMemberMapping outMemberMapping = outputMembersMapping[0]; + bool useMemberName = (outMemberMapping.MemberName != operation.Name + "Result"); + bool useNamespace = outMemberMapping.Namespace != outputMembersMapping.Namespace; + if (useMemberName || useNamespace) + { ReflectionUtils.CustomAttributeBuilderBuilder cabb; if (outMemberMapping.TypeName.StartsWith ("ArrayOf", StringComparison.Ordinal)) { cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(XmlArrayAttribute)); - } + } else { cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(XmlElementAttribute)); - } - if (useMemberName) - { - cabb.AddPropertyValue("ElementName", outMemberMapping.MemberName); - } - if (useNamespace) - { - cabb.AddPropertyValue("Namespace", outMemberMapping.Namespace); - } - - attrs.Add(cabb.Build()); - } - } - } - } - - return attrs; - } -#endif -/* - protected override IList GetMethodParameterAttributes(MethodInfo method, ParameterInfo paramInfo) - { - IList attrs = base.GetMethodParameterAttributes(method, paramInfo); - - // Add the XmlElementAttribute if needed - XmlMemberMapping inMemberMapping = inputMembersMapping[paramInfo.Position]; - if (inMemberMapping.Namespace != inputMembersMapping.Namespace) - { - CustomAttributeBuilderBuilder cabb = - new CustomAttributeBuilderBuilder(typeof(XmlElementAttribute)); - cabb.AddPropertyValue("Namespace", inMemberMapping.Namespace); - - attrs.Add(cabb.Build()); - } - - return attrs; - } -*/ - - #endregion - - #region Private Methods - - private void Initialize(DiscoveryClientDocumentCollection wsDocuments, string bindingName) - { - // Service descriptions - this.wsDescriptions = new ServiceDescriptionCollection(); - XmlSchemas schemas = new XmlSchemas(); - foreach (DictionaryEntry entry in wsDocuments) - { - if (entry.Value is ServiceDescription) - { - this.wsDescriptions.Add((ServiceDescription)entry.Value); - } - if (entry.Value is XmlSchema) - { - schemas.Add((XmlSchema)entry.Value); - } - } - - // XmlSchemaImporter - foreach (ServiceDescription serviceDescription in this.wsDescriptions) - { - foreach (XmlSchema schema in serviceDescription.Types.Schemas) - { - if (schemas[schema.TargetNamespace] == null) - { - schemas.Add(schema); - } - } - } - this.schemaImporter = new XmlSchemaImporter(schemas); - - this.wsBinding = GetWsBinding(this.wsDescriptions, bindingName); - this.wsUrl = GetWsUrl(this.wsDescriptions, this.wsBinding); - } - - /// - /// Search and returns the binding for the specified name. - /// - private Binding GetWsBinding(ServiceDescriptionCollection serviceDescriptions, string bindingName) - { - if (bindingName != null) - { - // Search for a specific binding - foreach (ServiceDescription description in serviceDescriptions) - { - foreach (Binding binding in description.Bindings) - { - if (binding.Name == bindingName) - { - return binding; - } - } - } - throw new ApplicationException(String.Format("Binding '{0}' does not exist in the WSDL document located at '{1}'", bindingName, this.serviceUri.Description)); - } - else - { - // Use the first one - foreach (ServiceDescription description in serviceDescriptions) - { - foreach (Binding binding in description.Bindings) - { - #region Instrumentation - - if (LOG.IsInfoEnabled) - { - LOG.Info(String.Format("The binding '{0}', found in the WSDL document located at '{1}', will be use.", binding.Name, this.serviceUri.Description)); - } - - #endregion - - return binding; - } - } - throw new ApplicationException(String.Format("No bindings exists in the WSDL document located at '{0}'", this.serviceUri.Description)); - } - } - - /// - /// Search and returns the url for the specified binding. - /// - private string GetWsUrl(ServiceDescriptionCollection serviceDescriptions, Binding binding) - { - foreach (ServiceDescription description in serviceDescriptions) - { - foreach (Service service in description.Services) - { - foreach (Port port in service.Ports) - { - if (port.Binding.Name == binding.Name) - { - SoapAddressBinding soapAddress = (SoapAddressBinding)port.Extensions.Find(typeof(SoapAddressBinding)); - return soapAddress.Location; - } - } - } - } - throw new ApplicationException(String.Format("No SoapAddressBinding has been found for binding '{0}' in the WSDL document located at '{1}'.", binding.Name, serviceUri)); - } - - /// - /// Search and returns the operation that matches the specified method. - /// - private Operation GetOperation(ServiceDescriptionCollection descriptions, Binding binding, MethodInfo method) - { - PortType portType = descriptions.GetPortType(binding.Type); - foreach (Operation operation in portType.Operations) - { - if (operation.Name == method.Name) - { - return operation; - } - } - throw new ApplicationException(String.Format("No Operation has been found for the method '{0}' in the WSDL document located at '{1}'.", method.Name, serviceUri.Description)); - } - - /// - /// Search and returns the OperationBinding that matches the specified Operation. - /// - private OperationBinding GetOperationBinding(Operation operation, Binding binding) - { - foreach (OperationBinding operationBinding in binding.Operations) - { - if (operation.IsBoundBy(operationBinding)) - { - return operationBinding; - } - } - throw new ApplicationException(String.Format("No OperationBinding matches the Operation '{0}' in the WSDL document located at '{2}'.", operation.Name, this.serviceUri.Description)); - } - - /// - /// Search and returns the type mapping between method parameters/return value - /// and the element parts of a literal-use SOAP message. - /// - private XmlMembersMapping GetMembersMapping(string messageName, MessagePartCollection messageParts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle) - { -#if NET_2_0 - if (soapBindingStyle == SoapBindingStyle.Rpc) - { - SoapSchemaMember[] soapSchemaMembers = new SoapSchemaMember[messageParts.Count]; - for (int i = 0; i < messageParts.Count; i++) - { - SoapSchemaMember ssm = new SoapSchemaMember(); - ssm.MemberName = messageParts[i].Name; - ssm.MemberType = messageParts[i].Type; - soapSchemaMembers[i] = ssm; - } - return this.schemaImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, soapSchemaMembers); - } - else - { - return this.schemaImporter.ImportMembersMapping(messageParts[0].Element); - } -#else - return this.schemaImporter.ImportMembersMapping(messageParts[0].Element); -#endif - } - - private void MoveToMethod(MethodInfo targetMethod) - { - operation = GetOperation(this.wsDescriptions, this.wsBinding, targetMethod); - operationBinding = GetOperationBinding(operation, this.wsBinding); - soapOperationBinding = (SoapOperationBinding)operationBinding.Extensions.Find(typeof(SoapOperationBinding)); - - string inputMessageName = (!StringUtils.IsNullOrEmpty(operationBinding.Input.Name) && (soapOperationBinding.Style != SoapBindingStyle.Rpc)) ? operationBinding.Input.Name : operation.Name; - SoapBodyBinding inputSoapBodyBinding = (SoapBodyBinding)operationBinding.Input.Extensions.Find(typeof(SoapBodyBinding)); - -#if !NET_2_0 - if (soapOperationBinding.Style == SoapBindingStyle.Rpc && - inputSoapBodyBinding.Use == SoapBindingUse.Literal) - { - throw new NotSupportedException("rpc-literal SOAP messages are not supported on .NET Framework 1.1"); - } -#endif - if (inputSoapBodyBinding.Use != SoapBindingUse.Literal) - { - throw new NotSupportedException("WebServiceProxyFactory only supports document-literal and rpc-literal SOAP messages to conform to WS-I Basic Profiles."); - } - - Message inputMessage = this.wsDescriptions.GetMessage(operation.Messages.Input.Message); - inputMembersMapping = GetMembersMapping(inputMessageName, inputMessage.Parts, inputSoapBodyBinding, soapOperationBinding.Style); - - outputMembersMapping = null; - if (operation.Messages.Output != null) - { - string outputMessageName = (!StringUtils.IsNullOrEmpty(operationBinding.Output.Name) && (soapOperationBinding.Style != SoapBindingStyle.Rpc)) ? operationBinding.Output.Name : (operation.Name + "Response"); - SoapBodyBinding outputSoapBodyBinding = (SoapBodyBinding)operationBinding.Output.Extensions.Find(typeof(SoapBodyBinding)); - Message outputMessage = this.wsDescriptions.GetMessage(operation.Messages.Output.Message); - outputMembersMapping = GetMembersMapping(outputMessageName, outputMessage.Parts, outputSoapBodyBinding, soapOperationBinding.Style); - } - } - - /// - /// Creates a that should be applied to proxy type. - /// - private CustomAttributeBuilder CreateWebServiceBindingAttribute(Binding wsBinding) - { - ReflectionUtils.CustomAttributeBuilderBuilder cabb = - new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(WebServiceBindingAttribute)); - - cabb.AddContructorArgument(this.wsBinding.Name); - cabb.AddPropertyValue("Namespace", this.wsBinding.ServiceDescription.TargetNamespace); - - return cabb.Build(); - } - -#if !NET_2_0 - private static readonly PropertyInfo XmlMembersMapping_ElementName = - typeof(XmlMembersMapping).GetProperty("ElementName"); - - private static readonly PropertyInfo XmlMembersMapping_Namespace = - typeof(XmlMembersMapping).GetProperty("Namespace"); -#endif - - /// - /// Creates a or a - /// that should be applied to proxy method. - /// - private static CustomAttributeBuilder CreateSoapMethodAttribute(Operation operation, - OperationBinding operationBinding, SoapOperationBinding soapOperationBinding, - XmlMembersMapping inputMembersMapping, XmlMembersMapping outputMembersMapping) - { - ReflectionUtils.CustomAttributeBuilderBuilder cabb; - -#if !NET_2_0 - // Access XmlMembersMapping.ElementName and .Namespace property using reflection [SPRNET-520] - string inputMembersMappingElementName = XmlMembersMapping_ElementName.GetValue(inputMembersMapping, null) as string; - string inputMembersMappingNamespace = XmlMembersMapping_Namespace.GetValue(inputMembersMapping, null) as string; -#else - string inputMembersMappingElementName = inputMembersMapping.ElementName; - string inputMembersMappingNamespace = inputMembersMapping.Namespace; -#endif - - if (soapOperationBinding.Style == SoapBindingStyle.Rpc) - { - cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(SoapRpcMethodAttribute)); - } - else - { - cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(SoapDocumentMethodAttribute)); - cabb.AddPropertyValue("ParameterStyle", SoapParameterStyle.Wrapped); - } - - cabb.AddContructorArgument(soapOperationBinding.SoapAction); - -#if NET_2_0 - cabb.AddPropertyValue("Use", SoapBindingUse.Literal); -#else - if (soapOperationBinding.Style != SoapBindingStyle.Rpc) - { - cabb.AddPropertyValue("Use", SoapBindingUse.Literal); - } -#endif - - if (inputMembersMappingElementName.Length > 0 && - inputMembersMappingElementName != operation.Name) - { - cabb.AddPropertyValue("RequestElementName", inputMembersMappingElementName); - } - - if (inputMembersMappingNamespace != null) - { - cabb.AddPropertyValue("RequestNamespace", inputMembersMappingNamespace); - } - - if (outputMembersMapping == null) - { - cabb.AddPropertyValue("OneWay", true); - } - else - { -#if !NET_2_0 - // Access XmlMembersMapping.ElementName and .Namespace property using reflection [SPRNET-520] - string outputMembersMappingElementName = XmlMembersMapping_ElementName.GetValue(outputMembersMapping, null) as string; - string outputMembersMappingNamespace = XmlMembersMapping_Namespace.GetValue(outputMembersMapping, null) as string; -#else - string outputMembersMappingElementName = outputMembersMapping.ElementName; - string outputMembersMappingNamespace = outputMembersMapping.Namespace; -#endif - if (outputMembersMappingElementName.Length > 0 && - outputMembersMappingElementName != (operation.Name + "Response")) - { - cabb.AddPropertyValue("ResponseElementName", outputMembersMappingElementName); - } - - if (outputMembersMappingNamespace != null) - { - cabb.AddPropertyValue("ResponseNamespace", outputMembersMappingNamespace); - } - } - - return cabb.Build(); - } - - #endregion - - #region SoapHttpClientProxyMethodBuilder inner class implementation - - /// - /// Proxy method builder that can be used to create a proxy method - /// for web services operation invocation. - /// - private sealed class SoapHttpClientProxyMethodBuilder : AbstractProxyMethodBuilder - { - #region Fields - - private static readonly MethodInfo Invoke = - typeof(SoapHttpClientProtocol).GetMethod("Invoke", BindingFlags.NonPublic | BindingFlags.Instance); - - #endregion - - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - public SoapHttpClientProxyMethodBuilder( - TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator) - : base(typeBuilder, proxyGenerator, false) - { - } - - #endregion - - #region Protected Methods - - /// - /// Generates the proxy method. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void GenerateMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - // In Parameters - ArrayList inParams = new ArrayList(); - // Ref or Out Parameters - ArrayList refOutParams = new ArrayList(); - - foreach (ParameterInfo paramInfo in interfaceMethod.GetParameters()) - { - if (paramInfo.IsRetval || paramInfo.IsOut) - { - refOutParams.Add(paramInfo); - } - else - { - inParams.Add(paramInfo); - } - } - - proxyGenerator.PushTarget(il); - - // Parameter #1 - il.Emit(OpCodes.Ldstr, interfaceMethod.Name); - - // Parameter #2 - LocalBuilder parameters = il.DeclareLocal(typeof(Object[])); - il.Emit(OpCodes.Ldc_I4, inParams.Count); - il.Emit(OpCodes.Newarr, typeof(Object)); - il.Emit(OpCodes.Stloc, parameters); - - int paramIndex = 0; - foreach (ParameterInfo paramInfo in inParams) - { - il.Emit(OpCodes.Ldloc, parameters); - il.Emit(OpCodes.Ldc_I4, paramIndex); - il.Emit(OpCodes.Ldarg, paramInfo.Position + 1); - if (paramInfo.ParameterType.IsValueType) - { - il.Emit(OpCodes.Box, paramInfo.ParameterType); - } - il.Emit(OpCodes.Stelem_Ref); - - paramIndex++; - } - - il.Emit(OpCodes.Ldloc, parameters); - - // Call Invoke method and save result - LocalBuilder results = il.DeclareLocal(typeof(Object[])); - il.EmitCall(OpCodes.Callvirt, Invoke, null); - il.Emit(OpCodes.Stloc, results); - - int resultIndex = (interfaceMethod.ReturnType == typeof(void) ? 0 : 1); - foreach (ParameterInfo paramInfo in refOutParams) - { - il.Emit(OpCodes.Ldarg, paramInfo.Position + 1); - il.Emit(OpCodes.Ldloc, results); - - // Cast / Unbox the return value - il.Emit(OpCodes.Ldc_I4, resultIndex); - il.Emit(OpCodes.Ldelem_Ref); - - Type elementType = paramInfo.ParameterType.GetElementType(); - if (elementType.IsValueType) - { - il.Emit(OpCodes.Unbox, elementType); - il.Emit(OpCodes.Ldobj, elementType); - il.Emit(OpCodes.Stobj, elementType); - } - else - { - il.Emit(OpCodes.Castclass, elementType); - il.Emit(OpCodes.Stind_Ref); - } - - resultIndex++; - } - - if (interfaceMethod.ReturnType != typeof(void)) - { - il.Emit(OpCodes.Ldloc, results); - - // Cast / Unbox the return value - il.Emit(OpCodes.Ldc_I4_0); - il.Emit(OpCodes.Ldelem_Ref); - if (interfaceMethod.ReturnType.IsValueType) - { - il.Emit(OpCodes.Unbox, interfaceMethod.ReturnType); - il.Emit(OpCodes.Ldobj, interfaceMethod.ReturnType); - } - else - { - il.Emit(OpCodes.Castclass, interfaceMethod.ReturnType); - } - } - } - - #endregion - } - - #endregion - } - - #endregion - - #region WebServiceProxyProxyTypeBuilder inner class implementation - - /// - /// Proxy type builder that can be used to create a proxy for - /// .Net-generated proxy class that can be safely cast to a service interface. - /// - private sealed class WebServiceProxyProxyTypeBuilder : InheritanceProxyTypeBuilder - { - #region Constructor(s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public WebServiceProxyProxyTypeBuilder() - { - this.Name = "WebServiceProxyProxy"; - } - - #endregion - - #region Protected Methods - - /// - /// Gets the mapping of the interface to proxy - /// into the actual methods on the target type - /// that does not need to implement that interface. - /// - /// - ///

- /// As the proxy type does not implement the interface, - /// we try to find matching methods. - ///

- ///
- /// - /// The of the target object. - /// - /// The interface to implement. - /// - /// An interface mapping for the interface to proxy. - /// - protected override InterfaceMapping GetInterfaceMapping( - Type targetType, Type intf) - { - InterfaceMapping mapping; - - mapping.TargetType = targetType; - mapping.InterfaceType = intf; - mapping.InterfaceMethods = intf.GetMethods(); - mapping.TargetMethods = ReflectionUtils.GetMatchingMethods( - targetType, mapping.InterfaceMethods, true); - - return mapping; - } - - #endregion - } - - #endregion - } + } + if (useMemberName) + { + cabb.AddPropertyValue("ElementName", outMemberMapping.MemberName); + } + if (useNamespace) + { + cabb.AddPropertyValue("Namespace", outMemberMapping.Namespace); + } + + attrs.Add(cabb.Build()); + } + } + } + } + + return attrs; + } +#endif +/* + protected override IList GetMethodParameterAttributes(MethodInfo method, ParameterInfo paramInfo) + { + IList attrs = base.GetMethodParameterAttributes(method, paramInfo); + + // Add the XmlElementAttribute if needed + XmlMemberMapping inMemberMapping = inputMembersMapping[paramInfo.Position]; + if (inMemberMapping.Namespace != inputMembersMapping.Namespace) + { + CustomAttributeBuilderBuilder cabb = + new CustomAttributeBuilderBuilder(typeof(XmlElementAttribute)); + cabb.AddPropertyValue("Namespace", inMemberMapping.Namespace); + + attrs.Add(cabb.Build()); + } + + return attrs; + } +*/ + + #endregion + + #region Private Methods + + private void Initialize(DiscoveryClientDocumentCollection wsDocuments, string bindingName) + { + // Service descriptions + this.wsDescriptions = new ServiceDescriptionCollection(); + XmlSchemas schemas = new XmlSchemas(); + foreach (DictionaryEntry entry in wsDocuments) + { + if (entry.Value is ServiceDescription) + { + this.wsDescriptions.Add((ServiceDescription)entry.Value); + } + if (entry.Value is XmlSchema) + { + schemas.Add((XmlSchema)entry.Value); + } + } + + // XmlSchemaImporter + foreach (ServiceDescription serviceDescription in this.wsDescriptions) + { + foreach (XmlSchema schema in serviceDescription.Types.Schemas) + { + if (schemas[schema.TargetNamespace] == null) + { + schemas.Add(schema); + } + } + } + this.schemaImporter = new XmlSchemaImporter(schemas); + + this.wsBinding = GetWsBinding(this.wsDescriptions, bindingName); + this.wsUrl = GetWsUrl(this.wsDescriptions, this.wsBinding); + } + + /// + /// Search and returns the binding for the specified name. + /// + private Binding GetWsBinding(ServiceDescriptionCollection serviceDescriptions, string bindingName) + { + if (bindingName != null) + { + // Search for a specific binding + foreach (ServiceDescription description in serviceDescriptions) + { + foreach (Binding binding in description.Bindings) + { + if (binding.Name == bindingName) + { + return binding; + } + } + } + throw new ApplicationException(String.Format("Binding '{0}' does not exist in the WSDL document located at '{1}'", bindingName, this.serviceUri.Description)); + } + else + { + // Use the first one + foreach (ServiceDescription description in serviceDescriptions) + { + foreach (Binding binding in description.Bindings) + { + #region Instrumentation + + if (LOG.IsInfoEnabled) + { + LOG.Info(String.Format("The binding '{0}', found in the WSDL document located at '{1}', will be use.", binding.Name, this.serviceUri.Description)); + } + + #endregion + + return binding; + } + } + throw new ApplicationException(String.Format("No bindings exists in the WSDL document located at '{0}'", this.serviceUri.Description)); + } + } + + /// + /// Search and returns the url for the specified binding. + /// + private string GetWsUrl(ServiceDescriptionCollection serviceDescriptions, Binding binding) + { + foreach (ServiceDescription description in serviceDescriptions) + { + foreach (Service service in description.Services) + { + foreach (Port port in service.Ports) + { + if (port.Binding.Name == binding.Name) + { + SoapAddressBinding soapAddress = (SoapAddressBinding)port.Extensions.Find(typeof(SoapAddressBinding)); + return soapAddress.Location; + } + } + } + } + throw new ApplicationException(String.Format("No SoapAddressBinding has been found for binding '{0}' in the WSDL document located at '{1}'.", binding.Name, serviceUri)); + } + + /// + /// Search and returns the operation that matches the specified method. + /// + private Operation GetOperation(ServiceDescriptionCollection descriptions, Binding binding, MethodInfo method) + { + PortType portType = descriptions.GetPortType(binding.Type); + foreach (Operation operation in portType.Operations) + { + if (operation.Name == method.Name) + { + return operation; + } + } + throw new ApplicationException(String.Format("No Operation has been found for the method '{0}' in the WSDL document located at '{1}'.", method.Name, serviceUri.Description)); + } + + /// + /// Search and returns the OperationBinding that matches the specified Operation. + /// + private OperationBinding GetOperationBinding(Operation operation, Binding binding) + { + foreach (OperationBinding operationBinding in binding.Operations) + { + if (operation.IsBoundBy(operationBinding)) + { + return operationBinding; + } + } + throw new ApplicationException(String.Format("No OperationBinding matches the Operation '{0}' in the WSDL document located at '{2}'.", operation.Name, this.serviceUri.Description)); + } + + /// + /// Search and returns the type mapping between method parameters/return value + /// and the element parts of a literal-use SOAP message. + /// + private XmlMembersMapping GetMembersMapping(string messageName, MessagePartCollection messageParts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle) + { +#if NET_2_0 + if (soapBindingStyle == SoapBindingStyle.Rpc) + { + SoapSchemaMember[] soapSchemaMembers = new SoapSchemaMember[messageParts.Count]; + for (int i = 0; i < messageParts.Count; i++) + { + SoapSchemaMember ssm = new SoapSchemaMember(); + ssm.MemberName = messageParts[i].Name; + ssm.MemberType = messageParts[i].Type; + soapSchemaMembers[i] = ssm; + } + return this.schemaImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, soapSchemaMembers); + } + else + { + return this.schemaImporter.ImportMembersMapping(messageParts[0].Element); + } +#else + return this.schemaImporter.ImportMembersMapping(messageParts[0].Element); +#endif + } + + private void MoveToMethod(MethodInfo targetMethod) + { + operation = GetOperation(this.wsDescriptions, this.wsBinding, targetMethod); + operationBinding = GetOperationBinding(operation, this.wsBinding); + soapOperationBinding = (SoapOperationBinding)operationBinding.Extensions.Find(typeof(SoapOperationBinding)); + + string inputMessageName = (!StringUtils.IsNullOrEmpty(operationBinding.Input.Name) && (soapOperationBinding.Style != SoapBindingStyle.Rpc)) ? operationBinding.Input.Name : operation.Name; + SoapBodyBinding inputSoapBodyBinding = (SoapBodyBinding)operationBinding.Input.Extensions.Find(typeof(SoapBodyBinding)); + +#if !NET_2_0 + if (soapOperationBinding.Style == SoapBindingStyle.Rpc && + inputSoapBodyBinding.Use == SoapBindingUse.Literal) + { + throw new NotSupportedException("rpc-literal SOAP messages are not supported on .NET Framework 1.1"); + } +#endif + if (inputSoapBodyBinding.Use != SoapBindingUse.Literal) + { + throw new NotSupportedException("WebServiceProxyFactory only supports document-literal and rpc-literal SOAP messages to conform to WS-I Basic Profiles."); + } + + Message inputMessage = this.wsDescriptions.GetMessage(operation.Messages.Input.Message); + inputMembersMapping = GetMembersMapping(inputMessageName, inputMessage.Parts, inputSoapBodyBinding, soapOperationBinding.Style); + + outputMembersMapping = null; + if (operation.Messages.Output != null) + { + string outputMessageName = (!StringUtils.IsNullOrEmpty(operationBinding.Output.Name) && (soapOperationBinding.Style != SoapBindingStyle.Rpc)) ? operationBinding.Output.Name : (operation.Name + "Response"); + SoapBodyBinding outputSoapBodyBinding = (SoapBodyBinding)operationBinding.Output.Extensions.Find(typeof(SoapBodyBinding)); + Message outputMessage = this.wsDescriptions.GetMessage(operation.Messages.Output.Message); + outputMembersMapping = GetMembersMapping(outputMessageName, outputMessage.Parts, outputSoapBodyBinding, soapOperationBinding.Style); + } + } + + /// + /// Creates a that should be applied to proxy type. + /// + private CustomAttributeBuilder CreateWebServiceBindingAttribute(Binding wsBinding) + { + ReflectionUtils.CustomAttributeBuilderBuilder cabb = + new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(WebServiceBindingAttribute)); + + cabb.AddContructorArgument(this.wsBinding.Name); + cabb.AddPropertyValue("Namespace", this.wsBinding.ServiceDescription.TargetNamespace); + + return cabb.Build(); + } + +#if !NET_2_0 + private static readonly PropertyInfo XmlMembersMapping_ElementName = + typeof(XmlMembersMapping).GetProperty("ElementName"); + + private static readonly PropertyInfo XmlMembersMapping_Namespace = + typeof(XmlMembersMapping).GetProperty("Namespace"); +#endif + + /// + /// Creates a or a + /// that should be applied to proxy method. + /// + private static CustomAttributeBuilder CreateSoapMethodAttribute(Operation operation, + OperationBinding operationBinding, SoapOperationBinding soapOperationBinding, + XmlMembersMapping inputMembersMapping, XmlMembersMapping outputMembersMapping) + { + ReflectionUtils.CustomAttributeBuilderBuilder cabb; + +#if !NET_2_0 + // Access XmlMembersMapping.ElementName and .Namespace property using reflection [SPRNET-520] + string inputMembersMappingElementName = XmlMembersMapping_ElementName.GetValue(inputMembersMapping, null) as string; + string inputMembersMappingNamespace = XmlMembersMapping_Namespace.GetValue(inputMembersMapping, null) as string; +#else + string inputMembersMappingElementName = inputMembersMapping.ElementName; + string inputMembersMappingNamespace = inputMembersMapping.Namespace; +#endif + + if (soapOperationBinding.Style == SoapBindingStyle.Rpc) + { + cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(SoapRpcMethodAttribute)); + } + else + { + cabb = new ReflectionUtils.CustomAttributeBuilderBuilder(typeof(SoapDocumentMethodAttribute)); + cabb.AddPropertyValue("ParameterStyle", SoapParameterStyle.Wrapped); + } + + cabb.AddContructorArgument(soapOperationBinding.SoapAction); + +#if NET_2_0 + cabb.AddPropertyValue("Use", SoapBindingUse.Literal); +#else + if (soapOperationBinding.Style != SoapBindingStyle.Rpc) + { + cabb.AddPropertyValue("Use", SoapBindingUse.Literal); + } +#endif + + if (inputMembersMappingElementName.Length > 0 && + inputMembersMappingElementName != operation.Name) + { + cabb.AddPropertyValue("RequestElementName", inputMembersMappingElementName); + } + + if (inputMembersMappingNamespace != null) + { + cabb.AddPropertyValue("RequestNamespace", inputMembersMappingNamespace); + } + + if (outputMembersMapping == null) + { + cabb.AddPropertyValue("OneWay", true); + } + else + { +#if !NET_2_0 + // Access XmlMembersMapping.ElementName and .Namespace property using reflection [SPRNET-520] + string outputMembersMappingElementName = XmlMembersMapping_ElementName.GetValue(outputMembersMapping, null) as string; + string outputMembersMappingNamespace = XmlMembersMapping_Namespace.GetValue(outputMembersMapping, null) as string; +#else + string outputMembersMappingElementName = outputMembersMapping.ElementName; + string outputMembersMappingNamespace = outputMembersMapping.Namespace; +#endif + if (outputMembersMappingElementName.Length > 0 && + outputMembersMappingElementName != (operation.Name + "Response")) + { + cabb.AddPropertyValue("ResponseElementName", outputMembersMappingElementName); + } + + if (outputMembersMappingNamespace != null) + { + cabb.AddPropertyValue("ResponseNamespace", outputMembersMappingNamespace); + } + } + + return cabb.Build(); + } + + #endregion + + #region SoapHttpClientProxyMethodBuilder inner class implementation + + /// + /// Proxy method builder that can be used to create a proxy method + /// for web services operation invocation. + /// + private sealed class SoapHttpClientProxyMethodBuilder : AbstractProxyMethodBuilder + { + #region Fields + + private static readonly MethodInfo Invoke = + typeof(SoapHttpClientProtocol).GetMethod("Invoke", BindingFlags.NonPublic | BindingFlags.Instance); + + #endregion + + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + public SoapHttpClientProxyMethodBuilder( + TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator) + : base(typeBuilder, proxyGenerator, false) + { + } + + #endregion + + #region Protected Methods + + /// + /// Generates the proxy method. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void GenerateMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + // In Parameters + ArrayList inParams = new ArrayList(); + // Ref or Out Parameters + ArrayList refOutParams = new ArrayList(); + + foreach (ParameterInfo paramInfo in interfaceMethod.GetParameters()) + { + if (paramInfo.IsRetval || paramInfo.IsOut) + { + refOutParams.Add(paramInfo); + } + else + { + inParams.Add(paramInfo); + } + } + + proxyGenerator.PushTarget(il); + + // Parameter #1 + il.Emit(OpCodes.Ldstr, interfaceMethod.Name); + + // Parameter #2 + LocalBuilder parameters = il.DeclareLocal(typeof(Object[])); + il.Emit(OpCodes.Ldc_I4, inParams.Count); + il.Emit(OpCodes.Newarr, typeof(Object)); + il.Emit(OpCodes.Stloc, parameters); + + int paramIndex = 0; + foreach (ParameterInfo paramInfo in inParams) + { + il.Emit(OpCodes.Ldloc, parameters); + il.Emit(OpCodes.Ldc_I4, paramIndex); + il.Emit(OpCodes.Ldarg, paramInfo.Position + 1); + if (paramInfo.ParameterType.IsValueType) + { + il.Emit(OpCodes.Box, paramInfo.ParameterType); + } + il.Emit(OpCodes.Stelem_Ref); + + paramIndex++; + } + + il.Emit(OpCodes.Ldloc, parameters); + + // Call Invoke method and save result + LocalBuilder results = il.DeclareLocal(typeof(Object[])); + il.EmitCall(OpCodes.Callvirt, Invoke, null); + il.Emit(OpCodes.Stloc, results); + + int resultIndex = (interfaceMethod.ReturnType == typeof(void) ? 0 : 1); + foreach (ParameterInfo paramInfo in refOutParams) + { + il.Emit(OpCodes.Ldarg, paramInfo.Position + 1); + il.Emit(OpCodes.Ldloc, results); + + // Cast / Unbox the return value + il.Emit(OpCodes.Ldc_I4, resultIndex); + il.Emit(OpCodes.Ldelem_Ref); + + Type elementType = paramInfo.ParameterType.GetElementType(); + if (elementType.IsValueType) + { + il.Emit(OpCodes.Unbox, elementType); + il.Emit(OpCodes.Ldobj, elementType); + il.Emit(OpCodes.Stobj, elementType); + } + else + { + il.Emit(OpCodes.Castclass, elementType); + il.Emit(OpCodes.Stind_Ref); + } + + resultIndex++; + } + + if (interfaceMethod.ReturnType != typeof(void)) + { + il.Emit(OpCodes.Ldloc, results); + + // Cast / Unbox the return value + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Ldelem_Ref); + if (interfaceMethod.ReturnType.IsValueType) + { + il.Emit(OpCodes.Unbox, interfaceMethod.ReturnType); + il.Emit(OpCodes.Ldobj, interfaceMethod.ReturnType); + } + else + { + il.Emit(OpCodes.Castclass, interfaceMethod.ReturnType); + } + } + } + + #endregion + } + + #endregion + } + + #endregion + + #region WebServiceProxyProxyTypeBuilder inner class implementation + + /// + /// Proxy type builder that can be used to create a proxy for + /// .Net-generated proxy class that can be safely cast to a service interface. + /// + private sealed class WebServiceProxyProxyTypeBuilder : InheritanceProxyTypeBuilder + { + #region Constructor(s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public WebServiceProxyProxyTypeBuilder() + { + this.Name = "WebServiceProxyProxy"; + } + + #endregion + + #region Protected Methods + + /// + /// Gets the mapping of the interface to proxy + /// into the actual methods on the target type + /// that does not need to implement that interface. + /// + /// + ///

+ /// As the proxy type does not implement the interface, + /// we try to find matching methods. + ///

+ ///
+ /// + /// The of the target object. + /// + /// The interface to implement. + /// + /// An interface mapping for the interface to proxy. + /// + protected override InterfaceMapping GetInterfaceMapping( + Type targetType, Type intf) + { + InterfaceMapping mapping; + + mapping.TargetType = targetType; + mapping.InterfaceType = intf; + mapping.InterfaceMethods = intf.GetMethods(); + mapping.TargetMethods = ReflectionUtils.GetMatchingMethods( + targetType, mapping.InterfaceMethods, true); + + return mapping; + } + + #endregion + } + + #endregion + } } \ No newline at end of file