My current project has posed some very interesting challenges. The first challenge was to write a web service using an existing WSDL. A vendor has created a "standard" WSDL by which all other companies that wish to implement the service must adhere to. What really made it a challenge was the choice we made to build this in WCF. So how do you implement a WCF web service using an existing WSDL? You could try to use the SVCUTIL.EXE tool to create the service, however I've found there are limitations with regards to the complexity of the existing WSDL or Schema. If the schema(s) found in the WSDL are too complex the SVCUTIL.EXE will not work for you. So my next option was to use WSDL.EXE from 2.0. Using WSDL.EXE with the /serviceInterface option will create the interface class and the data classes. The interface and data classes will be decorated using ASMX style attributes. For the data classes, keep them that way. For the interface class you will want to remove the ASMX style attributes and replace them with WCF style attributes as shown below.
Output from WSDL.EXE using the /serviceInterface parameter
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace Marks.WebService
{
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.1432")]
[System.Web.Services.WebServiceBindingAttribute(Name = "VerifyServiceSoap",
Namespace = "http://www.iicmva.com/CoverageVerification
public interface IVerifyServiceSoap
{
/// <remarks/>
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/VerifyInsurance",
RequestElementName = "CoverageRequest",
RequestNamespace = "http://www.iicmva.com/CoverageVerification/",
ResponseElementName = "CoverageResponse",
ResponseNamespace = "http://www.iicmva.com/CoverageVerification/",
Use = System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("Detail")]
CoverageResponseDetail[] VerifyInsurance(ref RequestorInformationModule RequestorInformation,
CoverageRequestDetail Detail);
}
}
For a WCF web service remove the attributes and replace them with ServiceContract and OperationContract attributes. Note you can define the Action and ReplyAction in the operation contract. Also note, if you use the data classes decorated with ASMX style attributes you will need to use the XmlSerializerFormat attribute on the interface. This will correctly serialize the data classes.
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace Marks.WebService
{
/// <remarks/>
[ServiceContract(Namespace = "http://www.iicmva.com/CoverageVerification/", Name = "VerifyServiceSoap")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document, Use = OperationFormatUse.Literal)]
public interface IVerifyServiceSoap
{
/// <remarks/>
[OperationContract(Action = "http://tempuri.org/VerifyInsurance",
ReplyAction = "http://tempuri.org/VerifyInsurance")]
CoverageResponseDetail[] VerifyInsurance(ref RequestorInformationModule RequestorInformation,
CoverageRequestDetail Detail);
}
}
This is all good and fine, but there is one little gotcha if your clients are expecting the XML declaration <?xml version="1.0" encoding="utf-8" ?> at the beginning of the response. The default text encoder has the smarts to detect if redundant information is being written to the response. Because the XML declaration most likely contains default values, the encoder does not write the XML declaration out. This is not something you can configure and from what I'm seeing in the blogs and a few emails back and forth to Microsoft, this continues to be a nuisance, they feel our pain and are trying to get this into a configurable option for the next release.
So, in the meantime, I will need to write a Custom Text Message Encoder which will write the XML Declaration out ALL of the time. Once I complete that, I will update this post with the results.
Update: Well, I downloaded the custom text message encoder example, made the modifications to the WriteMessage method as recommended and now I am faced with a content type issue (HTTP 415) when I try to post a message to the service. I tried various settings for ContentType but to no avail. So at this time, due to time constraints, I am forced to go back to a ASMX web service.
I was able to revert to the ASMX web service in about 10 minutes and the XML declaration was there, no problems. I would think, something as simple as a XML declaration at the beginning of a response message should be something configurable within the WCF web service to allow for backwards compatibility/interoperability.