我有一个WCF服务XYZ,它将部署在许多主机上。每个这样的服务可以与部署在其他主机之一上的另一个XYZ服务连接。它是一个分布式系统,服务之间的状态不同。
为了进行通信,我在Visual Studio中“添加服务引用”并不合理,因为这只会增加冗余(服务已经知道它将与之通信的内容)。
所以目前我的想法是在每个服务的App.config文件中指定其他服务端点。例如:
<client>
<endpoint name="BEL"
address="tcp://us.test.com:7650/OrderManagementService"
binding="tcpBinding"
contract="IOrderManagementService"/>
<endpoint name="BEL2"
address="tcp://us.test2.com:7650/OrderManagementService"
binding="tcpBinding"
contract="IOrderManagementService"/>
</client>
现在,我只想要一种方法来阅读这些设置并在我的代码中创建ChannelFactories和Channels。但是,实现这一目标很麻烦。
两个问题:我做得对吗?如果是这样,从配置文件中提取这些值的最佳方法是什么?
答案 0 :(得分:3)
直接创建频道并不难,并且为您读入所有端点配置。尝试这样的事情:
var factory = new ChannelFactory<IOrderManagementService>("BEL");
var proxy = factory.CreateChannel();
// call methods on proxy
proxy.Close();
请注意,代理需要在完成后正确关闭(这意味着正确调用Close
或Abort
)。但是,您可以将工厂长时间打开,即使在缓存中也是如此。
您可以将其封装到辅助方法中,以使调用代码变得简单:
public static ChannelFactory<TContract> NewChannelFactory<TContract>(string endpointConfigurationName) where TContract : class {
// TODO: Cache the factory in here for better performance.
return new ChannelFactory<TContract>(endpointConfigurationName);
}
public static void Invoke<TContract>(ChannelFactory<TContract> factory, Action<TContract> action) where TContract : class {
var proxy = (IClientChannel) factory.CreateChannel();
bool success = false;
try {
action((TContract) proxy);
proxy.Close();
success = true;
} finally {
if(!success) {
proxy.Abort();
}
}
}
答案 1 :(得分:0)
WebConfigurationManager可用于获取终结点。你有一个客户端部分,所以在GetSection中就像上面的代码一样传递它。
ClientSection clientSection = (WebConfigurationManager.GetSection("system.serviceModel/client") as ClientSection);
foreach(ChannelEndpointElement cee in clientSection.Endpoints)
{
// Store your endpoint for future use with ChannelFactories
}
答案 2 :(得分:0)
如果我理解你的问题,那就和我想做的事情类似。我不想在每个需要访问该服务的库或应用程序中包含服务引用。我创建了一个Mediator模式类,它具有服务引用并作为服务的代理。它将端点字符串作为唯一的类构造函数参数。构造函数看起来像这样(我把通道工厂示例作为注释)
public DspServiceMediator( String serviceAddress)
{
EndpointAddress end_point = new EndpointAddress(serviceAddress);
NetTcpBinding new_tcp = new NetTcpBinding(SecurityMode.None);
new_tcp.ReceiveTimeout = TimeSpan.MaxValue;
new_tcp.SendTimeout = new TimeSpan(0, 0, 30); //30 seconds
//_channelFactory = new ChannelFactory<DspServiceClient>(new_tcp, end_point);
_dspClient = new DspServiceClient(new_tcp, end_point);
}
我实际上复制了服务中的每个属性(很多时候我有很少的mods使服务更容易被最终客户端使用)但你可能只是违反了客户端代码中的Demeter法则并返回底层服务客户端(上面的代码中的_dspClient)并使用它。
答案 3 :(得分:0)
由于您的所有连接都是相同的合同,并且本质上是相同的客户端代码,因此您可以使用相同的ChannelFactory
创建所需数量的ServiceChannel
,并且可以连接每个ServiceChannel
EndpointAddress
1}}到常规旧应用程序设置或数据库中指定的不同private List<string> _endpointLists = new List<string>() { "127.0.0.0:1234" };
private static ChannelFactory<IWCFServiceChannel> _channelFactory = new ChannelFactory<ServiceReference.IWCFServiceChannel>("App.config Binding Name Here");
private List<WCFServiceChannel> _serviceChannels = new List<WCFServiceChannel>();
foreach (string uriEndpoint in _endpointLists)
_serviceChannels.Add(_channelFactory.CreateChannel(new EndpointAddress(uriEndpoint)));
_serviceChannels[0].Open();
...
:
ChannelFactory
您可以根据需要多次执行此操作,使用相同的ServiceChannel
,但每次都会创建具有不同端点的新{{1}}。