dotnet / wcf

This repo contains the client-oriented WCF libraries that enable applications built on .NET Core to communicate with WCF services.
MIT License
1.72k stars 558 forks source link

Configuring WCF Client with external configuration files #5606

Open sambhaji-burungale opened 4 months ago

sambhaji-burungale commented 4 months ago

We have WCF Service and Client application written in .NET Framework. Now, there is a requirement to upgrade client application to .NET Core. We learned that the WCF is not supported in .NET Core. And hence we started using this WCF Client NuGet packages in our Client application. So far, it worked very well. But, currently it does not support configuring WCF client via external configuration files which is crucial as our customers often use different configuration based on their requirement.

Since there is no official support for using configuration files in .NET Core, could you please advise on how the client application in .NET Core can still configure WCF client with configuration outside of code? Currently, I had started writing below code that reads configuration file and applies changes to binding programmatically. But looks like it would get more complex as I try to handle more WCF settings.

var xmlDoc = new XmlDocument(); xmlDoc.Load(configPath);

var endpointNodes = xmlDoc.SelectNodes("//system.serviceModel/client/endpoint");

for (int i = 0; i < endpointNodes.Count; i++) { var endpointNode = endpointNodes[i];

var addressAttr = endpointNode.Attributes["address"].Value; 

var bindingAttr = endpointNode.Attributes["binding"].Value;

var bindingConfigAttr = endpointNode.Attributes["bindingConfiguration"].Value;

if (bindingAttr == null)
    continue;

XmlNode bindingNode = xmlDoc.SelectSingleNode($"//system.serviceModel/bindings/{bindingType}/binding[@name='{bindingConfiguration}']");

switch (bindingType)
{
    case "basicHttpBinding":
        binding = new BasicHttpBinding();
        ConfigureBasicHttpBinding((BasicHttpBinding)binding, bindingNode);
        break;  

    case "netTcpBinding":
        binding = new NetTcpBinding();
        ConfigureNetTcpBinding((NetTcpBinding)binding, bindingNode);
        break;
    }
}

}

public static void ConfigureNetTcpBinding(NetTcpBinding binding, XmlNode bindingNode) { if (bindingNode == null) return;

foreach (XmlAttribute attribute in bindingNode.Attributes)
{
    switch (attribute.Name)
    {
        case "maxBufferSize":
            binding.MaxBufferSize = int.Parse(attribute.Value);
            break;

        case "maxReceivedMessageSize":
            binding.MaxReceivedMessageSize = long.Parse(attribute.Value);
            break;

            // Add more cases to handle other attributes as needed
    }
}

var securityNode = bindingNode.SelectSingleNode("security");
if (securityNode != null)
{
    foreach (XmlAttribute attribute in securityNode.Attributes)
    {
        switch (attribute.Name)
        {
            case "mode":
                binding.Security.Mode = (SecurityMode)Enum.Parse(typeof(SecurityMode), attribute.Value, true);
                break;

                // Add more cases to handle other security attributes as needed
        }
    }

    var transportNode = securityNode.SelectSingleNode("transport");
    if (transportNode != null)
    {
        foreach (XmlAttribute attribute in transportNode.Attributes)
        {
            switch (attribute.Name)
            {
                case "clientCredentialType":
                    binding.Security.Transport.ClientCredentialType = (TcpClientCredentialType)Enum.Parse(typeof(TcpClientCredentialType), attribute.Value, true);
                    break;

                    // Add more cases to handle other transport security attributes as needed
            }
        }
    }
}

}

mconnew commented 3 months ago

An option could be this external project that a fellow Microsoft developer created to bring some config capability: https://github.com/twsouthwick/ServiceModel.Configuration
Note, this is not an official Microsoft project and is something a developer released on his own so isn't officially supported. Having said that, I personally would expect his code to be of good quality.

If you want to role your own, a solution I've wanted to experiment with for a few years but haven't had the bandwidth to try out and document is Configuration Binding. You would need to have a way to know which type of Binding you are creating, but once you know that, I believe there shouldn't be anything preventing you from using configuration binding to represent the binding in config and "binding" it to the runtime type. It would be using a different schema than the WCF ConfigurationManager way of expressing a binding would be as they don't have a 1:1 mapping.

For the EndpointAddress, that class has some basic serialization built in. You do need to know the addressing version as the apis are EndpointAddress.ReadFrom(AddressingVersion addressingVersion, XmlDictionaryReader reader) and EndpointAddress.WriteContentsTo(AddressingVersion addressingVersion, XmlDictionaryWriter writer). BasicHttpBinding uses AddressingVersion.None by default, and NetTcpBinding uses AddressingVersion.WSAddressing10. Again, this isn't the same representation as you'll see in an app.config file. With the configuration binding idea from above along with this, I think most things are covered. You won't get behaviors with this though. If you switched to JSON config, ever though it's reading/writing XML, you could use an XmlDictionaryWriter that doesn't have pretty printing (so it all comes out on a single line) and stash the XML inside a string in JSON.

sambhaji-burungale commented 2 months ago

Thank you @mconnew

I will try the ServiceModel.Configuration...