我正在尝试抽象/封装以下代码,因此所有客户端调用都不需要重复此代码。例如,这是一个从视图模型(MVVM)到WCF服务的调用:
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());
}
我最初的重构尝试就是这样做:
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.Applications = new ObservableCollection<Application>(PrestoWcf.PrestoService.GetAllApplications().ToList());
但是,我收到错误WcfChannelFactory
已经处理掉了。这是有道理的,因为当视图模型试图使用它时它确实被处理掉了。但是,如果我删除了using
,那么我就没有正确处理WcfChannelFactory
。请注意,WcfChannelFactory
在WcfClientProxy
被调用时会嵌入CreateChannel()
。这就是视图模型在处理后尝试使用它的原因/方式。
如何正确处理WcfChannelFactory
,如何抽象此代码,以使我的视图模型调用尽可能简单?我希望我能够很好地解释这一点。
编辑 - 解决了!
基于牛排回答,这样做了:
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);
}
}
}
这是视图模型调用:
this.Applications = new ObservableCollection<Application>(PrestoWcf.Invoke(service => service.GetAllApplications()).ToList());
答案 0 :(得分:7)
以下内容可能会有所帮助
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()));
旁注:
我没有将这种模式用于一次性用品,因为我最近没有找到太多需要的一次性用品。但是,从理论上讲,我认为我喜欢这种模式,在使用一次性装置时,在一个使用区块内执行回调,原因有两个:
答案 1 :(得分:0)
您确定在那里使用服务定位器模式吗?除了它是反模式,使用Invoke<T>
和Func<T, TResult>
,我认为将来使用会有一些混乱。此外,我不认为这种方式会将服务的使用与另一层分开。
我认为通过返回结果,这种方法比使用Func<T, TResult>
具有更多的SOC。
public static class PrestoWcf
{
public static IEnumerable<Application> PrestoService
{
get
{
IEnumerable<Application> appList;
using (var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding()))
{
var endpointAddress = ConfigurationManager.AppSettings["prestoServiceAddress"];
appList = prestoService.GetAllApplications().ToArray(); //you can ignore the .ToArray, I just not sure whether the enumerable still keep the reference to service
}
return appList;
}
}
}
清洁,但我仍然不建议使用静态方法。