Someone asked me if it’s possible to add a Ping method to every service contract without repeatedly defining it in each service contract?  The answer is yes & and it’s fairly simply too.

Here I have a LoginService, which require that implicit Ping method (DateTime Ping(){})like all other service.

 

[ServiceContract]

class LoginService

{

    [OperationContract]

    public bool Login(string userName, string password)

    {

        return true;

    }

}

This is how you would configure your host for these implicit methods.

class Program

{

    static void Main(string[] args)

    {

        var sh = new ServiceHost(typeof(LoginService), new Uri("http://localhost:9001"));

 

        GeneratePingMethod(sh);

        sh.Open();

 

        Console.ReadLine();

        sh.Close();

    }

}

 

Please note “GeneratePingMethod” adds the Ping method to every endpoint.  I’m simply creating the operation using the WCF description API and adding it into the description tree. PingImplementationBehavior plugs in a custom OperationInvoker which calls the actual Ping implementation.

 

private static void GeneratePingMethod(ServiceHost sh)

{

    foreach (var endpoint in sh.Description.Endpoints)

    {

        var cd = endpoint.Contract;

        var od = new OperationDescription("Ping", cd);

        var inputMsg = new MessageDescription(cd.Namespace + cd.Name + "/Ping", MessageDirection.Input);

        var outputMsg = new MessageDescription(cd.Namespace + cd.Name + "/PingResponse", MessageDirection.Output);

        var retVal = new MessagePartDescription("PingResult", cd.Namespace); ;

        retVal.Type = typeof(DateTime);

 

        outputMsg.Body.ReturnValue = retVal;

 

 

        od.Messages.Add(inputMsg);

        od.Messages.Add(outputMsg);

 

        od.Behaviors.Add(new DataContractSerializerOperationBehavior(od));

        od.Behaviors.Add(new PingImplementationBehavior());

 

        cd.Operations.Add(od);

    }

}

 

class PingImplementationBehavior : IOperationBehavior

{

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)

    { }

 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)

    { }

 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)

    {

        dispatchOperation.Invoker = new PingInvoker();

    }

 

    public void Validate(OperationDescription operationDescription)

    { }

}

Again a fairly simple invoker which is tightly coupled to the signature of Ping method.

class PingInvoker : IOperationInvoker

{

    public object[] AllocateInputs()

    {

        return new object[0];

    }

 

    public object Invoke(object instance, object[] inputs, out object[] outputs)

    {

        outputs = new object[0];

        return Ping();

    }

 

    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)

    {

        throw new NotImplementedException();

    }

 

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)

    {

        throw new NotImplementedException();

    }

 

    public bool IsSynchronous

    {

        get { return true; }

    }

 

    public static DateTime Ping()

    {

        return DateTime.Now;

    }

}