Home > C#, WCF > Using the WCF service moniker with the WSDL of a service

Using the WCF service moniker with the WSDL of a service

Introduction

In a previous article I wrote about the WCF service moniker. This COM component allows legacy applications to communicate with their new .Net based siblings. In the previous article, I explained two of the three ways to use the WCF service moniker. In this article, I will explain you the third way: using a locally cached WSDL description of the web service. Using the locally cached WSDL has advantages; you don’t need to create a class library for your WCF service and it does not need to expose meta data. Not exposing meta data is in enterprise environments often required to increase the security of the service.

The demo WCF service

First we are going to create the same simple demo service as in my previous WCF moniker article. So start Visual Studio and create a new “WCF Service Application”.

image

Inside the project we create the following service contract:

[ServiceContract]
public interface IHelloName
{
 	[OperationContract]
	string Hello(string name);
}

We implement the service as follows:

public class HelloName : IHelloName
{
	public string Hello(string name)
	{
		return "Hello " + name;
	}
}

The configuration for our service is the following (enter this in your web.config):

<system.serviceModel>
  <services>
    <service behaviorConfiguration="serviceBehavior"
              name="HelloNameService.HelloName">
      <endpoint binding="basicHttpBinding"
                contract="HelloNameService.IHelloName" />

      <endpoint address="mex"
                binding="mexHttpBinding"
                contract="IMetadataExchange" />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="serviceBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="false" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

We are now done with our WCF service, so you can press F5 to start the WCF service.

service page in internet explorer

Retrieving the WSDL

Before using the WCF service moniker, lets first look at the WSDL exposed by the WCF service. In order to do this, open your browser and enter the url “http://localhost:49170/HelloName.svc?wsdl”.

Please note that this URL will be probably be different on your system.

WSDL import

The first thing to notice is that the WSDL document is importing other documents. Because we want to call our web service by using a single file saved on disk, this behavior is not feasible. Luckily we were not the first .Net developers that wanted to have a “flat” WSDL. Other programming languages with less advanced web service stacks were having problems with this aspect of the WSDL generated by WCF, so Tomas Restrepo and Cristian Weyers came up with an alternative ServiceHostFactory that modifies the WCF stack to expose a flat WSDL. You can find this extension called “Flat WSDL” at http://www.thinktecture.com/media/9297/flatwsdl.zip

Download it and add the class library “Thinktecture.ServiceModel.Extensions.Description.dll” as a reference to our WCF service project. We can now modify the svc file of our service to change the ServiceHostFactory that IIS or WAS will be using. To do this provide the value “Thinktecture.ServiceModel.Extensions.Description.FlatWsdlServiceHostFactory” for the “Factory” property.

change of the factory voor een svc file detailed

If you now relaunch the WCF service and open the WSDL again, you will see that is has been “flattened”; it does not import any documents anymore. Save the WSDL to a file on your hard disk (I chose the path “c:\temp\IHelloName.wsdl”).

WSDL in internet explorer flattened

Creating the client application

For this demo, we are going to create a client application in VBA and Excel, but you can use the WCF service moniker from within every programming technology that supports COM.

Enter the following code in the VBA editor of Excel:

Sub ServiceMonikerCallWSDL()
    Dim service As Object
    Dim monString As String

    Const ForReading = 1
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objFile = objFSO.OpenTextFile("c:\temp\IHelloName.wsdl", ForReading, False, TristateTrue)
    wsdlContract = objFile.ReadAll
    objFile.Close

    On Error GoTo Exception:

    monString = "service4:address='http://localhost:49170/HelloName.svc'" & _
                ", wsdl='" & wsdlContract & "'" & _
                ", binding=BasicHttpBinding_IHelloName, bindingNamespace=http://tempuri.org/" & _
                ", contract=IHelloName, contractNamespace=http://tempuri.org/"

    Set service = GetObject(monString)

    MsgBox (service.Hello("Excel WSDL"))

    Exit Sub

Exception:
    MsgBox Err.Description
End Sub

Remark: don’t forget to change the address of the service and the path of the WSDL file to the correct ones for your computer.

Before executing this code, we will first disable the publishing of metadata to prove that we can call the WCF service without using its exposed meta data. We can also remove the custom ServiceHostFactory in the svc file.

disable meta data detailed

If we now restart the WCF service and execute the VBA code in Excel we get the following response:

Hello excel from wsdl

Conclusion

As shown in this article, the WCF service moniker can relatively simple be used in combination with the WSDL of the service. This has the advantage that we can disable meta data publishing for services running in production and still be able to call it with the WCF service moniker. If you want to use this mode, don’t forget to ‘flatten’ the WSDL.

Advertisements
Categories: C#, WCF
  1. Jim Meehan
    January 29, 2011 at 00:54

    I tried to implement your solution using a wcf service defined in .net 4.0 and an Excel 2003 app and it works for services that have parameters of a simple data type. However, when i try to implement it using a service with an input parameter of a complex data type, it fails saying that it cannot it cannot load type ‘*’ from assembly Systme.ServiceModel. Should it work for complex data types?

    • pieterderycke
      January 29, 2011 at 12:48

      Hello Jim,

      You cannot use DataContracts with the service moniker using the WSDL or the Mex endpoints. You can only use DataContracts if you use a typed contract for your WCF service moniker. I should have mentioned this in the articles. Did you succeed in using the typed contract from Excel?

  2. Jim Meehan
    January 31, 2011 at 18:53

    I am having problems using the typed contract from Excel. When I try to access the service moniker in the Excel program, it fails:

    Type load for contract interface ID failed with error: Interface not registered

    I have successfully registered the program, but it always generates the warning:

    warning : Type library exporter warning processing ‘ErrorServiceClient, ErrorClient2010’. Warning: Type library exporter encountered a type that derives from a generic class and is not marked as [ClassInterface(ClassInterfaceType.None)]. Class interfaces cannot be exposed for such types. Consider marking the type with [ClassInterface(ClassInterfaceType.None)] and exposing an explicit interface as the default interface to COM using the ComDefaultInterface attribute.

    I have also successfully added the contract type to the global assembly cache.

    Any ideas?

  3. Jim Meehan
    January 31, 2011 at 19:50

    How do I troubleshoot type registration issues? I find an entry for my ErrorServiceClient under HKEY_LOCAL_MACHINE\SOFTWARE\Classes, but I don’t have an entry for ErrorData which is my data contract class.

  4. Jim Meehan
    January 31, 2011 at 23:15

    Where is the client config file to be located? In the same directory as the Excel executable or the location of the spreadsheet?

    • pieterderycke
      February 1, 2011 at 21:57

      The client config needs to be located inside the Excel directory and it has to be named excel.exe.config.

      I will investigate your other “interface not registered” problem as soon as I have some spare time.

  5. Sri
    April 1, 2011 at 14:44

    Pieter
    Appreciate if you can guide me on how can I create a flat wsdl for a thirdparty wcf service. I only have a service url, how can I programatically using that 3rd party url create a flat wsdl before consuming?

  6. Cal Braun
    March 15, 2013 at 20:08

    Trying this out and getting a WSDL error. I posted this question to stackoverflow, any ideas?
    http://stackoverflow.com/questions/15436383/getting-wsdl-error-when-calling-service-using-wcf-service-moniker
    Thanks!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: