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;
}
}