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(“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;


    }


}


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

Comments (0)