WCF Endpoint Configuration Error: The 'contract' attribute is invalid?

BBauer42 picture BBauer42 · Aug 16, 2013 · Viewed 26.8k times · Source

I have a WCF service let's call it UserService. The UserService has a reference to a class library. Let's call it DoWork.dll. The DoWork.dll has a WCF service reference to a different service we'll call CompanyService.

Now, when I first tried calling the UserService I would get an endpoint not configured error message. After reading around the web I've found that I need to add the CompanyService bindings and client information into the UserService's web.config under the <system.serviceModel> node.

Here it is:

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IComapnyService" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint name="BasicHttpBinding_ICompanyService"
          address="http://it-dev.company.local:81/Project/Copmpany/CompanyService.svc"
          binding="basicHttpBinding" 
          bindingConfiguration="BasicHttpBinding_IComapnyService"
          contract="CompanyService.ICompanyService"  />
    </client>

The problem I have is the contract="CompanyService.ICompanyService" shows me the error:

The 'contract' attribute is invalid - The value 'CompanyService.ICompanyService' is invalid according to its datatype 'clientContractType' - The Enumeration constraint failed.

Now, if I add the CompanyService reference directly to the UserService WCF project, the error goes away (obviously). However, I shouldn't have to do this. I have tried fully qualifying the namespace the ICompanyService contract is in and that doesn't work either. I have deleted the .suo file and rebuild the project and that doesn't work either (suggested elsewhere on the web). Also, if I type contract=, I get the drop down list but CompanyService.ICompanyService is nowhere to be found (only when I reference the service directly in the UserService project).

I have tried configuring it using Tools > WCF Service Configuration Editor and that does not help.

I should note that everything seems to work fine, but I don't like the fact that intellisense is giving me the blue squiggly underline and that error message. I have a feeling I need something else in the web.config to get this to work since the UserService references the DoWork.dll, which in turn references the CompanyService whose contract I cannot see properly.

Any suggestions are much appreciated. Thanks in advance.

Answer

Rick Rainey picture Rick Rainey · Aug 17, 2013

You're right - you should not have to do this.

The architecture of having a DLL (DoWork.dll) with a "service reference" (ComanyService) is bad. Unless the DLL has hard-coded the client endpoint (in code) to call the CompanyService for you, then anyone using the DLL will have to try and figure out how to configure the client endpoint for a service they don't know about. Which is what your running into.

The reason this works when you add a service reference directly from your UserService is that when you do this, you get a copy of the ServiceContract from the CompanyService metadata. To prove this, look in the Reference.cs file that get's generated, search for CompanyService and you will find it has the [ServiceContract] attribute, identifying it as a WCF service. Furthermore, you will see the [OperationContract] attributes for the methods, plus any [DataContracts] the service my also exchange. In other words, all these "types" got imported into your project and when you compile, WCF is now able to find these types when instantiating the client endpoint.

If CompanyService is one of your services, then consider extracting out the ServiceContract definition (interface) into a separate DLL. Then, you can reference those types as "assembly references" from the service (CompanyService) and any client applications, such as UserService. At least that way you're not having to add a service reference. But, you still have to populate the .... section in your application for a service you technically may not know the details of. Not the best approach.

A better approach is to move the service dependency out of the DoWork.dll. You could do this by just moving the logic into the UserService implementation.

Or, if you need to keep DoWork.dll independent, then consider wrapping DoWork with it's on WCF Service, which takes a dependency on the CompanyService. Then, from UserService, add a service reference to the new DoWork service. This is more in keeping with the tenants of SOA and will allow your services to evolve independently.