Share via


Adding Dynamic methods to a WCF Service

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("https://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;

    }

}

Originally posted by Zulfiqar Ahmed on 5 February 2010 here https://www.zamd.net/2010/02/05/AddingDynamicMethodsToAWCFService.aspx