I have an idea, but I need help implementing it.
WCF does not support delegates in its contracts. Instead it has a cumbersome callback contracts mechanism, and I'm looking for a way to overcome this limitation.
I thought about using a IDataContractSurrogate
to replace each delegate in the contract with a token that will be serialized to the remote endpoint. There, the token will be deserialized into a generated delegate. This generated delegate will send a generic callback message which encapsulates all the arguments (that the delegate was invoked with).
The generic callback message will reach the first endpoint, and there the original delegate would be invoked with the arguments.
Here is the purposed (simplified) sequence:
- A calls B-proxy.Foo(callback)
- callback is serialized through a DelegateSurrogate.
- The DelegateSurrogate stores the delegate in a dedicated delegate storage and replaces it with a token
- The message arrives to B's endpoint
- the token is deserialized through a DelegateSurrogate
- The DelegateSurrogate constructs a generated delegate
- B.Foo(generatedCallback) is invoked
- Later, B is invoking generatedCallback(args)
- generatedCallback(args) calls a dedicated generic contract on A's endpoint: CallbackContract-proxy.GenericCallback(args)
- CallbackContract.GenericCallback(args) is invoked on A's endpoint
- The original callback is retrieved from the storage and is invoked: callback(args)
I have already implemented this previously using service bus (NServiceBus
), but I want to adapt the idea to WCF and I'm having hard time. I know how to implement steps 3,6,9 and 11. I don't know yet how to wire everything in WCF - especially the surrogate part.
That's it - I hope my question made sense, and that the collective wisdom here will be able to help me build this up.
Here's a sample usage for my desired solution:
// client side
remoteSvc.GetEmployeeById(17, emp =>
{
employees.Add(emp);
logger.log("Result received");
});
// server side
public void GetEmployeeById(int id, Action<Employee> callback)
{
var emp = getEmpFromDb(id);
callback(emp);
}