I am trying to use Castle DynamicProxy to implement a typesafe version of a SignalR Hub. The goal being when I use Clients.All rather than getting a dynamic object back I have an interface to use.
The code is rather hacky at the moment but I wanted to prove that it will work before I go through the trouble of making it nice:
public interface IChatClient
{
void broadcastMessage(string name, string message);
}
public class ChatHub : TypeSafeHub<IChatClient>
{
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
}
public abstract class TypeSafeHub<TInterface> : Hub where TInterface:class
{
public new TypeSafeHubCallerConnectionContext<TInterface> Clients
{
get
{
return new TypeSafeHubCallerConnectionContext<TInterface>(base.Clients);
}
}
}
public class TypeSafeHubCallerConnectionContext<T> where T:class
{
private IHubCallerConnectionContext context;
private ProxyGenerator proxyGen;
public TypeSafeHubCallerConnectionContext(IHubCallerConnectionContext context)
{
this.context = context;
proxyGen= new ProxyGenerator();
}
public T All
{
get
{
return proxyGen.CreateInterfaceProxyWithTarget<T>(context.All);
}
Right now when I'm returning the proxy it fails because the target does not implement the interface.
Is there an easy way to achieve this goal or should I look at using an InterfaceProxyWithoutTarget and using an interceptor to wire up the call to the dynamic.
You seem to be on the right track.
This is a feature slated for release in SignalR 2.1. You can look at how it is implemented here: https://github.com/SignalR/SignalR/commit/3c4b8794b0f512daec677110a8e41ac717514584
While there is likely a way to do this with Castle DynamicProxy, it might be simpler to use ImpromptuInterface.
Every call made to TypedClientBuilder<T>.Build(_dynamicContext...)
could be replaced with Impromptu.ActLike<T>(_dynamicContext...)
. In your case, the call to Impromptu.ActLike
would replace proxyGen.CreateInterfaceProxyWithTarget
.
If you feel really adventurous, you can try out the SignalR nightlies from MyGet which already have the feature included.