Rapture in Everything

How to create a WCF web service from a WSDL

zblesk

This wasn’t the first time I was tasked with creating a mock web service based on a WSDL file. I’ve tried multiple approaches, but most of them weren’t exactly what I needed. So after digging around a bit, I’ve found a way that suits me and does just that.

I do not claim to be a WCF guru and there may be better ways to do this. If so, please let me know. But if you’re a developer in a hurry, you probably don’t care and have skipped these two paragraphs, anyway. :) Let’s start.

What I have:

My goal – what I need:

How to

In the following text, the service I am working with is called MyService. The VS project is named MyServiceMock.

Creating a new WCF project.

First, create a new WCF Service Application. If some .cs or .svc files were genreated, delete them.

Add a folder called WSDL and copy the WSDL and XSDs into it. Add them to the project. (Right click | Add existing item.) Set Build action to “Content”.

Open the command line in the projectwsdl folder and run:

svcutil /mc *.wsdl *.xsd

If svcutil isn’t in your path, run it from the Windows SDK directory. (For example in C\:Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools.)

This uses all the relevant files in the folder and should result in 2 files, output.config and MyService.cs.

Merge the generated output.config into your web.config.

Add the generated MyService.cs file into your project. By default, the svcutil doesn’t put the service contracts into any namespace. (That means they’re in global .) I recommend manually putting them into a namespace corresponding to your XML namespace, which you know from the WSDL, or you can find it in the generated code, in the ServiceContract attribute.

[System.ServiceModel.ServiceContractAttribute( 
	Namespace = "wsdl.myservice", 
	ConfigurationName = "ConfigName")]

Now I can then delete the two generated files.

I add a new Service to the project and call it MyServiceMock.svc, then go to MyServiceMock.svc.cs, make it inherit the generated contract interface, and implement it.

In my web.config, I change the client address to match my service endpoint.

<client> 
    <endpoint address="http://localhost:7745/MyServiceMock.svc" 
        ... >
<client>

I should be able to run the service now.

A possible error at this point:

Error: Cannot obtain Metadata from http://localhost:7745/MyServiceMock.svc If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. For help enabling metadata publishing, please refer to theMSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange Error  URI: http://localhost:7745/MyServiceMock.svc  Metadatacontains a reference that cannot be resolved: ‘http://localhost:7745/MyServiceMock.svc’.  The requested service, ‘http://localhost:7745/MyServiceMock.svc’ could not be activated. See the server’s diagnostic trace logs for more information.HTTP GET Error  URI: http://localhost:7745/MyServiceMock.svc  There was an error downloading ‘http://localhost:7745/MyServiceMock.svc’. The request failed with the error message:–    **Cannot have two operations in the same contract with the same name, methods *MyServiceMethodAsync* and *MyServiceMethod* in type wsdl.myservice.MyService violate this rule.** You can change the name of one of the operations by changing  
(...)

As you can see, the WSDL contained the definitions for both the blocking and the async versions of the MyServiceMethod, but they are essentially the same method. This can be solved by removing the Async methods from both the interface and implementation.

Another possible error is this, shown by the Microsoft WCF Test Client when trying to connect to my new endpoint.

--------------------------- 
Microsoft WCF Test Client 
--------------------------- 

The contract 'MyServiceMock' in client configuration does not match the name in service contract, or there is no valid method in this contract. 

To recover, please manually correct client configuration. 

Or restore to default configuration. 

Or check "Always regenerate config when launching services" in the Tools -> Options menu, then refresh the service.

Somewhere I found that the way to fix this is to use the original WSDL for the service instead of generating one on the fly. This is why I’d copied the WSDL into the project at the beginning. (There are other advantages – now the definitions are version-controlled and I always know which version was used to generate the code.)

In web.config, I need to change the Behavior definition to serve metadata from a static file.

 <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" 
    externalMetadataLocation="../wsdl/MyService.wsdl" />

Then I have to fix the WSDL file. Somewhere in it, there is an endpoint address listed. I set it to my deployed URL. (This address will be used in the client generated according to this WSDL.)

location="http://localhost:65000/MyServiceMock.svc"/>

Assuming your IIS configuration allows the serving of WSDL and XSD files, this should be it. Deploy the service (in my case to http://localhost:65000/), and everything should be up and running.

Here’s one more error possible at this step:

The configuration section 'protocolMapping' cannot be read because it is missing a section declaration

This could indicate your app pool is running on .NET 2.0, instead of 4.0. Change it in the IIS settings.

Now if I want to connect to the nes MyServiceMock WS using SoapUI, I create a new SoapUI project and give it a link directly to the WSDL. Since I fixed the WSDL file, the correct endpoint will be set.

If I use the WCF Test Client, running the .svc file from the Visual Studio should be enough. (Keep in mind, though, that WCF TC will use the endpoint in your WSDL. You might want to change it to your dev server if necessary.)