Modify a Web Service's WSDL Using a SoapExtensionReflector

A customer pinged me with an interesting problem.  They hosted an ASMX web service to run under SSL according to the KB article "HOW TO:  Secure XML Web Services with Secure Sockets Layer in Windows Server 2003".  When they viewed the WSDL for the service, the scheme for the URI still indicated "http" instead of "https".   There is a link in that KB article that indicates it is up to you to modify the WSDL:

Edit the Web Service Description Language (WSDL) files for your service so that the address for your Web service begins with https instead of http. Make sure that the copy of the WSDL that your client uses also indicates https.

Yikes.  Edit the WSDL?  That kind of indicates that you should save the WSDL off to a file, make the modification, and also configure the web service not to emit the documentation for your site.

OK, it is easier than this.  The SoapExtensionReflector type is very helpful here.  The SoapExtensionReflector is called when your type is being reflected over to provide the WSDL definition for your service.  You can leverage this type to intercept the reflection call and modify the WSDL output.  Here is an example that changes the URI scheme from http to https:

 using System;
using System.Web.Services.Description;

namespace Msdn.Web.Services.Samples
{
    public class HttpsReflector : SoapExtensionReflector
    {
        public override void ReflectMethod()
        {
            //no-op
        }

        public override void ReflectDescription()
        {
            ServiceDescription description = ReflectionContext.ServiceDescription;
            foreach (Service service in description.Services)
            {
                foreach (Port port in service.Ports)
                {
                    foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
                    {
                        SoapAddressBinding binding = extension as SoapAddressBinding;
                        if (null != binding)
                        {
                            binding.Location = binding.Location.Replace("https://", "https://");
                        }
                    }
                }
            }
        }
    }
}

Using Visual Studio 2005, I created the class above and put it in the App_Code folder in my web site.  Then, in the web.config file, I added the following section within configuration/system.web:

<

webServices>

<

soapExtensionReflectorTypes>

<

add type="Msdn.Web.Services.Samples.HttpsReflector, App_code"/>

</

soapExtensionReflectorTypes>

</

webServices>

When you run the web service, you can request the WSDL for the site using the ?wsdl querystring to see the result.  Also, when someone uses the "Add Web Reference" dialog, the reflector is called as well.  Here is the result from a simple HelloWorld service that is running under the ASP.NET Development Server (the Cassini web server for file-based web applications in Visual Studio 2005).

<

wsdl:service name="HelloService">

<

wsdl:port name="HelloServiceSoap" binding="tns:HelloServiceSoap">

<

soap:address location="https://localhost:2153/WebSite1/HelloService.asmx" />

</

wsdl:port>

<

wsdl:port name="HelloServiceSoap12" binding="tns:HelloServiceSoap12">

<

soap12:address location="https://localhost:2153/WebSite1/HelloService.asmx" />

</

wsdl:port>

</

wsdl:service>Of course, if you don't want to expose a SOAP 1.2 endpoint for your URL, you can also configure ASMX not to expose a SOAP 1.2 endpoint.