WCF C# - 从 App.config 获取特定的配置值

Posted

技术标签:

【中文标题】WCF C# - 从 App.config 获取特定的配置值【英文标题】:WCF C# - Getting Specific Configuration Values From App.config 【发布时间】:2011-10-09 15:44:02 【问题描述】:

我有一个 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。但是,这样做很麻烦。

两个问题:我做的对吗?如果是这样,从配置文件中提取这些值的最佳方法是什么?

【问题讨论】:

这个问题***.com/questions/297431/… 可能有帮助 【参考方案1】:

直接创建通道并不难,所有端点配置都已为您读入。试试这样的:

var factory = new ChannelFactory<IOrderManagementService>("BEL");
var proxy = factory.CreateChannel();
// call methods on proxy
proxy.Close();

请注意,代理需要在完成后立即正确关闭(这意味着正确调用CloseAbort)。但是,您可以让工厂长时间处于打开状态,即使在缓存中也是如此。

您可以将其封装到辅助方法中以使调用代码简单:

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();
        
    

【讨论】:

谢谢,我不知道端点配置是自动为我读入的! 奇怪的表述 - 为什么不直接捕获异常,中止通道并重新抛出? @Richard:捕获并重新抛出异常需要时间,并且会删除部分堆栈跟踪。如果这些事情与您的代码无关,那很好,但避免这种情况不需要任何成本。 虽然速度较慢,但​​这是您希望很少执行的代码路径,并且代码的意图非常明确。如果使用通用 throw 子句,则不会丢失任何信息 Close 可以像其他代码一样轻松抛出异常。如果发生这种情况,您仍然希望调用 Abort。如果您不使用上述模式,则需要两个嵌套的 catch 块,这对我来说似乎更丑。【参考方案2】:

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 

【讨论】:

【参考方案3】:

如果我正确理解了您的问题,这与我想做的事情相似。我不想在需要访问服务的每个库或应用程序中包含服务引用。我创建了一个具有服务引用并充当服务代理的中介模式类。它将端点字​​符串作为唯一的类构造函数参数。构造函数看起来像这样(我在评论中添加了一个通道工厂示例)

    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);
    

我实际上复制了服务中的每个属性(很多时候我有一些小模块使最终客户端更容易使用该服务)但是您可以在客户端代码中违反 Demeter 法则并返回底层服务客户端( _dspClient 在上面的代码中)并使用它。

【讨论】:

【参考方案4】:

由于您的所有连接都是相同的合约,并且本质上是相同的客户端代码,因此您可以使用相同的ChannelFactory 创建任意数量的ServiceChannel,并且可以将每个ServiceChannel 连接到不同的@ 987654324@es 在常规旧应用程序设置或数据库中指定:

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,但每次都使用不同的端点创建新的ServiceChannels。

【讨论】:

以上是关于WCF C# - 从 App.config 获取特定的配置值的主要内容,如果未能解决你的问题,请参考以下文章

从 c# 中的 app.config 获取 ConnectionString [重复]

WCF:如何从配置中获取绑定对象

.NET - 部署 WCF 客户端,没有 app.config

无法从 App.Config 中检索密钥

c# 配置文件App.config操作类库

如何在 app.config 中获取服务基地址?