When creating web services that are to be interoperable (easily accessbile across various platforms) the wsdl cannot have any xsd:import elements. In order to achieve this we need to flatten the wsdl. We do this by creating our own ServiceHostFactory.
First we create a class that defines the new ServiceHostFactory called FlatWsdlServiceHostFactory :
Now we create a Custom ServiceHost that performs the action of flattening the wsdl:
Now we have the actual class that inspects your wsdl and injects the xsd's into the wsdl by replacing the xsd:import elements in your wsdl.
Now your FlatWsdlServiceHostFactory is ready which would flatten your wsdl. Create a new WCF Service called FaltWsdlService.svc and open the markup of this file which the following code
Replace the above with the code below which states the Service needs to use the FlatWsdlServiceHostFactory instead of the default ServiceHostFactory from WCF.
Now when you browse to your wsdl you not find any xsd:import elements rather you would have one single wsdl.
First we create a class that defines the new ServiceHostFactory called FlatWsdlServiceHostFactory :
using System;
namespace FlatWsdl
{
public sealed class FlatWsdlServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory
{
public override System.ServiceModel.ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
return base.CreateServiceHost(constructorString, baseAddresses);
}
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new FlatWsdlServiceHost(serviceType, baseAddresses);
}
}
}
Now we create a Custom ServiceHost that performs the action of flattening the wsdl:
using System;
using System.ServiceModel.Description;
namespace FlatWsdl
{
public class FlatWsdlServiceHost : System.ServiceModel.ServiceHost
{
public FlatWsdlServiceHost() { }
public FlatWsdlServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses)
{
}
public FlatWsdlServiceHost(object singletonInstance, params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
{
}
/// <summary>
/// Just Inject Flat WSDL
/// </summary>
protected override void ApplyConfiguration()
{
Console.WriteLine("ApplyConfiguration (thread {0})", System.Threading.Thread.CurrentThread.ManagedThreadId);
base.ApplyConfiguration();
InjectFlatWsdlExtension();
}
private void InjectFlatWsdlExtension()
{
foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
{
endpoint.Behaviors.Add(new FlatWsdl());
}
}
}
}
Now we have the actual class that inspects your wsdl and injects the xsd's into the wsdl by replacing the xsd:import elements in your wsdl.
using System.Collections;
using System.Collections.Generic;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Xml.Schema;
using ServiceDescription = System.Web.Services.Description.ServiceDescription;
namespace FlatWsdl
{
public class FlatWsdl: IWsdlExportExtension, IEndpointBehavior
{
public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context) { }
public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
{
XmlSchemaSet schemaSet = exporter.GeneratedXmlSchemas;
foreach (ServiceDescription wsdl in exporter.GeneratedWsdlDocuments)
{
List<XmlSchema> importsList = new List<XmlSchema>();
foreach (XmlSchema schema in wsdl.Types.Schemas)
AddImportedSchemas(schema, schemaSet, importsList);
if (importsList.Count == 0)
return;
wsdl.Types.Schemas.Clear();
foreach (XmlSchema schema in importsList)
{
RemoveXsdImports(schema);
wsdl.Types.Schemas.Add(schema);
}
}
}
private void AddImportedSchemas(XmlSchema schema, XmlSchemaSet schemaSet, List<XmlSchema> importsList)
{
foreach (XmlSchemaImport import in schema.Includes)
{
ICollection realSchemas = schemaSet.Schemas(import.Namespace);
foreach (XmlSchema ixsd in realSchemas)
{
if (!importsList.Contains(ixsd))
{
importsList.Add(ixsd);
AddImportedSchemas(ixsd, schemaSet, importsList);
}
}
}
}
private void RemoveXsdImports(XmlSchema schema)
{
for (int i = 0; i < schema.Includes.Count; i++)
{
if (schema.Includes[i] is XmlSchemaImport)
schema.Includes.RemoveAt(i--);
}
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
}
Now your FlatWsdlServiceHostFactory is ready which would flatten your wsdl. Create a new WCF Service called FaltWsdlService.svc and open the markup of this file which the following code
<%@ ServiceHost Language="C#" Debug="true" Service="Sample.FlatWsdlService" CodeBehind="FlatWsdlService.svc.cs" %>
Replace the above with the code below which states the Service needs to use the FlatWsdlServiceHostFactory instead of the default ServiceHostFactory from WCF.
<%@ ServiceHost Language="C#" Debug="true" Factory="FlatWsdl.FlatWsdlServiceHostFactory" Service="SampleService.FlatWsdlService" CodeBehind="FlatWsdlService.svc.cs" %>
Now when you browse to your wsdl you not find any xsd:import elements rather you would have one single wsdl.
No comments:
Post a Comment