Wcf facility already handles that OOTB, without any need for code generation.

On 12/08/2010 1:43 AM, LOBOMINATOR wrote:
Hello

http://wcfproxygenerator.codeplex.com/releases/view/28579
The sample has an Abstract class ExceptionHandlingProxyBase<T>  which
does implement logic to close and regenerate WCF proxies when an
exception occurs.

     [ServiceContract]
     public interface IFoo
     {
      [OperationContract]
void Bar();
int BarWithReturn();
void BarWithParam(int yeah);
     }

How can I use dynamic proxy to generate a class which looks like this:

public class Proxy : ExceptionHandlingProxyBase<IFoo>, IFoo
{
public void Bar() {
    base.Invoke("Bar");
}
public int Bar() {
    return base.Invoke("Bar");
}
public void BarWithParam(int yeah) {
base.Invoke("BarWithParam", yeah);
}
}

Here the ExceptionHandlingProxyBase

    public class ExceptionHandlingProxyBase<T>  : ICommunicationObject,
IDisposable
          where T : class
     {
         // state
         private bool IsOpened { get; set; }
         public bool IsDisposed { get; private set; }

         // lock
         private object m_channelLock = new object();
         private bool m_isInitialized = false;
         private bool m_isProxyCreated = false;
         private ManualResetEvent m_proxyRecreationLock = new
ManualResetEvent(true);
         protected int m_proxyRecreationLockWait = 1000;

         // channel
         private ChannelFactory<T>  m_channelFactory = null;
         private T m_channel = default(T);

         #region Constructors

         public ExceptionHandlingProxyBase()
         {
         }

         public ExceptionHandlingProxyBase(string
endpointConfigurationName)
         {
             Initialize(endpointConfigurationName);
         }

         protected virtual void Initialize(string
endpointConfigurationName)
         {
             if (this.m_isInitialized) throw new
InvalidOperationException("Object already initialized.");
             this.m_isInitialized = true;

             m_channelFactory = new
ChannelFactory<T>(endpointConfigurationName);
         }

         public ExceptionHandlingProxyBase(string
endpointConfigurationName, string remoteAddress)
         {
             Initialize(endpointConfigurationName, remoteAddress);
         }

         protected virtual void Initialize(string
endpointConfigurationName, string remoteAddress)
         {
             if (this.m_isInitialized) throw new
InvalidOperationException("Object already initialized.");
             this.m_isInitialized = true;

             m_channelFactory = new
ChannelFactory<T>(endpointConfigurationName, new
EndpointAddress(remoteAddress));
         }

         public ExceptionHandlingProxyBase(Binding binding,
EndpointAddress remoteAddress)
         {
             Initialize(binding, remoteAddress);
         }

         protected virtual void Initialize(Binding binding,
EndpointAddress remoteAddress)
         {
             if (this.m_isInitialized) throw new
InvalidOperationException("Object already initialized.");
             this.m_isInitialized = true;

             m_channelFactory = new ChannelFactory<T>(binding,
remoteAddress);
         }

         #endregion

         #region Proxy creation

         public event EventHandler AfterRecreateProxy;

         protected virtual void CreateProxy()
         {

             lock (this.m_channelLock)
             {
                 if (this.m_isProxyCreated) throw new
InvalidOperationException("Proxy already created.");
                 CreateInnerChannel();
                 this.m_isProxyCreated = true;

             }
         }

         protected virtual void RecreateProxy()
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 CreateInnerChannel();

                 if (AfterRecreateProxy != null)
                     AfterRecreateProxy(this, null);
             }
         }

         private void CreateInnerChannel()
         {
             lock (this.m_channelLock)
             {
                 if (m_channelFactory == null)
                     throw new InvalidOperationException("Proxy
invalid. This occurs when you use the default constructor.");

                 m_channel = m_channelFactory.CreateChannel();

                 ICommunicationObject co = m_channel as
ICommunicationObject;
                 co.Faulted += InnerChannel_Faulted;
                 co.Closed += InnerChannel_Closed;
                 co.Closing += InnerChannel_Closing;
                 co.Opened += InnerChannel_Opened;
                 co.Opening += InnerChannel_Opening;
             }
         }
         #endregion

         #region Communication events

         private void InnerChannel_Opening(object sender, EventArgs e)
         {
             lock (m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 if (this.Opening != null)
                     this.Opening(sender, e);
             }
         }

         private void InnerChannel_Opened(object sender, EventArgs e)
         {
             lock (m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 if (this.Opened != null)
                     this.Opened(sender, e);
             }
         }


         void InnerChannel_Closing(object sender, EventArgs e)
         {
             lock (m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 if (this.Closing != null)
                     this.Closing(sender, e);
             }
         }
         private void InnerChannel_Closed(object sender, EventArgs e)
         {
             lock (m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 try
                 {
                     this.m_proxyRecreationLock.Reset(); // will stop
other threads from trying to Invoke() while recreating the proxy

                     if (this.Closed != null)
                         this.Closed(sender, e);

                     OnClosed();
                 }
                 finally
                 {
                     this.m_proxyRecreationLock.Set(); // will stop
other threads from trying to Invoke() while recreating the proxy
                 }

             }

         }
         protected virtual void OnClosed()
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 this.Abort();
                 RecreateProxy();

             }
         }


         private void InnerChannel_Faulted(object sender, EventArgs e)
         {
             lock (m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 try
                 {
                     this.m_proxyRecreationLock.Reset(); // will stop
other threads from trying to Invoke() while recreating the proxy

                     if (this.Faulted != null)
                         this.Faulted(sender, e);

                     OnFaulted();
                 }
                 finally
                 {
                     this.m_proxyRecreationLock.Set(); // will stop
other threads from trying to Invoke() while recreating the proxy
                 }
             }

         }
         protected virtual void OnFaulted()
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 this.Abort();
                 RecreateProxy();
             }
         }

         #endregion

         # region Channel Properties
         public IClientChannel InnerChannel
         {
             get
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 return (IClientChannel)m_channel;
             }
         }

         public ClientCredentials ClientCredentials
         {
             get
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 return m_channelFactory.Credentials;
             }
         }

         public ServiceEndpoint Endpoint
         {
             get
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 return m_channelFactory.Endpoint;
             }
         }

         public CommunicationState State
         {
             get
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 IChannel channel = (IChannel)m_channel;
                 if (channel == null)
                     return CommunicationState.Created;

                 return channel.State;
             }
         }

         #endregion

         #region ICommunicationObject Members

         public event EventHandler Closed;
         public event EventHandler Closing;
         public event EventHandler Faulted;
         public event EventHandler Opened;
         public event EventHandler Opening;

         public void Abort()
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 ICommunicationObject co =
(ICommunicationObject)m_channel;
                 co.Closed -= new
EventHandler(this.InnerChannel_Closed);
                 co.Closing -= new
EventHandler(this.InnerChannel_Closing);
                 co.Faulted -= new
EventHandler(this.InnerChannel_Faulted);
                 co.Opened -= new
EventHandler(this.InnerChannel_Opened);
                 co.Opening -= new
EventHandler(this.InnerChannel_Opening);
                 co.Abort();
             }
         }

         public void Open(TimeSpan timeout)
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 if (!this.IsOpened)
                 {
                     EnsureProxy();
                     ((ICommunicationObject)m_channel).Open(timeout);
                     this.IsOpened = true;
                 }
             }
         }

         public void Open()
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");

                 if (!this.IsOpened)
                 {
                     EnsureProxy();
                     ((ICommunicationObject)m_channel).Open();
                     this.IsOpened = true;
                 }
             }
         }

         public void Close(TimeSpan timeout)
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
                 ((ICommunicationObject)m_channel).Close(timeout);
             }
         }

         public void Close()
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
                 ((ICommunicationObject)m_channel).Close();
             }
         }

         public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback
callback, object state)
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
                 return
((ICommunicationObject)m_channel).BeginClose(timeout, callback,
state);
             }
         }

         public IAsyncResult BeginClose(AsyncCallback callback, object
state)
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
                 return
((ICommunicationObject)m_channel).BeginClose(callback, state);
             }
         }

         public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback
callback, object state)
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
                 return
((ICommunicationObject)m_channel).BeginClose(timeout, callback,
state);
             }
         }

         public IAsyncResult BeginOpen(AsyncCallback callback, object
state)
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
                 return
((ICommunicationObject)m_channel).BeginOpen(callback, state);
             }
         }

         public void EndClose(IAsyncResult result)
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
                 ((ICommunicationObject)m_channel).EndClose(result);
             }
         }

         public void EndOpen(IAsyncResult result)
         {
             lock (this.m_channelLock)
             {
                 if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
                 ((ICommunicationObject)m_channel).EndOpen(result);
             }
         }


         #endregion

         #region IDisposable Members

         public void Dispose()
         {
             lock (m_channelLock)
             {
                 Cleanup();
                 this.IsDisposed = true;
             }
         }

         protected virtual void Cleanup()
         {
             try
             {
                 ICommunicationObject co =
(ICommunicationObject)m_channel;
                 co.Closed -= InnerChannel_Closed;
                 co.Closing -= InnerChannel_Closing;
                 co.Faulted -= InnerChannel_Faulted;
                 co.Opened -= InnerChannel_Opened;
                 co.Opening -= InnerChannel_Opening;
                 co.Close();
             }
             catch
             {
                 try
                 {
                     ICommunicationObject co =
(ICommunicationObject)m_channel;
                     co.Abort();
                 }
                 catch { }
             }

             try
             {
                 m_channelFactory.Close();
             }
             catch
             {
                 try
                 {
                     m_channelFactory.Abort();
                 }
                 catch { }
             }

         }

         #endregion

         #region Invoke

         public delegate void RetryInvokeHandler(out Message
unreadMessage);
         public event RetryInvokeHandler RetryInvoke;

         protected void Invoke(string operationName, params object[]
parameters)
         {
             if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
             this.Open();

             MethodInfo methodInfo = GetMethod(operationName);

             try
             {
                 // manual reset event here, turn it on when faulted
                 // other threads will queue, and get a successful
Invoke() once proxy is recreated

this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait); //
if this takes longer than 1 second we have bigger problems
                 methodInfo.Invoke(m_channel, parameters);
             }
             catch (TargetInvocationException targetEx) // Invoke()
always throws this type
             {
                 CommunicationException commEx =
targetEx.InnerException as CommunicationException;
                 if (commEx == null)
                 {
                     throw targetEx.InnerException; // not a
communication exception, throw it
                 }

                 FaultException faultEx = commEx as FaultException;
                 if (faultEx != null)
                 {
                     throw targetEx.InnerException; // the service
threw a fault, throw it
                 }

                 try
                 {
                     // manual reset event here, turn it on when
faulted
                     // other threads will queue, and get a successful
Invoke() once proxy is recreated

this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait); //
if this takes longer than 1 second we have bigger problems

                     // if it is a Message type it won't work, must
fire RetryInvoke() and hopefully derived class will supply the
original
                     // message to send again...
                     if (parameters.Length == 1&&  parameters[0] is
Message)
                     {
                         Message unreadMessage;
                         RetryInvoke(out unreadMessage);
                         methodInfo.Invoke(m_channel, new object[]
{ unreadMessage }); // a communication exception, retry once
                     }
                     else
                         methodInfo.Invoke(m_channel, parameters); // a
communication exception, retry once
                 }
                 catch (TargetInvocationException targetEx2)
                 {
                     throw targetEx2.InnerException; // still failed,
throw it
                 }
             }
         }

         protected TResult Invoke<TResult>(string operationName, params
object[] parameters)
         {
             MethodInfo methodInfo = GetMethod(operationName);
             return Invoke<TResult>(methodInfo, parameters);
         }

         protected TResult Invoke<TResult>(MethodInfo methodInfo,
params object[] parameters)
         {

             if (this.IsDisposed) throw new
InvalidOperationException("Cannot use disposed object.");
             this.Open();

             TResult result = default(TResult);

             try
             {
                 // manual reset event here, turn it on when faulted
                 // other threads will queue, and get a successful
Invoke() once proxy is recreated

this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait); //
if this takes longer than 1 second we have bigger problems
                 result = (TResult)methodInfo.Invoke(m_channel,
parameters);
             }
             catch (TargetInvocationException targetEx) // Invoke()
always throws this type
             {
                 CommunicationException commEx =
targetEx.InnerException as CommunicationException;
                 if (commEx == null)
                 {
                     throw targetEx.InnerException; // not a
communication exception, throw it
                 }

                 FaultException faultEx = commEx as FaultException;
                 if (faultEx != null)
                 {
                     throw targetEx.InnerException; // the service
threw a fault, throw it
                 }

                 // a communication exception, retry once
                 try
                 {
                     // manual reset event here, turn it on when
faulted
                     // other threads will queue, and get a successful
Invoke() once proxy is recreated

this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait); //
if this takes longer than 1 second we have bigger problems

                     // if it is a Message type it won't work, must
fire RetryInvoke() and hopefully derived class will supply the
original
                     // message to send again...
                     if (parameters.Length == 1&&  parameters[0] is
Message)
                     {
                         Message unreadMessage;
                         RetryInvoke(out unreadMessage);
                         result = (TResult)methodInfo.Invoke(m_channel,
new object[] { unreadMessage }); // communication exception, retry
once
                     }
                     else
                         result = (TResult)methodInfo.Invoke(m_channel,
parameters); // communication exception, retry once

                 }
                 catch (TargetInvocationException targetEx2)
                 {
                     throw targetEx2.InnerException; // still failed,
throw it
                 }
             }

             return result;
         }

         internal MethodInfo GetMethod(string operationName)
         {
             Type t = typeof(T);

             HashSet<MethodInfo>  methods = new HashSet<MethodInfo>();
             GetMethodsRecursive(t, BindingFlags.Public |
BindingFlags.Instance, ref methods);

             var result = from m in methods
                          where m.Name == operationName
                          select m;

             if (result.Count() == 0)
                 throw new
InvalidOperationException(String.Format("Unable to invoke method {0}.
Method does not exist on contract {1}.", operationName,
t.ToString()));

             if (result.Count()>  1)
                 throw new
InvalidOperationException(String.Format("Unable to invoke method {0}.
More than one method is defined on contract {1} by the same name.
Overloads not supported by CachedProxyBase.", operationName,
t.ToString()));

             return result.First();
         }

         private void GetMethodsRecursive(Type t, BindingFlags flags,
ref HashSet<MethodInfo>  methods)
         {
             MethodInfo[] children = t.GetMethods(flags);
             methods.UnionWith(children);
             foreach (Type contract in t.GetInterfaces())
             {
                 GetMethodsRecursive(contract, flags, ref methods);
             }
         }

         private void EnsureProxy()
         {
             lock (this.m_channelLock)
             {
                 if (!this.m_isProxyCreated)
                 {
                     this.CreateProxy();
                 }
             }
         }

         #endregion

     }


--
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.

Reply via email to