WCF routing how to add Backuplist Programmatically

616 views Asked by At

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?

2

There are 2 answers

0
esiprogrammer On BEST ANSWER

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

5
Mr Moose On

I've never done this, but a quick look through the documentation on MSDN for Message Filters shows that alternative backup endpoints are configured via the FilterTableElementEntry class (BackupList property).

A filter table is a named collection of FilterTableEntryElement objects that define the association between a filter, a primary destination endpoint, and a list of alternative backup endpoints. The filter table entries also allow you to specify an optional priority for each filter condition.

Check for Filter Table and BackupList on Google, and you'll come across examples of usage of this. This example looks particularly promising with plenty of comments describing the steps.