WCF Dynamic ClientBase Proxy part two
January 15, 2008 12:10 pm .Net, Readify, Tools, WCFA while ago I wrote a Reusable Client Proxy that allows you to reuse the ClientBase proxy even if it faults without the developer having to take care of the complicated lifetime management and make sure it is closing the proxy if it gets into a faulted state.
After several months of using this proxy and some good feedback I started to write a new version of this proxy and do several small changes:
- Fixed bug that proxy was not correctly generated if there were multiple levels of inheritance on the contract interface.
- Added an IClientBase interface that gets implemented automatically that gives access from outside to the ClientBase specific properties (ClientCredentials, EndPoint, InnerChannel and State)
- Added an event on this interface: ProxyCreated that gets triggerd after a new instance of the proxy was created (e.g. due to a fault) so you can reinitialize the proxy, set the ClientCredentials or any other operations you want to do with the IClientBase.
- Added support to automatically unwrap Exceptions out of FaultExceptions.
- The assembly is now signed by default so you can start using it immediatelly.
Implementation details:
FIX: Proxy was not correctly generated for multi-inheritance interfaces
Trying to create a proxy on the IService2 was failing as the code was not generating the MyOperation1 method:
[ServiceContract()] public interface IService1 { [OperationContract] string MyOperation1(string arg1, int arg2); } [ServiceContract()] public interface IService2 : IService1 { [OperationContract] void MyOperation2(string value); }
Added the IClientBase interface to the generated proxies
A new IClientBase interface was added and all the relevant properties and methods from the real ClientBase<T> class are now exposed.
The interface is only exposed on the objects returned by the GetReusableInstance method.
A new event was also added on the interface: ProxyCreated that is fired every time a new proxy had to be created due to the old one failing.
The event can be used to apply custom ClientCredentials or behaviours.
public delegate void ProxyCreatedHandler(IClientBase proxy); /// <summary> /// Interface to expose the inner ClientBase properties hidden by the Proxy /// </summary> public interface IClientBase { /// <summary> /// Fired when a new proxy is created. /// In here you can initialize the Credentials and EndPoints. /// </summary> event ProxyCreatedHandler ProxyCreated; /// <summary> /// Gets the client credentials used to call an operation. /// Returns a System.ServiceModel.Description.ClientCredentials that represents /// the proof of identity presented by the client. /// </summary> ClientCredentials ClientCredentials { get; } /// <summary> /// Gets the target endpoint for the service to which the WCF client can connect. /// </summary> ServiceEndpoint Endpoint { get; } /// <summary> /// Gets the underlying System.ServiceModel.IClientChannel implementation. /// </summary> /// <value>The client channel for the WCF client object.</value> IClientChannel InnerChannel { get; } /// <summary> /// Gets the current state of the System.ServiceModel.ClientBase<TChannel> object. /// </summary> CommunicationState State { get; } /// <summary> /// Causes the System.ServiceModel.ClientBase<TChannel> object to transition // immediately from its current state into the closed state. /// </summary> void Abort(); /// <summary> /// Causes the System.ServiceModel.ClientBase<TChannel> object to transition // from its current state into the closed state. /// </summary> void Close(); /// <summary> /// Causes the System.ServiceModel.ClientBase<TChannel> object to transition // from the created state into the opened state. /// </summary> void Open(); }
Having the new ProxyCreated event allows a much cleaner type of code to be implemented.
For example if you know you need custom username/password authorization you can subscribe to the event:
IService1 service = WCFClientProxy<IService1>.GetReusableInstance("Service1"); (service as IClientBase).ProxyCreated += new ProxyCreatedHandler(Program_ProxyCreated);
Then handle the event to do the custom authorization:
static void Program_ProxyCreated(IClientBase proxy) { proxy.ClientCredentials.UserName.UserName = "myUser"; proxy.ClientCredentials.UserName.Password = "myPassword"; }
Other changes
- Renamed GetWrappedInstance to GetReusableInstance.
- Dropped the references to the Enterprise Library just in case you don’t use them so the assembly has no external references.
- Set the version number to 1.2.0.
Update: You can find the Readify.WCF.DynamicClientProxy 1.2 including the source code here.
January 16th, 2008 at 12:40 am
Hi Corneliu,
First, very nice work you’ve done here!
Last time you released this dynamic clientbase proxy with the source code. Is there a possiblity that you can send me the code base? That would save me quite some work
Thank you!
January 16th, 2008 at 8:32 am
RJ,
I’ve updated the link to include the source code as well.
Enjoy,
Corneliu.
March 4th, 2008 at 7:31 am
Hi Corneliu,
I implemented something similar, but I used RealProxy under the covers. For performance, I implemented a method cache of method handles rather than constantly resolving a MethodBase from a string name and set of parameters.
March 4th, 2008 at 8:25 am
Rory,
Once you create the first proxy for a specific interface I cache the proxy type so there is no need to cache the method handle anymore as all the calls are emited and there is no reflection used at all once you have the proxy instance.
Corneliu.
April 20th, 2008 at 12:55 pm
How do we dispose of the client proxy? After a while it runs out of connections. I think that’s the reason ClientBase implemented IDisposable to encourage people to dispose of the client and not keep it around for a long time. Reusing the same client around in one method call or method call chain is fine, but we should drop the connection as soon as we’re done.
April 20th, 2008 at 1:07 pm
Nevermind ignore my last comment — I figured it out. I’m stupid
May 10th, 2008 at 7:54 am
Thanks for the great source. I’m particularly interested in how you cache subsequent proxy generation. Looked through the code and don’t see it. Could you help me out to understand it?
May 10th, 2008 at 7:58 am
Disregard the previous comment.
May 10th, 2008 at 8:04 am
How does one actually use the code? Any samples? I see the caching and I see the classes but how you actuall use it? Please help out.
May 15th, 2008 at 12:32 pm
Jeff,
Part one (http://www.acorns.com.au/blog/?p=86) had example how to use the client proxy.
Basically all you do have to do is:
IService1 service = WCFClientProxy.GetWrappedInstance(“Service1“);
This will get a WCF instance to your service all wrapped and ready to use.
The code does not cache the proxy itself. It will cache the class type used to generate the proxy so next time you ask for it, it instantiates it and is ready to go.
Regards,
Corneliu.
June 13th, 2008 at 3:00 am
Hi Corneliu,
Have you already think about generating asynchronous operations, if they are in the interface for example with a custom attribute like this :
void DoWork();
[AsyncMethod(AsyncType.Begin, "DoWork")]
void BeginDoWork();
[AsyncMethod(AsyncType.End, "DoWork")]
void EndDoWork();
Your Dynamic client proxy seems to be very good, and is exactly what I was looking for but loosing asynchronous operations can be a problem in some cases I think.
Ben.
June 13th, 2008 at 9:11 am
Ben,
That sounds interesting. I’ll look into that see how complex it is to build.
Regards,
Corneliu.
June 18th, 2008 at 12:47 am
thank you been looking for a username/pwd sample all over the place
August 12th, 2008 at 5:12 am
Great code, thanks for posting it.
I have a quick question. If I want to set my endpoint and binding programmatically, how would I do that?
Thanks,
Darrell
September 27th, 2008 at 12:14 pm
Hi,
Thanks for this very nice code that I’m using in one app.
For any reason you got a CommunicationObjectAbortedException after a inactivity period?
I’m using net.tcp hosted on a windows service. Everything works fine until some inactivity. Calling the same operation the client throws the exception “An existing connection was forcibly closed by the remote host
“.
I put some wcf logging on the server and the exception is “The communication object, System.ServiceModel.Channels.ServerSessionPreambleConnectionReader+ServerFramingDuplexSessionChannel, cannot be used for communication because it has been Aborted.”
Could this be related with the dynamic proxy?
Thanks.
October 9th, 2008 at 6:11 pm
Hi Corneliu
Firstly awesome code.
Did you have a chance to look at asynchronous operations?
I’m using WPG and Silverlight and asynchronous is a must.
Thanks
George
October 9th, 2008 at 6:12 pm
WPG?? I meant WPF.
October 10th, 2008 at 10:41 pm
Thanks for sharing this Corneliu – saved me a ton of time.
October 16th, 2008 at 5:11 am
This is extremely useful and well done, thank you. One issue: When I use GetReusableFaultUnwrappingInstance and an exception occurs, the outer exception is still thrown and not the inner exception. (In other words the actual fault is not unwrapped.) Could you look at that again to see if there is some bug?
November 19th, 2008 at 2:19 pm
Hi Corneliu,
After making 10 calls, my service starts to freeze, and have to wait 10 mins time-out before i can use it again making more calls.
How can I increase the max connections, and also closing the proxy when its finish?
thanks
Will
December 15th, 2008 at 11:04 am
Nate,
The framework should only do that if the inner fault is NOT an exception. If the inner fault is an exception it should be properly raised. Can you please send me a sample where you have the issue.
William,
Like with all WCF connections you need to dispose them.
Easiest is to cast the received interface to IClientBase and do a using for example:
IMyService service = WCFClientProxy.GetInstance(”MyService”);
using( (IClientBase)service )
{
…..
}
This will properly close the connection once you exit the using statement.
Look at the IClientBase interface for more details.
Corneliu.
February 5th, 2009 at 7:00 pm
Excellent article! A few questions arose while digging through the sources though:
There seems to be a mismatch between WCFClientProxy.RegisterEndpoint and WCFClientProxy.GetRegisteredInstance. The first builds the type with the non-reusable’ builder. The second forwards to WCFClientProxy.GetReusableInstance and results in a different type being build. Perhaps RegisterEndpoint needs an enum to indicate which builder to use?
In the WCFAbstractReusableClientProxy.AssureProxy method a call is placed to WCFClientProxy.GetInstance… Does that mean the ‘reusability’ is limited to only once? I guess it should read GetReusableInstance here
February 17th, 2009 at 2:14 pm
[...] Automatic Disposing February 17, 2009 2:14 pm Corneliu .Net, WCF, WCF Dynamic Proxy A while ago I published a small and neat Dynamic Proxy that could be used to automatically create for you implementation of the (WCF) ClientBase<T> [...]