John Lay
John Lay

Reputation: 301

Can you mimic an existing service in WCF?

We have a 3rd party vendor service and an in-house service to communicate with it. Everything works perfectly with our in-house service, but I've been asked to write a fall back clone of our vendor's service. The intention is to be able to run up our clone, swap-out the client end-point and allow our in-house service to continue testing against the clone.

Is it possible to recreate/mimic a service such that an existing client can communicate with it (without modification) as if it were the original service?

So far I’ve tried 3 things and none of them work.

1st approach

Create a simple service, reference the 3rd party service to gain access to the custom types and mimic the [operation Contract]’s.

When I try to communicate with this service I get the following error.

A first chance exception of type 'System.ServiceModel.ActionNotSupportedException' occurred in System.ServiceModel.dll Additional information: The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).

There is no security requirements as we are using basic http (no ssl). The service model portion of the config file and the service behaviour class attributes are below:

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="SimpleBinding" />
      </basicHttpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="cloneBehavior" name="MyClone">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="SimpleBinding"
          contract="MyService.IMyService" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost/clone/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="cloneBehavior">
          <serviceMetadata httpGetEnabled="True" httpGetUrl="http://localhost/clone/mex" />
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
</system.serviceModel>

and the service behaviour

[ServiceBehavior(Name = "CloneService", 
    ConfigurationName = "MyClone", 
    InstanceContextMode = InstanceContextMode.PerCall, 
    AddressFilterMode = AddressFilterMode.Any)]
public class MyService : IMyService
{

Everything looks good and I have come to my first dead end.

2nd approach

Get rid of my interface/service contract and inherit directly from the interface generated in the reference.cs file.

When I run this service up, I get the following error

System.InvalidOperationException: The operations myMethodA and myMethodB have the same action (). Every operation must have a unique action value.

at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ActionDemuxer.Add(String action, DispatchOperationRuntime operation) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime..ctor(DispatchRuntime dispatch) at System.ServiceModel.Dispatcher.DispatchRuntime.GetRuntimeCore() at System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpened() at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) at Microsoft.Tools.SvcHost.ServiceHostHelper.OpenService(ServiceInfo info)

Taking a look at the generated interface for this method, they are all decorated with the following attribute:

[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")]

My understanding from msdn is that WCF defaults to adding a unique action of the pattern <namespace>/<service>/<operation>[Response].

If I try setting the action to * then I can hit the service (as expected with the catch all / unmatched message handler), but I can't hit a specific method.

Nevertheless, manually making all the actions unique (and conforming to the above pattern), give this error:

The contract ‘IMyService’ in client configuration does not match the name in service contract, or there is no valid method in this contract. …

I have clearly defined methods in the service contract and have come to a second dead end.

3rd approach

Using the wsdl.exe tool to generate a service from the wsdl. I followed the instructions from this SO post to generate an interface and inherit from it.

I’ve also tried generating the service itself by using the clientWsdl.wsdl /l:CS /server command and following the instructions in this post.

After tidying up the generated code and running it up, I’m back to my original error:

A first chance exception of type 'System.ServiceModel.ActionNotSupportedException' occurred in System.ServiceModel.dll Additional information: The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).

At each attempt I have double checked all the config settings and updated the contract at each stage.

At this stage I'm wondering if it's even possible.

Upvotes: 2

Views: 1266

Answers (2)

fcatacutan
fcatacutan

Reputation: 63

Were you ever able to mimic the service using WCF? I find myself in a similar situation where I've been tasked to write some integration tests where our method makes a call to a vendor's web service. I would have preferred to leverage Moq to write proper unit tests, but I'm constrained by 1) not being allowed to change the signature of the method that I'm testing, and 2) not really knowing anything about the web service itself except for what we send to the service and its expected response.

@jparram's suggestion was my next approach.

Note: I would have preferred to have posted this as a comment seeing that I'm not really answering your question.

Upvotes: 1

jparram
jparram

Reputation: 804

If I understand your scenario, I would create wrapper service that decides which service to call. It sounds like that's what you want to do with Scenario 1. So, your client would always be calling your wrapper service, and your wrapper service would map the inputs to the required inputs of your 3rd party service or your back up service.

The error you received sounds like an issue in the generation of the proxy client where the "Action" is not getting mapped. Take a look at the generated proxy code from a known working configuration and compare it to what is in your scenario 1.

Edit Compare the generated proxy client of your service and the 'real' service. The complaint about the Action = "" is probably due to the:

[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="")]

On your client not getting mapped to the corresponding operation.

Upvotes: 0

Related Questions