【问题标题】:WCF routing how to add Backuplist ProgrammaticallyWCF路由如何以编程方式添加备份列表
【发布时间】:2017-12-21 23:48:11
【问题描述】:

我正在使用 WCF 路由服务并且我正在尝试实现故障转移,我需要以编程方式添加过滤表备份列表,这是一个示例配置:

<system.serviceModel>
          <client>
            <endpoint address="http://localhost:8081/Service1" binding="basicHttpBinding"
                      contract="*" name="ServiceOperation1" />
            <endpoint address="http://localhost:8081/Service2" binding="basicHttpBinding"
                      contract="*" name="ServiceOperation2" />
            <endpoint address="http://localhost:8081/Service3" binding="basicHttpBinding"
                      contract="*" name="ServiceOperation3" />
          </client>
          <routing>
            <filters>
              <filter name="MatchAllFilter" filterType="MatchAll" />
            </filters>
            <filterTables>
              <filterTable name="RoutingTable">
                <add filterName="MatchAllFilter" endpointName="ServiceOperation1" backupList="BackUps" />
              </filterTable>
            </filterTables>
            <backupLists>
              <backupList name="BackUps">
                <add endpointName="ServiceOperation2"/>
                <add endpointName="ServiceOperation3" />
              </backupList>
            </backupLists>
          </routing>
          <behaviors>
            <serviceBehaviors>
              <behavior name="">
                <routing filterTableName="RoutingTable" />
              </behavior>
            </serviceBehaviors>
          </behaviors>
            <services>
                <service name="System.ServiceModel.Routing.RoutingService">
                  <endpoint address="binary" binding="basicHttpBinding"
                           contract="System.ServiceModel.Routing.IRequestReplyRouter" name="VirtualEndpoint" />
                    <host>
                        <baseAddresses>
                            <add baseAddress="http://localhost:8080/RoutingService/Router" />
                        </baseAddresses>
                    </host>
                </service>
            </services>
</system.serviceModel>

我能够添加我找到示例in this question的FilterTable

这是我的代码 sn-p:

var routingHost = new ServiceHost(typeof(RoutingService));
var routingEp = routingHost.AddServiceEndpoint(typeof(System.ServiceModel.Routing.IRequestReplyRouter), mybinding, url);      
var filterTable = new MessageFilterTable<IEnumerable<ServiceEndpoint>>();   
filterTable.Add(new MatchAllMessageFilter(), new List<ServiceEndpoint>()
                        {
                            serviceoperation1Endpoint
                        });


 routingHost.Description.Behaviors.Add(
                              new RoutingBehavior(new RoutingConfiguration(filterTable, false)));

routingHost.open();

所以在我的场景中,ServiceOperation2ServiceOperation3 是备份端点,我做了很多研究,但找不到以编程方式添加备份列表的方法

任何想法如何将备份列表添加到 filterTable?

【问题讨论】:

    标签: c# wcf wcf-routing


    【解决方案1】:

    我最终得到了这个动态生成配置文件的解决方案

    在我的场景中,我从数据库加载端点并从中生成路由服务配置,

    public class MyServiceEndPoint 
    {
        public string TypeName { get; set; }
    
        public string Url { get; set; }
    
        public string Name { get; set; }
    }
    
    //// generates routing service configuration section, including client enoints/filterTable/backups and routing service behavior
    private void CreateRoutingConfiguration(List<MyServiceEndPoint> serviceEndpoints)
    {
         ///// group endopints by Name, each service could have multiple endpoints ( 1 main and n backup endpoints)
        var groupedEndpoitns = (from endp in serviceEndpoints
                                        group endp by endp.Name into endpGroup
                                        select new { ServiceName = endpGroup.Key, EndPoint = endpGroup }).ToList();
    
    
    
        var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        var serviceModelSectionGroup = System.ServiceModel.Configuration.ServiceModelSectionGroup.GetSectionGroup(config);
    
        var routingSection = (RoutingSection)serviceModelSectionGroup.Sections["routing"];
        var clientsection = (ClientSection)serviceModelSectionGroup.Sections["client"];
        var bindingSection = (BindingsSection)serviceModelSectionGroup.Sections["bindings"];
        var behaviorSection = (BehaviorsSection)serviceModelSectionGroup.Sections["behaviors"];
    
        bindingSection.NetTcpBinding.Bindings.Clear();
        clientsection.Endpoints.Clear();
        var filterTable = new FilterTableEntryCollection() { Name = "RoutingTable" };
        routingSection.Filters.Clear();
        routingSection.FilterTables.Clear();
        routingSection.BackupLists.Clear();
    
        var nettcpBinding = new NetTcpBindingElement()
        {
            Name = "myTcpBinding",
            TransferMode = TransferMode.Buffered,
            MaxBufferSize = 2147483647,
            MaxReceivedMessageSize = 2147483647,        
            SendTimeout = new TimeSpan(0, 10, 0),
            ReceiveTimeout = new TimeSpan(0, 10, 0),
    
        };
    
        nettcpBinding.Security.Mode = SecurityMode.None;
        bindingSection.NetTcpBinding.Bindings.Add(nettcpBinding);
    
    
        foreach (var endpointGroup in groupedEndpoitns)
        {
            var backupListItem = new BackupEndpointCollection();
            backupListItem.Name = endpointGroup.ServiceName + "Backup";
    
            var filter = new FilterElement();
            filter.Name = endpointGroup.ServiceName + "Filter";
            filter.FilterType = FilterType.Custom;
            filter.CustomType = "MyServiceContractMessageFilterType,asemblyName";
            filter.FilterData = endpointGroup.EndPoint.FirstOrDefault().ClientTypeName;
            routingSection.Filters.Add(filter);
    
            int endpointCount = 0;
            List<ChannelEndpointElement> channelEndpoints = new List<ChannelEndpointElement>();
            foreach (var endpoint in endpointGroup.EndPoint)
            {
                endpointCount++;
                var channelEndpoint = new ChannelEndpointElement();
                channelEndpoint.Address = new Uri(endpoint.Url);
                channelEndpoint.Binding = "netTcpBinding";
                channelEndpoint.BindingConfiguration = "myTcpBinding";
                channelEndpoint.Contract = "*";
                channelEndpoint.Name = $"{endpoint.Name}EndPoint{endpointCount}";
                clientsection.Endpoints.Add(channelEndpoint);
                channelEndpoints.Add(channelEndpoint);
    
            }
    
            var firstChannelEndpoint = channelEndpoints.FirstOrDefault(); /// this endpoint will be selected as main endpoint
            var filterTableItem = new FilterTableEntryElement();
            filterTableItem.FilterName = filter.Name;
            filterTableItem.EndpointName = firstChannelEndpoint.Name;
            filterTableItem.BackupList = backupListItem.Name;
            filterTable.Add(filterTableItem);    
    
            foreach (var backupEndpoints in channelEndpoints)
            {
                backupListItem.Add(new BackupEndpointElement() { EndpointName = backupEndpoints.Name });
                routingSection.BackupLists.Add(backupListItem);
            }
        }
    
        routingSection.FilterTables.Add(filterTable);    
        behaviorSection.ServiceBehaviors.Clear();
        var behavior = new ServiceBehaviorElement();
        behavior.Add(new RoutingExtensionElement() { FilterTableName = filterTable.Name });
        behaviorSection.ServiceBehaviors.Add(behavior);
        config.Save(ConfigurationSaveMode.Modified, false);
        ConfigurationManager.RefreshSection("system.serviceModel/routing");
        ConfigurationManager.RefreshSection("system.serviceModel/client");        
    ConfigurationManager.RefreshSection("system.serviceModel/behaviors");
    }
    

    所以首先我生成了配置文件 而不是创建一个路由服务的实例,例如:

    CreateRoutingConfiguration(serviceEndpoints);
    routingHost = new ServiceHost(typeof(RoutingService));
    routingHost.AddServiceEndpoint(typeof(System.ServiceModel.Routing.IRequestReplyRouter), mybinding, $"net.tcp://localhost:6000/Router");
    routingHost.Open();
    

    希望对某人有所帮助

    【讨论】:

      【解决方案2】:

      我从来没有这样做过,但是快速浏览一下 MSDN 上Message Filters 的文档会发现备用备份端点是通过FilterTableElementEntry 类(BackupList 属性)配置的。

      过滤表是 FilterTableEntryElement 的命名集合 定义过滤器、主 目标端点,以及备用备份端点列表。这 过滤表条目还允许您指定可选的优先级 每个过滤条件。

      在 Google 上检查 Filter Table 和 BackupList,您会遇到使用此功能的示例。 This example 看起来特别有前途,有很多 cmets 描述了这些步骤。

      【讨论】:

      • 感谢您的帮助,但我已经查看了这些文档,但 FilterTableElementEntry 无法在运行时更改,或者据我所知,我找到了 this 但显然我们只能应用更改serviceElement 运行时部分
      • 在我看来这是可能的。我在最后一句中发布的示例显示了如何构造 BackupList,然后使用它来构造 RoutingConfiguration 和 ServiceHost。这实际上看起来像是一个很好的独立的小例子。为什么不尝试使用它作为基础,看看您是否可以按照您在问题中显示的那样配置您的服务。
      • 如果我在过滤表中添加备份端点(作为您提供的示例以及我的代码如 filterTable.Add(new MatchAllMessageFilter(), new List&lt;ServiceEndpoint&gt;() { serviceoperation1Endpoint, serviceoperation2Endpoint, serviceoperation3Endpoint }); 它会抛出 Multiple filters matched 异常
      • 显然它匹配所有 endpints,它应该是 1 main endpoint2 backup endpoints ,相同的配置,或者我错过了什么......
      • 我不完全确定您是如何设置与Addresses, Bindings and Contracts 相关的服务的。您的代码 sn-p 没有提供足够的信息来显示对此所做的工作。您可以查看 Filters 属性以了解导致异常抛出的过滤器。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-24
      • 2011-08-07
      • 1970-01-01
      • 1970-01-01
      • 2014-11-10
      相关资源
      最近更新 更多