e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
378 lines
16 KiB
C#
378 lines
16 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
#pragma warning disable 1634, 1691
|
|
|
|
namespace System.ServiceModel.ComIntegration
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Runtime;
|
|
using System.Runtime.InteropServices;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Channels;
|
|
using System.ServiceModel.Description;
|
|
using System.ServiceModel.Diagnostics;
|
|
using System.ServiceModel.Dispatcher;
|
|
using System.Threading;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
using ConfigNS = System.ServiceModel.Configuration;
|
|
using WsdlNS = System.Web.Services.Description;
|
|
|
|
internal class WsdlServiceChannelBuilder : IProxyCreator, IProvideChannelBuilderSettings
|
|
{
|
|
|
|
ContractDescription contractDescription = null;
|
|
ServiceChannelFactory serviceChannelFactory = null;
|
|
Dictionary<MonikerHelper.MonikerAttribute, string> propertyTable;
|
|
ServiceChannel serviceChannel = null;
|
|
ServiceEndpoint serviceEndpoint = null;
|
|
KeyedByTypeCollection<IEndpointBehavior> behaviors = new KeyedByTypeCollection<IEndpointBehavior>();
|
|
bool useXmlSerializer = false;
|
|
|
|
//Suppressing PreSharp warning that property get methods should not throw
|
|
#pragma warning disable 6503
|
|
ServiceChannelFactory IProvideChannelBuilderSettings.ServiceChannelFactoryReadWrite
|
|
{
|
|
get
|
|
{
|
|
if (serviceChannel != null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.TooLate), HR.RPC_E_TOO_LATE));
|
|
return serviceChannelFactory;
|
|
}
|
|
}
|
|
#pragma warning restore 6503
|
|
|
|
ServiceChannel IProvideChannelBuilderSettings.ServiceChannel
|
|
{
|
|
get
|
|
{
|
|
return CreateChannel();
|
|
}
|
|
}
|
|
ServiceChannelFactory IProvideChannelBuilderSettings.ServiceChannelFactoryReadOnly
|
|
{
|
|
get
|
|
{
|
|
return serviceChannelFactory;
|
|
}
|
|
}
|
|
|
|
//Suppressing PreSharp warning that property get methods should not throw
|
|
#pragma warning disable 6503
|
|
KeyedByTypeCollection<IEndpointBehavior> IProvideChannelBuilderSettings.Behaviors
|
|
{
|
|
get
|
|
{
|
|
if (serviceChannel != null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.TooLate), HR.RPC_E_TOO_LATE));
|
|
return behaviors;
|
|
}
|
|
}
|
|
#pragma warning restore 6503
|
|
|
|
void IDisposable.Dispose()
|
|
{
|
|
if (serviceChannel != null)
|
|
serviceChannel.Close();
|
|
|
|
}
|
|
|
|
internal WsdlServiceChannelBuilder(Dictionary<MonikerHelper.MonikerAttribute, string> propertyTable)
|
|
{
|
|
this.propertyTable = propertyTable;
|
|
ProcessWsdl();
|
|
|
|
}
|
|
|
|
private ServiceChannel CreateChannel()
|
|
{
|
|
Thread.MemoryBarrier();
|
|
if (serviceChannel == null)
|
|
{
|
|
lock (this)
|
|
{
|
|
Thread.MemoryBarrier();
|
|
if (serviceChannel == null)
|
|
{
|
|
try
|
|
{
|
|
if (serviceChannelFactory == null)
|
|
{
|
|
FaultInserviceChannelFactory();
|
|
}
|
|
if (serviceChannelFactory == null)
|
|
{
|
|
throw Fx.AssertAndThrow("ServiceChannelFactory cannot be null at this point");
|
|
}
|
|
serviceChannelFactory.Open();
|
|
if (serviceEndpoint == null)
|
|
{
|
|
throw Fx.AssertAndThrow("ServiceEndpoint cannot be null");
|
|
}
|
|
serviceChannel = serviceChannelFactory.CreateServiceChannel(new EndpointAddress(serviceEndpoint.Address.Uri, serviceEndpoint.Address.Identity, serviceEndpoint.Address.Headers), serviceEndpoint.Address.Uri);
|
|
ComPlusChannelCreatedTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationChannelCreated,
|
|
SR.TraceCodeComIntegrationChannelCreated, serviceEndpoint.Address.Uri, contractDescription.ContractType);
|
|
if (serviceChannel == null)
|
|
{
|
|
throw Fx.AssertAndThrow("serviceProxy MUST derive from RealProxy");
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if ((serviceChannel == null) && (serviceChannelFactory != null))
|
|
{
|
|
serviceChannelFactory.Close();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return serviceChannel;
|
|
|
|
}
|
|
private ServiceChannelFactory CreateServiceChannelFactory()
|
|
{
|
|
serviceChannelFactory = ServiceChannelFactory.BuildChannelFactory(serviceEndpoint) as ServiceChannelFactory;
|
|
if (serviceChannelFactory == null)
|
|
{
|
|
throw Fx.AssertAndThrow("We should get a ServiceChannelFactory back");
|
|
}
|
|
FixupProxyBehavior();
|
|
return serviceChannelFactory;
|
|
}
|
|
|
|
void FaultInserviceChannelFactory()
|
|
{
|
|
if (propertyTable == null)
|
|
{
|
|
throw Fx.AssertAndThrow("PropertyTable should not be null");
|
|
}
|
|
foreach (IEndpointBehavior behavior in behaviors)
|
|
serviceEndpoint.Behaviors.Add(behavior);
|
|
serviceChannelFactory = CreateServiceChannelFactory();
|
|
}
|
|
|
|
void FixupProxyBehavior()
|
|
{
|
|
ClientOperation operation = null;
|
|
|
|
if (useXmlSerializer)
|
|
XmlSerializerOperationBehavior.AddBehaviors(contractDescription);
|
|
|
|
foreach (OperationDescription opDesc in contractDescription.Operations)
|
|
{
|
|
operation = serviceChannelFactory.ClientRuntime.Operations[opDesc.Name];
|
|
operation.SerializeRequest = true;
|
|
operation.DeserializeReply = true;
|
|
|
|
if (useXmlSerializer)
|
|
operation.Formatter = XmlSerializerOperationBehavior.CreateOperationFormatter(opDesc);
|
|
else
|
|
operation.Formatter = new DataContractSerializerOperationFormatter(opDesc, TypeLoader.DefaultDataContractFormatAttribute, null);
|
|
}
|
|
}
|
|
|
|
private void ProcessWsdl()
|
|
{
|
|
string wsdlText;
|
|
string portType;
|
|
string bindingName;
|
|
string address;
|
|
string spnIdentity = null;
|
|
string upnIdentity = null;
|
|
string dnsIdentity = null;
|
|
EndpointIdentity identity = null;
|
|
string serializer = null;
|
|
string contractNamespace = null;
|
|
string bindingNamespace = null;
|
|
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.Wsdl, out wsdlText);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.Contract, out portType);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.Binding, out bindingName);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.Address, out address);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.SpnIdentity, out spnIdentity);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.UpnIdentity, out upnIdentity);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.DnsIdentity, out dnsIdentity);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.Serializer, out serializer);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.BindingNamespace, out bindingNamespace);
|
|
propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.ContractNamespace, out contractNamespace);
|
|
|
|
if (string.IsNullOrEmpty(wsdlText))
|
|
{
|
|
throw Fx.AssertAndThrow("Wsdl should not be null at this point");
|
|
}
|
|
if (string.IsNullOrEmpty(portType) || string.IsNullOrEmpty(bindingName) || string.IsNullOrEmpty(address))
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.ContractBindingAddressCannotBeNull)));
|
|
|
|
if (!string.IsNullOrEmpty(spnIdentity))
|
|
{
|
|
if ((!string.IsNullOrEmpty(upnIdentity)) || (!string.IsNullOrEmpty(dnsIdentity)))
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.MonikerIncorrectServerIdentity)));
|
|
identity = EndpointIdentity.CreateSpnIdentity(spnIdentity);
|
|
}
|
|
else if (!string.IsNullOrEmpty(upnIdentity))
|
|
{
|
|
if ((!string.IsNullOrEmpty(spnIdentity)) || (!string.IsNullOrEmpty(dnsIdentity)))
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.MonikerIncorrectServerIdentity)));
|
|
identity = EndpointIdentity.CreateUpnIdentity(upnIdentity);
|
|
}
|
|
else if (!string.IsNullOrEmpty(dnsIdentity))
|
|
{
|
|
if ((!string.IsNullOrEmpty(spnIdentity)) || (!string.IsNullOrEmpty(upnIdentity)))
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.MonikerIncorrectServerIdentity)));
|
|
identity = EndpointIdentity.CreateDnsIdentity(dnsIdentity);
|
|
}
|
|
else
|
|
identity = null;
|
|
|
|
bool removeXmlSerializerImporter = false;
|
|
|
|
if (!String.IsNullOrEmpty(serializer))
|
|
{
|
|
if ("xml" != serializer && "datacontract" != serializer)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.MonikerIncorectSerializer)));
|
|
|
|
if ("xml" == serializer)
|
|
useXmlSerializer = true;
|
|
else
|
|
removeXmlSerializerImporter = true; // specifying datacontract will explicitly remove the Xml importer
|
|
// if this parameter is not set we will simply use indigo defaults
|
|
}
|
|
|
|
TextReader reader = new StringReader(wsdlText);
|
|
try
|
|
{
|
|
try
|
|
{
|
|
WsdlNS.ServiceDescription wsdl = WsdlNS.ServiceDescription.Read(reader);
|
|
|
|
if (String.IsNullOrEmpty(contractNamespace))
|
|
contractNamespace = wsdl.TargetNamespace;
|
|
|
|
if (String.IsNullOrEmpty(bindingNamespace))
|
|
bindingNamespace = wsdl.TargetNamespace;
|
|
|
|
WsdlNS.ServiceDescriptionCollection wsdlDocs = new WsdlNS.ServiceDescriptionCollection();
|
|
wsdlDocs.Add(wsdl);
|
|
XmlSchemaSet schemas = new XmlSchemaSet();
|
|
foreach (XmlSchema schema in wsdl.Types.Schemas)
|
|
schemas.Add(schema);
|
|
|
|
MetadataSet mds = new MetadataSet(WsdlImporter.CreateMetadataDocuments(wsdlDocs, schemas, null));
|
|
WsdlImporter importer;
|
|
|
|
if (useXmlSerializer)
|
|
importer = CreateXmlSerializerImporter(mds);
|
|
else
|
|
{
|
|
if (removeXmlSerializerImporter)
|
|
importer = CreateDataContractSerializerImporter(mds);
|
|
else
|
|
importer = new WsdlImporter(mds);
|
|
}
|
|
|
|
XmlQualifiedName contractQname = new XmlQualifiedName(portType, contractNamespace);
|
|
XmlQualifiedName bindingQname = new XmlQualifiedName(bindingName, bindingNamespace);
|
|
|
|
WsdlNS.PortType wsdlPortType = wsdlDocs.GetPortType(contractQname);
|
|
contractDescription = importer.ImportContract(wsdlPortType);
|
|
|
|
WsdlNS.Binding wsdlBinding = wsdlDocs.GetBinding(bindingQname);
|
|
Binding binding = importer.ImportBinding(wsdlBinding);
|
|
|
|
EndpointAddress endpointAddress = new EndpointAddress(new Uri(address), identity, (AddressHeaderCollection)null);
|
|
|
|
serviceEndpoint = new ServiceEndpoint(contractDescription, binding, endpointAddress);
|
|
|
|
ComPlusWsdlChannelBuilderTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationWsdlChannelBuilderLoaded,
|
|
SR.TraceCodeComIntegrationWsdlChannelBuilderLoaded, bindingQname, contractQname, wsdl, contractDescription, binding, wsdl.Types.Schemas);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
throw;
|
|
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.FailedImportOfWsdl, e.Message)));
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
IDisposable disposee = reader;
|
|
disposee.Dispose();
|
|
}
|
|
}
|
|
|
|
public WsdlImporter CreateDataContractSerializerImporter(MetadataSet metaData)
|
|
{
|
|
Collection<IWsdlImportExtension> wsdlImportExtensions = ConfigNS.ClientSection.GetSection().Metadata.LoadWsdlImportExtensions();
|
|
|
|
for (int i = 0; i < wsdlImportExtensions.Count; i++)
|
|
{
|
|
if (wsdlImportExtensions[i].GetType() == typeof(XmlSerializerMessageContractImporter))
|
|
wsdlImportExtensions.RemoveAt(i);
|
|
}
|
|
|
|
WsdlImporter importer = new WsdlImporter(metaData, null, wsdlImportExtensions);
|
|
|
|
return importer;
|
|
}
|
|
|
|
public WsdlImporter CreateXmlSerializerImporter(MetadataSet metaData)
|
|
{
|
|
Collection<IWsdlImportExtension> wsdlImportExtensions = ConfigNS.ClientSection.GetSection().Metadata.LoadWsdlImportExtensions();
|
|
|
|
for (int i = 0; i < wsdlImportExtensions.Count; i++)
|
|
{
|
|
if (wsdlImportExtensions[i].GetType() == typeof(DataContractSerializerMessageContractImporter))
|
|
wsdlImportExtensions.RemoveAt(i);
|
|
}
|
|
|
|
WsdlImporter importer = new WsdlImporter(metaData, null, wsdlImportExtensions);
|
|
|
|
return importer;
|
|
}
|
|
|
|
|
|
ComProxy IProxyCreator.CreateProxy(IntPtr outer, ref Guid riid)
|
|
{
|
|
IntPtr inner = IntPtr.Zero;
|
|
if (riid != InterfaceID.idIDispatch)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidCastException(SR.GetString(SR.NoInterface, riid)));
|
|
if (contractDescription == null)
|
|
{
|
|
throw Fx.AssertAndThrow("ContractDescription should not be null at this point");
|
|
}
|
|
return DispatchProxy.Create(outer, contractDescription, this);
|
|
|
|
}
|
|
|
|
bool IProxyCreator.SupportsErrorInfo(ref Guid riid)
|
|
{
|
|
if (riid != InterfaceID.idIDispatch)
|
|
return false;
|
|
else
|
|
return true;
|
|
|
|
}
|
|
|
|
bool IProxyCreator.SupportsDispatch()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool IProxyCreator.SupportsIntrinsics()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|