I'm trying to abstract/encapsulate the following code so all client calls don't need to repeat this code. For example, this is a call, from a view model (MVVM) to a WCF service:
using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
{
var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];
IPrestoService prestoService = channelFactory.CreateChannel(new EndpointAddress(endpointAddress));
this.Applications = new ObservableCollection<Application>(prestoService.GetAllApplications().ToList());
}
My original attempt at refactoring was to do this:
public static class PrestoWcf
{
public static IPrestoService PrestoService
{
get
{
using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
{
var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];
return channelFactory.CreateChannel(new EndpointAddress(endpointAddress));
}
}
}
}
This allows my view models to make the call with just one line of code now:
this.Applications = new ObservableCollection<Application>(PrestoWcf.PrestoService.GetAllApplications().ToList());
However, I get an error the the WcfChannelFactory
is already disposed. This makes sense because it really is disposed when the view model tries to use it. But, if I removing the using
, then I'm not properly disposing of the WcfChannelFactory
. Note, the WcfChannelFactory
embeds itself in the WcfClientProxy
when CreateChannel()
is called. This is why/how the view model is trying to use it after it has been disposed.
How do I abstract this code, to keep my view model calls as simple as possible, while properly disposing WcfChannelFactory
? I hope I explained this well enough.
Edit - Solved!
Based on steaks answer, this did it:
public static class PrestoWcf
{
public static T Invoke<T>(Func<IPrestoService, T> func)
{
using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
{
var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];
IPrestoService prestoService = channelFactory.CreateChannel(new EndpointAddress(endpointAddress));
return func(prestoService);
}
}
}
And here is the view model call:
this.Applications = new ObservableCollection<Application>(PrestoWcf.Invoke(service => service.GetAllApplications()).ToList());
Something like the following may help
public static void UsePrestoService(Action<IPrestoService> callback)
{
using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
{
var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];
IPrestoService prestoService = channelFactory.CreateChannel(new EndpointAddress(endpointAddress));
//Now you have access to the service before the channel factory is disposed. But you don't have to worry about disposing the channel factory.
callback(prestoService);
}
}
UsePrestoService(service => this.Applications = new ObservableCollection<Application>(service.GetAllApplications().ToList()));
Side note:
I haven't used this pattern much with disposables because I haven't found too much of a need for disposables recently. However, in theory I think I like this pattern, taking a callback that executes inside of a using block, when working with disposables for two reasons:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With