Generic method call code - c#

I have an interface with a bunch of methods with different signatures (context here is a WCF callback interface). My server has a list of clients. In response to events I want to call a method of the interface on every client. There is a bunch of boiler plate code around this call (check client is alive, should this client be include in list to callback, try catch, drop client if operation fails etc). Whats the best way to pull out this boiler plate code into a generic CallBackClients(SomeKindOfGenericDeligate method_to_call) where method_to_call is one of the interface methods.
ICallback {
void Fish(string my_string);
void SuperFish(int my_int, double my_double);
... etc ...
}
CallBackClients( -- ?? generic delegate ?? -- ) {
foreach (IClientCallback client in client_list) {
// The boiler plate code:
if (((ICommunicationObject)client.callback).State == CommunicationState.Opened) {
try {
Do method call based on delagate / lamda code passed in - how ??
}
catch (Exception e) {
Remove_client(client, method.ToString(), e);
}
}
else
Remove_client(client, method.ToString());
}
}
}
Pseudo code for caller:
void EventHandler_A() {
// Call Fish method on all clients:
CallBackClients(Fish("hello"));
}
void EventHandler_B() {
// Call SuperFish method on all clients:
CallBackClients(SuperFish(10, 5.3);
}

You can encapsulate a method to call later on any given IClientCallBack in an Action<IClientCallBack>:
CallBackClients(Action<IClientCallBack> actionOnDelegates) {
foreach (IClientCallback client in client_list) {
// The boiler plate code:
if (((ICommunicationObject)client.callback).State == CommunicationState.Opened) {
try {
actionOnDelegates(client);
}
catch (Exception e) {
Remove_client(client, method.ToString(), e);
}
}
else
Remove_client(client, method.ToString());
}
}
}
this would then be called like so; these create an anonymous method to call the method on the specified client:
void EventHandler_A() {
// Call Fish method on all clients:
CallBackClients(client => client.Fish("hello"));
}
void EventHandler_B() {
// Call SuperFish method on all clients:
CallBackClients(client => client.SuperFish(10, 5.3);
}

Related

Refactoring a WCF Trusted Facade

I'm attempting to refactor a "trusted facade" which currently wraps over 50 service calls to the backend. All calls have different signatures, but everything else is being repeated. The issue with the existing calls was that there was no attempt made to manage the connections, resulting in ephemeral ports remaining in the "BOUND" state.
ORIGINAL CODE:
public class ReportWeb : IReportWeb
{
ReportService.ReportClient client = new ReportClient();
...
public string[] GetAccounts() => client.GetAccounts();
}
NEW CODE:
private ChannelFactory<IReportService> _factory = null;
private IReportService _proxy = null;
private void OpenProxy()
{
_factory = new ChannelFactory<IReportService>("NetTcpBinding_IReportService");
_proxy = _factory.CreateChannel();
}
private void CloseProxy()
{
((IClientChannel)_proxy).Close();
_factory.Close();
}
One of 50+ similar methods:
public string[] GetAccounts() // Different - name, params, and return type
{
string[] accounts = null; // Different
try
{
OpenProxy();
accounts = _proxy.GetAccounts(); // Different
CloseProxy();
}
catch (Exception exception)
{
bool faulted = _factory.State == CommunicationState.Faulted;
_factory.Abort();
if (faulted)
{
throw new ApplicationException(exception.Message);
}
else
{
throw;
}
}
return accounts;
}
Another similar method:
//Another method
public ContractsInfo[] GetContracts(int contractId) // Different -
// name, params, and return type
{
ContractsInfo[] contracts = null; // Different
try
{
OpenProxy();
contracts = _proxy.GetContracts(contractId); // Different
CloseProxy();
}
catch (Exception exception)
{
bool faulted = _factory.State == CommunicationState.Faulted;
_factory.Abort();
if (faulted)
{
throw new ApplicationException(exception.Message);
}
else
{
throw;
}
}
return contracts;
}
Calling code from Web Forms project:
public string[] GetAccounts()
{
ReportClient client = NewReportClient();
string[] results = null;
try
{
results = client.GetAccounts();
client.Close();
}
catch (Exception ex)
{
client.Abort();
throw ex;
}
return results;
}
There are over fifty other methods like GetData() with different signatures. They will all be identical except for the service call in each, which will vary in params and return type. I need a more abstract, or generic, way of coding this and thus adhere to the DRY principle. Would Func<T, TResult> Delegate be appropriate here? Either way, can someone suggest a best approach here with some stub code to illustrate?
I suppose that this is the case where Generic method with can be applied. It is
possible to read about Generics here
Let me show a code example:
public class Foo
{
public T GetDate<T, UArg>(UArg arg) where T : new()
{
return new T();
}
}

Generics program to access WCF service from client

Please look at the below code where a client is accessing WCF service
Function GetPriority
public List<Priority> GetPriority()
{
List<Priority> lstPriority = new List<Priority>();
using (TmsServiceClient client = new TmsServiceClient())
{
try
{
lstPriority = client.GetPriority();
}
catch (FaultException<TMSCustomException> myFault)
{
Console.WriteLine(myFault.Detail.ExceptionMessage);
client.Abort();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
client.Abort();
}
}
return lstPriority;
}
Function GetStatus:
public List<Status> GetStatus()
{
List<Status> lstStatus = new List<Status>();
using (TmsServiceClient client = new TmsServiceClient())
{
try
{
lstStatus = client.GetStatus();
}
catch (FaultException<TMSCustomException> myFault)
{
Console.WriteLine(myFault.Detail.ExceptionMessage);
client.Abort();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
client.Abort();
}
}
return lstStatus;
}
Both the methods are working fine. As can be seen that there are many similarities between the two methods and they differ only at the time of method invocation and return type. Can this be make generic? If so how to do so? Or any other better way so that the catch exception block code should not be repeated everytime.
Thanks in advance
You can easily refactor almost entire Get ... method into generic one. The only real variable part is which client method to call, which can be easily solved using Func<T,TResult>.
private List<T> Get<T>(Func<TmsServiceClient, List<T>> clientCall)
{
List<T> results = new List<T>();
using (TmsServiceClient client = new TmsServiceClient())
{
try
{
// invoke client method passed as method parameter
results = clientCall(client);
}
catch (FaultException<TMSCustomException> myFault)
{
Console.WriteLine(myFault.Detail.ExceptionMessage);
client.Abort();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
client.Abort();
}
}
return results;
}
Now your methods implementations look like this:
public List<Status> GetStatus()
{
return Get<Status>(client => client.GetStatus());
}
public List<Priority> GetPriority()
{
return Get<Priority>(client => client.GetPriority());
}
Edit in response to OP comment:
Func<TmsServiceClient, List<T>> passed as a parameter to Get<T> method is a delegate. Delegate is kind of function pointer - an object you use to delegate some actions to be executed later (hence the name).
Func<TmsServiceClient, List<T>> is basically a delegate that takes one input argument (of TmsServiceClient type) and returns List<T> as a result.
Now, what we do in for example GetStatus? We create an instance of such delegate (via lambda expression) - and we "tell" it to execute GetStatus() method on Client object, which we will provide:
// this line works the same as in example above
// Take client as parameter call its .GetStatus method
return Get<Status>((TmsServiceClient client) => client.GetStatus());
And that exactly what happens in
// invoke client method passed as method parameter
results = clientCall(client);
line. The delegate executes method we asked for.

How to implement this with a pattern or maybe lambda syntax?

I have several methods that execute the same setup code and then some cleanup code. The stuff in between changes. I could do it like this:
void method1()
{
var x = DoSetupStuff();
// Method 1 specific code that uses x
DoCleanupStuff(x);
}
void method2()
{
var x = DoSetupStuff();
// Method 2 specific code that uses x
DoCleanupStuff(x);
}
But I'd rather do something where I don't have to call both setup and cleanup methods every time. Maybe like one call where the method specific stuff can be passed in?
void SetupAndCleanup( method-specific-code )
{
// Setup code here
int x = 1;
// method-specific code injected here.
// note that it uses x.
// cleanup code here
x = 0;
}
The method1, method2 approach works perfectly well, I'm just wandering if there is a way to improve it or make it more elegant.
If "x" is always an int you can just pass in an Action:
void SetupAndCleanup( Action<int> methodCode )
{
// Setup code here
int x = 1;
try
{
methodCode(x);
}
finally
{
// cleanup code here
x = 0;
}
}
You can use a delegate:
void SetupAndCleanup(Action action) {
// setup
action();
// cleanup
}
void Method1() {
SetupAndCleanup(() => {
// do my stuff here
});
}
// or...
private void Method2Impl() {
// do my stuff here
}
void Method2() {
SetupAndCleanup(Method2Impl);
}
or an IDisposable:
private sealed class SetupClass : IDisposable {
public SetupClass() {
// setup
}
public void Dispose() {
// cleanup
}
}
void Method1() {
using (SetupClass setup = new SetupClass() {
// do stuff here
}
}
void Method2() {
using (SetupClass setup = new SetupClass() {
// do stuff here
}
}
If you can place the Method1 & Method2 specific code into their own functions, and each could share the same method signature, then create a delegate type of the signature, and write Method1 & Method2 to conform to the signature and pass it to SetupAndCleanup. A lambda will work if you can do everything you need to using the lambda. To use the lambda just remember that the lambda follows the signature of the delegate.
Sounds like you might want to use a class:
public abstract class DoStuff
{
protected abstract void DoStuffImpl(var x);
private var DoSetupStuff()
{
} // eo DoSetupStuff
private void DoCleanupStuff(var x)
{
} // eo DoCleanupStuff
public DoStuff()
{
} // eo ctor
public void DoMethod()
{
var x = DoSetupStuff();
DoStuffImpl(x);
DoCleanupStuff(x);
} // eo DoMethod
} // eo class DoStuff
Then provide specializations:
public class Special1 : DoStuff
{
protected override DoStuffImpl(var x)
{
// work with x here
}
} // eo class Special1
public class Special2 : DoStuff
{
protected override DoStuffImpl(var x)
{
// work with x here, but in a different way
}
} // eo class Special2
// work with them
Special1 s1; s1.DoMethod();
Special2 s2; s2.DoMethod();
I'd use a method such as this:
void ExecuteMethodWithSetupAndCleanup(Action<int> method)
{
// do the setup stuff
var x = DoSetupStuff();
// run the provided code
method(x);
// do the cleanup stuff
DoCleanupStuff(x);
}
And then use it like this:
void method1()
{
ExecuteMethodWithSetupAndCleanup(x =>
{
// here is the method1 specific code using x
}
}
void method2()
{
ExecuteMethodWithSetupAndCleanup(x =>
{
// here is the method2 specific code using x
}
}
Alternatively, if you already have method1() and method2() and you want to keep them separate, and only remove the setup/cleanup from them, you can do something like this:
void method1(int x)
{
// here is the method1 specific code using x
}
void method2(int x)
{
// here is the method2 specific code using x
}
void ExecuteMethod1AndMethod2()
{
ExecuteMethodWithSetupAndCleanup(method1);
ExecuteMethodWithSetupAndCleanup(method2);
}
How about something like:
protected Action DoSetupStuff()
{
//... setup code
Action cleanup = () =>
{
//... prepare cleanup code for later
};
return cleanup;
}
void DoSomethingUseful()
{
var cleanup = DoSetupStuff();
// do something useful
cleanup();
}
This way, your setup method prepares its own cleanup code, and your primary DoSomethingUseful method never has to know about it.

Loan Pattern / Automatic Resource Management in Java

I have tried to implement automatic resource management for Java (something like C#'s using). Following is the code I have come up with:
import java.lang.reflect.*;
import java.io.*;
interface ResourceUser<T> {
void use(T resource);
}
class LoanPattern {
public static <T> void using(T resource, ResourceUser<T> user) {
Method closeMethod = null;
try {
closeMethod = resource.getClass().getMethod("close");
user.use(resource);
}
catch(Exception x) {
x.printStackTrace();
}
finally {
try {
closeMethod.invoke(resource);
}
catch(Exception x) {
x.printStackTrace();
}
}
}
public static void main(String[] args) {
using(new PrintWriter(System.out,true), new ResourceUser<PrintWriter>() {
public void use(PrintWriter writer) {
writer.println("Hello");
}
});
}
}
Please analyze the above code and let me know of any possible flaws and also suggest how I can improve this. Thank you.
(Sorry for my poor English. I am not a native English speaker.)
I would modify your using method like:
public static <T> void using(T resource, ResourceUser<T> user) {
try {
user.use(resource);
} finally {
try {
Method closeMethod = resource.getClass().getMethod("close");
closeMethod.invoke(resource);
} catch (NoSuchMethodException e) {
// not closable
} catch (SecurityException e) {
// not closable
}
}
}
Also, you need to define the behavior you want for the case that the resource is not closable (when you catch the above exceptions). You can either throw a specific exception like UnclosableResourceException or completely ignore this case. You can even implement 2 methods with these 2 behaviors (using and tryUsing).

What is the best workaround for the WCF client `using` block issue?

I like instantiating my WCF service clients within a using block as it's pretty much the standard way to use resources that implement IDisposable:
using (var client = new SomeWCFServiceClient())
{
//Do something with the client
}
But, as noted in this MSDN article, wrapping a WCF client in a using block could mask any errors that result in the client being left in a faulted state (like a timeout or communication problem). Long story short, when Dispose() is called, the client's Close() method fires, but throws an error because it's in a faulted state. The original exception is then masked by the second exception. Not good.
The suggested workaround in the MSDN article is to completely avoid using a using block, and to instead instantiate your clients and use them something like this:
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
Compared to the using block, I think that's ugly. And a lot of code to write each time you need a client.
Luckily, I found a few other workarounds, such as this one on the (now defunct) IServiceOriented blog. You start with:
public delegate void UseServiceDelegate<T>(T proxy);
public static class Service<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");
public static void Use(UseServiceDelegate<T> codeBlock)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
}
Which then allows:
Service<IOrderService>.Use(orderService =>
{
orderService.PlaceOrder(request);
});
That's not bad, but I don't think it's as expressive and easily understandable as the using block.
The workaround I'm currently trying to use I first read about on blog.davidbarret.net. Basically, you override the client's Dispose() method wherever you use it. Something like:
public partial class SomeWCFServiceClient : IDisposable
{
void IDisposable.Dispose()
{
if (this.State == CommunicationState.Faulted)
{
this.Abort();
}
else
{
this.Close();
}
}
}
This appears to be able to allow the using block again without the danger of masking a faulted state exception.
So, are there any other gotchas I have to look out for using these workarounds? Has anybody come up with anything better?
Actually, although I blogged (see Luke's answer), I think this is better than my IDisposable wrapper. Typical code:
Service<IOrderService>.Use(orderService=>
{
orderService.PlaceOrder(request);
});
(edit per comments)
Since Use returns void, the easiest way to handle return values is via a captured variable:
int newOrderId = 0; // need a value for definite assignment
Service<IOrderService>.Use(orderService=>
{
newOrderId = orderService.PlaceOrder(request);
});
Console.WriteLine(newOrderId); // should be updated
Given a choice between the solution advocated by IServiceOriented.com and the solution advocated by David Barret's blog, I prefer the simplicity offered by overriding the client's Dispose() method. This allows me to continue to use the using() statement as one would expect with a disposable object. However, as #Brian pointed out, this solution contains a race condition in that the State might not be faulted when it is checked but could be by the time Close() is called, in which case the CommunicationException still occurs.
So, to get around this, I've employed a solution that mixes the best of both worlds.
void IDisposable.Dispose()
{
bool success = false;
try
{
if (State != CommunicationState.Faulted)
{
Close();
success = true;
}
}
finally
{
if (!success)
Abort();
}
}
I wrote a higher order function to make it work right. We've used this in several projects and it seems to work great. This is how things should have been done from the start, without the "using" paradigm or so on.
TReturn UseService<TChannel, TReturn>(Func<TChannel, TReturn> code)
{
var chanFactory = GetCachedFactory<TChannel>();
TChannel channel = chanFactory.CreateChannel();
bool error = true;
try {
TReturn result = code(channel);
((IClientChannel)channel).Close();
error = false;
return result;
}
finally {
if (error) {
((IClientChannel)channel).Abort();
}
}
}
You can make calls like this:
int a = 1;
int b = 2;
int sum = UseService((ICalculator calc) => calc.Add(a, b));
Console.WriteLine(sum);
This is pretty much just like you have in your example. In some projects, we write strongly typed helper methods, so we end up writing things like "Wcf.UseFooService(f=>f...)".
I find it quite elegant, all things considered. Is there a particular problem you encountered?
This allows other nifty features to be plugged in. For instance, on one site, the site authenticates to the service on behalf of the logged in user. (The site has no credentials by itself.) By writing our own "UseService" method helper, we can configure the channel factory the way we want, etc. We're also not bound to using the generated proxies -- any interface will do.
This is Microsoft's recommended way to handle WCF client calls:
For more detail see: Expected Exceptions
try
{
...
double result = client.Add(value1, value2);
...
client.Close();
}
catch (TimeoutException exception)
{
Console.WriteLine("Got {0}", exception.GetType());
client.Abort();
}
catch (CommunicationException exception)
{
Console.WriteLine("Got {0}", exception.GetType());
client.Abort();
}
Additional information
So many people seem to be asking this question on WCF that Microsoft even created a dedicated sample to demonstrate how to handle exceptions:
c:\WF_WCF_Samples\WCF\Basic\Client\ExpectedExceptions\CS\client
Download the sample:
C# or VB
Considering that there are so many issues involving the using statement, (heated?) Internal discussions and threads on this issue, I'm not going to waste my time trying to become a code cowboy and find a cleaner way. I'll just suck it up, and implement WCF clients this verbose (yet trusted) way for my server applications.
Optional Additional Failures to catch
Many exceptions derive from CommunicationException and I don't think most of those exceptions should be retried. I drudged through each exception on MSDN and found a short list of retry-able exceptions (in addition to TimeOutException above). Do let me know if I missed an exception that should be retried.
// The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
catch (ChannelTerminatedException cte)
{
secureSecretService.Abort();
// todo: Implement delay (backoff) and retry
}
// The following is thrown when a remote endpoint could not be found or reached. The endpoint may not be found or
// reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
catch (EndpointNotFoundException enfe)
{
secureSecretService.Abort();
// todo: Implement delay (backoff) and retry
}
// The following exception that is thrown when a server is too busy to accept a message.
catch (ServerTooBusyException stbe)
{
secureSecretService.Abort();
// todo: Implement delay (backoff) and retry
}
Admittedly, this is a bit of mundane code to write. I currently prefer this answer, and don't see any "hacks" in that code that may cause issues down the road.
I've finally found some solid steps towards a clean solution to this problem.
This custom tool extends WCFProxyGenerator to provide an exception handling proxy. It generates an additional proxy called ExceptionHandlingProxy<T> which inherits ExceptionHandlingProxyBase<T> - the latter of which implements the meat of the proxy's functionality. The result is that you can choose to use the default proxy that inherits ClientBase<T> or ExceptionHandlingProxy<T> which encapsulates managing the lifetime of the channel factory and channel. ExceptionHandlingProxy respects your selections in the Add Service Reference dialog with respect to asynchronous methods and collection types.
Codeplex has a project called Exception Handling WCF Proxy Generator. It basically installs a new custom tool to Visual Studio 2008, then use this tool to generate the new service proxy (Add service reference). It has some nice functionality to deal with faulted channels, timeouts and safe disposal. There's an excellent video here called ExceptionHandlingProxyWrapper explaining exactly how this works.
You can safely use the Using statement again, and if the channel is faulted on any request (TimeoutException or CommunicationException), the Wrapper will re-initialize the faulted channel and retry the query. If that fails then it will call the Abort() command and dispose of the proxy and rethrow the Exception. If the service throws a FaultException code it will stop executing, and the proxy will be aborted safely throwing the correct exception as expected.
Based on answers by Marc Gravell, MichaelGG, and Matt Davis, our developers came up with the following:
public static class UsingServiceClient
{
public static void Do<TClient>(TClient client, Action<TClient> execute)
where TClient : class, ICommunicationObject
{
try
{
execute(client);
}
finally
{
client.DisposeSafely();
}
}
public static void DisposeSafely(this ICommunicationObject client)
{
if (client == null)
{
return;
}
bool success = false;
try
{
if (client.State != CommunicationState.Faulted)
{
client.Close();
success = true;
}
}
finally
{
if (!success)
{
client.Abort();
}
}
}
}
Example of use:
string result = string.Empty;
UsingServiceClient.Do(
new MyServiceClient(),
client =>
result = client.GetServiceResult(parameters));
It's as close to the "using" syntax as possible, you don't have to return a dummy value when calling a void method, and you can make multiple calls to the service (and return multiple values) without having to use tuples.
Also, you can use this with ClientBase<T> descendants instead of ChannelFactory if desired.
The extension method is exposed if a developer wants to manually dispose of a proxy/channel instead.
#Marc Gravell
Wouldn't it be OK to use this:
public static TResult Using<T, TResult>(this T client, Func<T, TResult> work)
where T : ICommunicationObject
{
try
{
var result = work(client);
client.Close();
return result;
}
catch (Exception e)
{
client.Abort();
throw;
}
}
Or, the same thing (Func<T, TResult>) in case of Service<IOrderService>.Use
These would make returning variables easier.
What is this?
This is the CW version of the accepted answer but with (what I consider complete) Exception handling included.
The accepted answer references this website that is no longer around. To save you trouble, I am including the most relevant parts here. In addition, I modified it slightly to include exception retry handling to handle those pesky network timeouts.
Simple WCF Client Usage
Once you generate your client side proxy, this is all you need to implement it.
Service<IOrderService>.Use(orderService=>
{
orderService.PlaceOrder(request);
});
ServiceDelegate.cs
Add this file to your solution. No changes are needed to this file, unless you want to alter the number of retries or what exceptions you want to handle.
public delegate void UseServiceDelegate<T>(T proxy);
public static class Service<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");
public static void Use(UseServiceDelegate<T> codeBlock)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
Exception mostRecentEx = null;
int millsecondsToSleep = 1000;
for(int i=0; i<5; i++) // Attempt a maximum of 5 times
{
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
break;
}
// The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
catch (ChannelTerminatedException cte)
{
mostRecentEx = cte;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
// The following is thrown when a remote endpoint could not be found or reached. The endpoint may not be found or
// reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
catch (EndpointNotFoundException enfe)
{
mostRecentEx = enfe;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
// The following exception that is thrown when a server is too busy to accept a message.
catch (ServerTooBusyException stbe)
{
mostRecentEx = stbe;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch (TimeoutException timeoutEx)
{
mostRecentEx = timeoutEx;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch (CommunicationException comException)
{
mostRecentEx = comException;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch(Exception )
{
// rethrow any other exception not defined here
// You may want to define a custom Exception class to pass information such as failure count, and failure type
proxy.Abort();
throw ;
}
}
if (success == false && mostRecentEx != null)
{
proxy.Abort();
throw new Exception("WCF call failed after 5 retries.", mostRecentEx );
}
}
}
PS: I've made this post a community wiki. I won't collect "points" from this answer, but prefer you upvote it if you agree with the implementation, or edit it to make it better.
Below is an enhanced version of the source from the question and extended to cache multiple channel factories and attempt to look up the endpoint in the configuration file by contract name.
It uses .NET 4 (specifically: contravariance, LINQ, var):
/// <summary>
/// Delegate type of the service method to perform.
/// </summary>
/// <param name="proxy">The service proxy.</param>
/// <typeparam name="T">The type of service to use.</typeparam>
internal delegate void UseServiceDelegate<in T>(T proxy);
/// <summary>
/// Wraps using a WCF service.
/// </summary>
/// <typeparam name="T">The type of service to use.</typeparam>
internal static class Service<T>
{
/// <summary>
/// A dictionary to hold looked-up endpoint names.
/// </summary>
private static readonly IDictionary<Type, string> cachedEndpointNames = new Dictionary<Type, string>();
/// <summary>
/// A dictionary to hold created channel factories.
/// </summary>
private static readonly IDictionary<string, ChannelFactory<T>> cachedFactories =
new Dictionary<string, ChannelFactory<T>>();
/// <summary>
/// Uses the specified code block.
/// </summary>
/// <param name="codeBlock">The code block.</param>
internal static void Use(UseServiceDelegate<T> codeBlock)
{
var factory = GetChannelFactory();
var proxy = (IClientChannel)factory.CreateChannel();
var success = false;
try
{
using (proxy)
{
codeBlock((T)proxy);
}
success = true;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
/// <summary>
/// Gets the channel factory.
/// </summary>
/// <returns>The channel factory.</returns>
private static ChannelFactory<T> GetChannelFactory()
{
lock (cachedFactories)
{
var endpointName = GetEndpointName();
if (cachedFactories.ContainsKey(endpointName))
{
return cachedFactories[endpointName];
}
var factory = new ChannelFactory<T>(endpointName);
cachedFactories.Add(endpointName, factory);
return factory;
}
}
/// <summary>
/// Gets the name of the endpoint.
/// </summary>
/// <returns>The name of the endpoint.</returns>
private static string GetEndpointName()
{
var type = typeof(T);
var fullName = type.FullName;
lock (cachedFactories)
{
if (cachedEndpointNames.ContainsKey(type))
{
return cachedEndpointNames[type];
}
var serviceModel = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).SectionGroups["system.serviceModel"] as ServiceModelSectionGroup;
if ((serviceModel != null) && !string.IsNullOrEmpty(fullName))
{
foreach (var endpointName in serviceModel.Client.Endpoints.Cast<ChannelEndpointElement>().Where(endpoint => fullName.EndsWith(endpoint.Contract)).Select(endpoint => endpoint.Name))
{
cachedEndpointNames.Add(type, endpointName);
return endpointName;
}
}
}
throw new InvalidOperationException("Could not find endpoint element for type '" + fullName + "' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element.");
}
}
A wrapper like this would work:
public class ServiceClientWrapper<ServiceType> : IDisposable
{
private ServiceType _channel;
public ServiceType Channel
{
get { return _channel; }
}
private static ChannelFactory<ServiceType> _channelFactory;
public ServiceClientWrapper()
{
if(_channelFactory == null)
// Given that the endpoint name is the same as FullName of contract.
_channelFactory = new ChannelFactory<ServiceType>(typeof(T).FullName);
_channel = _channelFactory.CreateChannel();
((IChannel)_channel).Open();
}
public void Dispose()
{
try
{
((IChannel)_channel).Close();
}
catch (Exception e)
{
((IChannel)_channel).Abort();
// TODO: Insert logging
}
}
}
That should enable you to write code like:
ResponseType response = null;
using(var clientWrapper = new ServiceClientWrapper<IService>())
{
var request = ...
response = clientWrapper.Channel.MyServiceCall(request);
}
// Use your response object.
The wrapper could of course catch more exceptions if that is required, but the principle remains the same.
I used Castle dynamic proxy to solve the Dispose() issue, and also implemented auto-refreshing the channel when it is in an unusable state. To use this you must create a new interface that inherits your service contract and IDisposable. The dynamic proxy implements this interface and wraps a WCF channel:
Func<object> createChannel = () =>
ChannelFactory<IHelloWorldService>
.CreateChannel(new NetTcpBinding(), new EndpointAddress(uri));
var factory = new WcfProxyFactory();
var proxy = factory.Create<IDisposableHelloWorldService>(createChannel);
proxy.HelloWorld();
I like this since you can inject WCF services without consumers needing to worry about any details of WCF. And there's no added cruft like the other solutions.
Have a look at the code, it's actually pretty simple:
WCF Dynamic Proxy
Use an extension method:
public static class CommunicationObjectExtensions
{
public static TResult MakeSafeServiceCall<TResult, TService>(this TService client, Func<TService, TResult> method) where TService : ICommunicationObject
{
TResult result;
try
{
result = method(client);
}
finally
{
try
{
client.Close();
}
catch (CommunicationException)
{
client.Abort(); // Don't care about these exceptions. The call has completed anyway.
}
catch (TimeoutException)
{
client.Abort(); // Don't care about these exceptions. The call has completed anyway.
}
catch (Exception)
{
client.Abort();
throw;
}
}
return result;
}
}
If you don't need IoC or are using an autogenerated client (Service Reference), then you can simple use a wrapper to manage the closing and let the GC take the clientbase when it is in a safe state that will not throw any exception. The GC will call Dispose in serviceclient, and this will call Close. Since it is alread closed, it cannot cause any damage. I am using this without problems in production code.
public class AutoCloseWcf : IDisposable
{
private ICommunicationObject CommunicationObject;
public AutoDisconnect(ICommunicationObject CommunicationObject)
{
this.CommunicationObject = CommunicationObject;
}
public void Dispose()
{
if (CommunicationObject == null)
return;
try {
if (CommunicationObject.State != CommunicationState.Faulted) {
CommunicationObject.Close();
} else {
CommunicationObject.Abort();
}
} catch (CommunicationException ce) {
CommunicationObject.Abort();
} catch (TimeoutException toe) {
CommunicationObject.Abort();
} catch (Exception e) {
CommunicationObject.Abort();
//Perhaps log this
} finally {
CommunicationObject = null;
}
}
}
Then when you are accessing the server, you create the client and use using in the autodisconect:
var Ws = new ServiceClient("netTcpEndPointName");
using (new AutoCloseWcf(Ws)) {
Ws.Open();
Ws.Test();
}
Summary
Using the techniques described in this answer one can consume a WCF service in a using block with the following syntax:
var channelFactory = new ChannelFactory<IMyService>("");
var serviceHelper = new ServiceHelper<IMyService>(channelFactory);
var proxy = serviceHelper.CreateChannel();
using (proxy as IDisposable)
{
proxy.DoWork();
}
You can of course adapt this even further to achieve a more concise programming model specific to your situation - but the point is that we can create an implementation of IMyService reprenting the channel which correctly implements the disposable pattern.
Details
All the answers given thus far address the problem of getting around the "bug" in the WCF Channel implemention of IDisposable. The answer that seems to offer the most concise programming model (allowing you to use the using block to dispose on unmanaged resources) is this one - where the proxy is modifed to implement IDisposable with a bug-free implementation. The problem with this approach is maintainability - we have to re-implement this functionality for ever proxy we use. On a variation of this answer we will see how we can use composition rather than inheritance to make this technique generic.
First Attempt
There seem to various implementations for the IDisposable implementation, but for sake of argument we will use an adaption of that used by the currently accepted answer.
[ServiceContract]
public interface IMyService
{
[OperationContract]
void DoWork();
}
public class ProxyDisposer : IDisposable
{
private IClientChannel _clientChannel;
public ProxyDisposer(IClientChannel clientChannel)
{
_clientChannel = clientChannel;
}
public void Dispose()
{
var success = false;
try
{
_clientChannel.Close();
success = true;
}
finally
{
if (!success)
_clientChannel.Abort();
_clientChannel = null;
}
}
}
public class ProxyWrapper : IMyService, IDisposable
{
private IMyService _proxy;
private IDisposable _proxyDisposer;
public ProxyWrapper(IMyService proxy, IDisposable disposable)
{
_proxy = proxy;
_proxyDisposer = disposable;
}
public void DoWork()
{
_proxy.DoWork();
}
public void Dispose()
{
_proxyDisposer.Dispose();
}
}
Armed with the above classes we can now write
public class ServiceHelper
{
private readonly ChannelFactory<IMyService> _channelFactory;
public ServiceHelper(ChannelFactory<IMyService> channelFactory )
{
_channelFactory = channelFactory;
}
public IMyService CreateChannel()
{
var channel = _channelFactory.CreateChannel();
var channelDisposer = new ProxyDisposer(channel as IClientChannel);
return new ProxyWrapper(channel, channelDisposer);
}
}
This allows us to consume our service using the using block:
ServiceHelper serviceHelper = ...;
var proxy = serviceHelper.CreateChannel();
using (proxy as IDisposable)
{
proxy.DoWork();
}
Making this generic
All we have done so far is to reformulate Tomas' solution. What prevents this code from being generic is the fact that ProxyWrapper class has to be re-implemented for every service contract we want. We will now look at a class that allows us to create this type dynamically using IL:
public class ServiceHelper<T>
{
private readonly ChannelFactory<T> _channelFactory;
private static readonly Func<T, IDisposable, T> _channelCreator;
static ServiceHelper()
{
/**
* Create a method that can be used generate the channel.
* This is effectively a compiled verion of new ProxyWrappper(channel, channelDisposer) for our proxy type
* */
var assemblyName = Guid.NewGuid().ToString();
var an = new AssemblyName(assemblyName);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName);
var proxyType = CreateProxyType(moduleBuilder, typeof(T), typeof(IDisposable));
var channelCreatorMethod = new DynamicMethod("ChannelFactory", typeof(T),
new[] { typeof(T), typeof(IDisposable) });
var ilGen = channelCreatorMethod.GetILGenerator();
var proxyVariable = ilGen.DeclareLocal(typeof(T));
var disposableVariable = ilGen.DeclareLocal(typeof(IDisposable));
ilGen.Emit(OpCodes.Ldarg, proxyVariable);
ilGen.Emit(OpCodes.Ldarg, disposableVariable);
ilGen.Emit(OpCodes.Newobj, proxyType.GetConstructor(new[] { typeof(T), typeof(IDisposable) }));
ilGen.Emit(OpCodes.Ret);
_channelCreator =
(Func<T, IDisposable, T>)channelCreatorMethod.CreateDelegate(typeof(Func<T, IDisposable, T>));
}
public ServiceHelper(ChannelFactory<T> channelFactory)
{
_channelFactory = channelFactory;
}
public T CreateChannel()
{
var channel = _channelFactory.CreateChannel();
var channelDisposer = new ProxyDisposer(channel as IClientChannel);
return _channelCreator(channel, channelDisposer);
}
/**
* Creates a dynamic type analogous to ProxyWrapper, implementing T and IDisposable.
* This method is actually more generic than this exact scenario.
* */
private static Type CreateProxyType(ModuleBuilder moduleBuilder, params Type[] interfacesToInjectAndImplement)
{
TypeBuilder tb = moduleBuilder.DefineType(Guid.NewGuid().ToString(),
TypeAttributes.Public | TypeAttributes.Class);
var typeFields = interfacesToInjectAndImplement.ToDictionary(tf => tf,
tf => tb.DefineField("_" + tf.Name, tf, FieldAttributes.Private));
#region Constructor
var constructorBuilder = tb.DefineConstructor(
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName,
CallingConventions.Standard,
interfacesToInjectAndImplement);
var il = constructorBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[0]));
for (var i = 1; i <= interfacesToInjectAndImplement.Length; i++)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg, i);
il.Emit(OpCodes.Stfld, typeFields[interfacesToInjectAndImplement[i - 1]]);
}
il.Emit(OpCodes.Ret);
#endregion
#region Add Interface Implementations
foreach (var type in interfacesToInjectAndImplement)
{
tb.AddInterfaceImplementation(type);
}
#endregion
#region Implement Interfaces
foreach (var type in interfacesToInjectAndImplement)
{
foreach (var method in type.GetMethods())
{
var methodBuilder = tb.DefineMethod(method.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig |
MethodAttributes.Final | MethodAttributes.NewSlot,
method.ReturnType,
method.GetParameters().Select(p => p.ParameterType).ToArray());
il = methodBuilder.GetILGenerator();
if (method.ReturnType == typeof(void))
{
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, typeFields[type]);
il.Emit(OpCodes.Callvirt, method);
il.Emit(OpCodes.Ret);
}
else
{
il.DeclareLocal(method.ReturnType);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, typeFields[type]);
var methodParameterInfos = method.GetParameters();
for (var i = 0; i < methodParameterInfos.Length; i++)
il.Emit(OpCodes.Ldarg, (i + 1));
il.Emit(OpCodes.Callvirt, method);
il.Emit(OpCodes.Stloc_0);
var defineLabel = il.DefineLabel();
il.Emit(OpCodes.Br_S, defineLabel);
il.MarkLabel(defineLabel);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
}
tb.DefineMethodOverride(methodBuilder, method);
}
}
#endregion
return tb.CreateType();
}
}
With our new helper class we can now write
var channelFactory = new ChannelFactory<IMyService>("");
var serviceHelper = new ServiceHelper<IMyService>(channelFactory);
var proxy = serviceHelper.CreateChannel();
using (proxy as IDisposable)
{
proxy.DoWork();
}
Note that you could also use the same technique (with slight modifications) for auto-generated clients inheriting for ClientBase<> (instead of using ChannelFactory<>), or if you want to use a different implementation of IDisposable to close your channel.
I like this way of closing connection:
var client = new ProxyClient();
try
{
...
client.Close();
}
finally
{
if(client.State != CommunicationState.Closed)
client.Abort();
}
I have written a simple base class that handles this. It's available as a NuGet package and it's quite easy to use.
//MemberServiceClient is the class generated by SvcUtil
public class MemberServiceManager : ServiceClientBase<MemberServiceClient>
{
public User GetUser(int userId)
{
return PerformServiceOperation(client => client.GetUser(userId));
}
//you can also check if any error occured if you can't throw exceptions
public bool TryGetUser(int userId, out User user)
{
return TryPerformServiceOperation(c => c.GetUser(userId), out user);
}
}
public static class Service<TChannel>
{
public static ChannelFactory<TChannel> ChannelFactory = new ChannelFactory<TChannel>("*");
public static TReturn Use<TReturn>(Func<TChannel,TReturn> codeBlock)
{
var proxy = (IClientChannel)ChannelFactory.CreateChannel();
var success = false;
try
{
var result = codeBlock((TChannel)proxy);
proxy.Close();
success = true;
return result;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
}
So it allows to write return statements nicely:
return Service<IOrderService>.Use(orderService =>
{
return orderService.PlaceOrder(request);
});
I'd like to add implementation of Service from Marc Gravell's answer for case of using ServiceClient instead of ChannelFactory.
public interface IServiceConnector<out TServiceInterface>
{
void Connect(Action<TServiceInterface> clientUsage);
TResult Connect<TResult>(Func<TServiceInterface, TResult> channelUsage);
}
internal class ServiceConnector<TService, TServiceInterface> : IServiceConnector<TServiceInterface>
where TServiceInterface : class where TService : ClientBase<TServiceInterface>, TServiceInterface, new()
{
public TResult Connect<TResult>(Func<TServiceInterface, TResult> channelUsage)
{
var result = default(TResult);
Connect(channel =>
{
result = channelUsage(channel);
});
return result;
}
public void Connect(Action<TServiceInterface> clientUsage)
{
if (clientUsage == null)
{
throw new ArgumentNullException("clientUsage");
}
var isChanneldClosed = false;
var client = new TService();
try
{
clientUsage(client);
client.Close();
isChanneldClosed = true;
}
finally
{
if (!isChanneldClosed)
{
client.Abort();
}
}
}
}
For those interested, here's a VB.NET translation of the accepted answer (below). I've refined it a bit for brevity, combining some of the tips by others in this thread.
I admit it's off-topic for the originating tags (C#), but as I wasn't able to find a VB.NET version of this fine solution I assume that others will be looking as well. The Lambda translation can be a bit tricky, so I'd like to save someone the trouble.
Note that this particular implementation provides the ability to configure the ServiceEndpoint at runtime.
Code:
Namespace Service
Public NotInheritable Class Disposable(Of T)
Public Shared ChannelFactory As New ChannelFactory(Of T)(Service)
Public Shared Sub Use(Execute As Action(Of T))
Dim oProxy As IClientChannel
oProxy = ChannelFactory.CreateChannel
Try
Execute(oProxy)
oProxy.Close()
Catch
oProxy.Abort()
Throw
End Try
End Sub
Public Shared Function Use(Of TResult)(Execute As Func(Of T, TResult)) As TResult
Dim oProxy As IClientChannel
oProxy = ChannelFactory.CreateChannel
Try
Use = Execute(oProxy)
oProxy.Close()
Catch
oProxy.Abort()
Throw
End Try
End Function
Public Shared ReadOnly Property Service As ServiceEndpoint
Get
Return New ServiceEndpoint(
ContractDescription.GetContract(
GetType(T),
GetType(Action(Of T))),
New BasicHttpBinding,
New EndpointAddress(Utils.WcfUri.ToString))
End Get
End Property
End Class
End Namespace
Usage:
Public ReadOnly Property Jobs As List(Of Service.Job)
Get
Disposable(Of IService).Use(Sub(Client) Jobs = Client.GetJobs(Me.Status))
End Get
End Property
Public ReadOnly Property Jobs As List(Of Service.Job)
Get
Return Disposable(Of IService).Use(Function(Client) Client.GetJobs(Me.Status))
End Get
End Property
Our system architecture often uses the Unity IoC framework to create instances of ClientBase so there's no sure way to enforce that the other developers even use using{} blocks. In order to make it as fool-proof as possible, I made this custom class that extends ClientBase, and handles closing down the channel on dispose, or on finalize in case someone doesn't explicitly dispose of the Unity created instance.
There is also stuff that needed to be done in the constructor to set up the channel for custom credentials and stuff, so that's in here too...
public abstract class PFServer2ServerClientBase<TChannel> : ClientBase<TChannel>, IDisposable where TChannel : class
{
private bool disposed = false;
public PFServer2ServerClientBase()
{
// Copy information from custom identity into credentials, and other channel setup...
}
~PFServer2ServerClientBase()
{
this.Dispose(false);
}
void IDisposable.Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
if (!this.disposed)
{
try
{
if (this.State == CommunicationState.Opened)
this.Close();
}
finally
{
if (this.State == CommunicationState.Faulted)
this.Abort();
}
this.disposed = true;
}
}
}
Then a client can simply:
internal class TestClient : PFServer2ServerClientBase<ITest>, ITest
{
public string TestMethod(int value)
{
return base.Channel.TestMethod(value);
}
}
And the caller can do any of these:
public SomeClass
{
[Dependency]
public ITest test { get; set; }
// Not the best, but should still work due to finalizer.
public string Method1(int value)
{
return this.test.TestMethod(value);
}
// The good way to do it
public string Method2(int value)
{
using(ITest t = unityContainer.Resolve<ITest>())
{
return t.TestMethod(value);
}
}
}
I referred few answers on this post and customized it as per my needs.
I wanted the ability to do something with WCF client before using it so the DoSomethingWithClient() method.
public interface IServiceClientFactory<T>
{
T DoSomethingWithClient();
}
public partial class ServiceClient : IServiceClientFactory<ServiceClient>
{
public ServiceClient DoSomethingWithClient()
{
var client = this;
// do somthing here as set client credentials, etc.
//client.ClientCredentials = ... ;
return client;
}
}
Here is the helper class:
public static class Service<TClient>
where TClient : class, ICommunicationObject, IServiceClientFactory<TClient>, new()
{
public static TReturn Use<TReturn>(Func<TClient, TReturn> codeBlock)
{
TClient client = default(TClient);
bool success = false;
try
{
client = new TClient().DoSomethingWithClient();
TReturn result = codeBlock(client);
client.Close();
success = true;
return result;
}
finally
{
if (!success && client != null)
{
client.Abort();
}
}
}
}
And I can use it as:
string data = Service<ServiceClient>.Use(x => x.GetData(7));
I have my own wrapper for a channel which implements Dispose as follows:
public void Dispose()
{
try
{
if (channel.State == CommunicationState.Faulted)
{
channel.Abort();
}
else
{
channel.Close();
}
}
catch (CommunicationException)
{
channel.Abort();
}
catch (TimeoutException)
{
channel.Abort();
}
catch (Exception)
{
channel.Abort();
throw;
}
}
This seems to work well and allows a using block to be used.
The following helper allows to call void and non-void methods. Usage:
var calculator = new WcfInvoker<CalculatorClient>(() => new CalculatorClient());
var sum = calculator.Invoke(c => c.Sum(42, 42));
calculator.Invoke(c => c.RebootComputer());
The class itself is:
public class WcfInvoker<TService>
where TService : ICommunicationObject
{
readonly Func<TService> _clientFactory;
public WcfInvoker(Func<TService> clientFactory)
{
_clientFactory = clientFactory;
}
public T Invoke<T>(Func<TService, T> action)
{
var client = _clientFactory();
try
{
var result = action(client);
client.Close();
return result;
}
catch
{
client.Abort();
throw;
}
}
public void Invoke(Action<TService> action)
{
Invoke<object>(client =>
{
action(client);
return null;
});
}
}
Override the client's Dispose() without the need to generate a proxy class based on ClientBase, also without the need to manage channel creation and caching! (Note that WcfClient is not an ABSTRACT class and is based on ClientBase)
// No need for a generated proxy class
//using (WcfClient<IOrderService> orderService = new WcfClient<IOrderService>())
//{
// results = orderService.GetProxy().PlaceOrder(input);
//}
public class WcfClient<TService> : ClientBase<TService>, IDisposable
where TService : class
{
public WcfClient()
{
}
public WcfClient(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public WcfClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public WcfClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public WcfClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
protected virtual void OnDispose()
{
bool success = false;
if ((base.Channel as IClientChannel) != null)
{
try
{
if ((base.Channel as IClientChannel).State != CommunicationState.Faulted)
{
(base.Channel as IClientChannel).Close();
success = true;
}
}
finally
{
if (!success)
{
(base.Channel as IClientChannel).Abort();
}
}
}
}
public TService GetProxy()
{
return this.Channel as TService;
}
public void Dispose()
{
OnDispose();
}
}
My method of doing this has been to create an inherited class that explicitly implements IDisposable. This is useful for folks who use the gui to add the service reference ( Add Service Reference ). I just drop this class in the project making the service reference and use it instead of the default client:
using System;
using System.ServiceModel;
using MyApp.MyService; // The name you gave the service namespace
namespace MyApp.Helpers.Services
{
public class MyServiceClientSafe : MyServiceClient, IDisposable
{
void IDisposable.Dispose()
{
if (State == CommunicationState.Faulted)
{
Abort();
}
else if (State != CommunicationState.Closed)
{
Close();
}
// Further error checks and disposal logic as desired..
}
}
}
Note: This is just a simple implementation of dispose, you can implement more complex dispose logic if you like.
You can then replace all your calls made with the regular service client with the safe clients, like this:
using (MyServiceClientSafe client = new MyServiceClientSafe())
{
var result = client.MyServiceMethod();
}
I like this solution as it does not require me to have access to the Interface definitions and I can use the using statement as I would expect while allowing my code to look more or less the same.
You will still need to handle the exceptions which can be thrown as pointed out in other comments in this thread.
You could also use a DynamicProxy to extend the Dispose() method. This way you could do something like:
using (var wrapperdProxy = new Proxy<yourProxy>())
{
// Do whatever and dispose of Proxy<yourProxy> will be called and work properly.
}

Categories