Search code examples
c#wcfwcf-routing

WCF routing how to add Backuplist Programmatically


I'm using WCF routing service and I'm trying to Implement failover, I need to add filter table backuplist programmatically, this is a sample configuration:

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

I was able to add FilterTable which I found example in this question

here is my code snippet:

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

so in my scenario ServiceOperation2 and ServiceOperation3 are the backup endpoints, I made lots of research I coudn't find a way to add backuplist Programmatically

any Idea how can I add backuplist to filterTable?


Solution

  • I ended up with this solution to dynamically generate config file

    In my scenario, I load my endpoints from database and generated routing service configuration out of it,

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

    so first I generated configuration file and than create an intance of routing service like:

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

    hope it will be helpful for someone