Hi Krzysztof
I forgot about that. There is another method on the CommandProxy class that
is used to raise the event. So the signature of the CommandProxy class
should be more like this:
public class CommandProxy : ICommands
{
public event EventHandler<EventArgs> OnTerminated;
private void RaiseOnAvailabilityChange()
{
var local = OnTerminated;
if (local != null)
{
local(SelfReference(), EventArgs.Empty);
}
}
// Stop the leaking of the 'this' reference by getting it from this
method
// The proxy will override this method and make sure we only return
the
// link to the proxy.
protected internal virtual object SelfReference()
{
return this;
}
public void NotifyOfTermination()
{
RaiseOnAvailabilityChange();
}
}
The NotifyOfTermination method is invoked when the remote interface
disappears (e.g. the remote application signs off from the network or
something). The method is called by casting the proxy to a commandproxy and
then invoking the method, e.g.:
var generator = new ProxyGenerator();
var proxy =
(ICoolCommands)generator.CreateInterfaceProxyWithTarget(
typeof(ICoolCommands),
baseObject,
options,
new IInterceptor[] { selfReference, methodWithoutResult,
methodWithResult });
var commandProxy = (CommandProxy)proxy;
commandProxy.NotifyOfTermination ();
I'll try out the BaseTypeForInterfaceProxies property and see where it gets
me. Would an other solution be to do the following?
var generator = new ProxyGenerator();
var proxy =
(ICoolCommands)generator.CreateInterfaceProxyWithTarget(
typeof(ICommands),
new Type[] { typeof(ICoolCommands) },
baseObject,
options,
new IInterceptor[] { selfReference, methodWithoutResult,
methodWithResult });
I'm not sure what that would do with the overlapping events on the
ICoolCommands interface though.
Regards
Patrick
2011/5/14 Krzysztof Koźmic <[email protected]>
> @Patrick,
>
> How and when is RaiseOnAvailabilityChange method invoked?
>
> I'm not sure I got that right but I think what you're really after is proxy
> without target, but instead with CommandProxy class as its base class.
>
> ProxyGenerationOptions has a BaseTypeForInterfaceProxies property for that.
>
> HTH,
> Krzysztof
>
>
> On 13/05/2011 8:00 AM, Patrick van der Velde wrote:
>
> Hi All
>
> I'm trying to use DynamicProxy to create a proxy object for a remote
> interface. For that to work I've done the following. I have defined a base
> interface for all command interfaces. This base interface doesn't provide
> any command methods but does provide an event. The base interface looks like
> this:
>
> public interface ICommands
> {
> event EventHandler<EventArgs> OnTerminated;
> }
>
> That base interface is implemented by a proxy base class which will be
> used to refer to the proxy in the storage layer. The definition of that base
> proxy object looks like:
>
> public class CommandProxy : ICommands
> {
> public event EventHandler<EventArgs> OnTerminated;
>
> private void RaiseOnAvailabilityChange()
> {
> var local = OnTerminated;
> if (local != null)
> {
> local(SelfReference(), EventArgs.Empty);
> }
> }
>
> // Stop the leaking of the 'this' reference by getting it from
> this method
> // The proxy will override this method and make sure we only return
> the
> // link to the proxy.
> protected internal virtual object SelfReference()
> {
> return this;
> }
> }
>
> Interfaces that derive from ICommands are only allowed to have methods
> that either return Task or Task<T> to indicate that any method called on the
> interface is likely to take up a finite amount of time. An example
> definition of a command interface looks like this:
>
> public interface ICoolCommands : ICommands
> {
> Task SomeMethod(int input);
>
> Task<int> SomeOtherMethod(int input);
> }
>
> The actual definition of the command interfaces may be different and is
> not known to the proxy building code.
>
> I've then defined several interceptors to handle the case of methods with
> a Task return value and methods with a Task<T> return value.
> The first interceptor handles (I think) the 'SelfRefence' method in the
> base proxy object.
> internal sealed class CommandSetProxySelfReferenceInterceptor :
> IInterceptor
> {
> public void Intercept(IInvocation invocation)
> {
> invocation.ReturnValue = invocation.Proxy;
> }
> }
>
> The following two interceptors handle the case of methods with a Task and
> a Task<T> return value. Note that these interceptors never call in to the
> proxy base object because that object doesn't have any of the correct
> methods implemented.
> internal sealed class CommandSetMethodWithTaskResultInterceptor :
> IInterceptor
> {
> public void Intercept(IInvocation invocation)
> {
> invocation.ReturnValue =
> Task.Factory.StartNew(
> () => Console.WriteLine(
> string.Format("{}({})",
> invocation.Method.Name,
> invocation.Arguments[0])));
> }
> }
>
> internal sealed class CommandSetMethodWithTypedTaskResultInterceptor
> : IInterceptor
> {
> public void Intercept(IInvocation invocation)
> {
> invocation.ReturnValue =
> Task<int>.Factory.StartNew(
> () =>
> {
> Console.WriteLine(
> string.Format("{}({})",
> invocation.Method.Name,
> invocation.Arguments[0]));
> return 10;
> });
> }
> }
>
> And finally there is an interceptorselector to handle setting up the
> interceptor chains.
>
> internal sealed class CommandSetInterceptorSelector :
> IInterceptorSelector
> {
> public IInterceptor[] SelectInterceptors(Type type, MethodInfo
> method, IInterceptor[] interceptors)
> {
> var name = "SelfReference";
> if (string.Equals(name, method.Name, StringComparison.Ordinal))
> {
> return interceptors.Where(i => i is
> CommandSetProxySelfReferenceInterceptor).ToArray();
> }
>
> if (method.ReturnType == typeof(Task))
> {
> return interceptors.Where(i => i is
> CommandSetMethodWithTaskResultInterceptor).ToArray();
> }
>
> return interceptors.Where(i => i is
> CommandSetMethodWithTypedTaskResultInterceptor).ToArray();
> }
> }
>
> Now to build the proxy I use the following code (simplified from the real
> code)
>
> class Program
> {
> static void Main(string[] args)
> {
> var baseObject = new CommandProxy();
>
> var selfReference = new
> CommandSetProxySelfReferenceInterceptor();
> var methodWithoutResult = new
> CommandSetMethodWithTaskResultInterceptor();
> var methodWithResult = new
> CommandSetMethodWithTypedTaskResultInterceptor();
>
> var options = new ProxyGenerationOptions
> {
> Selector = new CommandSetInterceptorSelector(),
> };
>
> var generator = new ProxyGenerator();
> var proxy =
> (ICoolCommands)generator.CreateInterfaceProxyWithTarget(
> typeof(ICoolCommands),
> baseObject,
> options,
> new IInterceptor[] { selfReference, methodWithoutResult,
> methodWithResult });
>
> proxy.SomeMethod(10);
> var result = proxy.SomeOtherMethod(20);
> Console.ReadLine();
> }
> }
>
> The problem is that it fails when I try to create the proxy (the line
> that has generator.CreateInterfaceProxyWithTarget) because the target
> doesn't implement the ICoolCommands interface. So the question now is how
> can I:
> - Create a proxy for a derivative of the ICommands interface, without the
> proxy code knowing what that interface is going to be
> - Have a base object that I can use to invoke events on
>
> I suspect I want some form of mixin (as shown here
> http://kozmic.pl/2009/08/12/castle-dynamic-proxy-tutorial-part-xiii-mix-in-this-mix)
> but I'm not sure about that. If anybody has any good suggestions then that
> would be awesome.
>
> In case it's necessary I've attached a C# code file with the example
> code.
>
> With kind regards
>
> Patrick van der Velde
> --
> You received this message because you are subscribed to the Google Groups
> "Castle Project Users" group.
> To post to this group, send email to [email protected]
> .
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/castle-project-users?hl=en.
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Castle Project Users" group.
> To post to this group, send email to [email protected]
> .
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/castle-project-users?hl=en.
>
--
You received this message because you are subscribed to the Google Groups
"Castle Project Users" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/castle-project-users?hl=en.