21

We've got to access a web service that uses soap11... no problem I'll just set the binding as:

BasicHttpBinding wsBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);

Nope. No dice. So I asked the host of the service why we're having authentication issues and he said that our config needed to have this custom binding:

<bindings>
    <customBinding>
        <binding name="lbinding">
            <security  authenticationMode="UserNameOverTransport" 
                messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11" 
                securityHeaderLayout="Strict" 
                includeTimestamp="false"
                requireDerivedKeys="true" 
                keyEntropyMode="ServerEntropy">
            </security>
            <textMessageEncoding messageVersion="Soap11" />
            <httpsTransport authenticationScheme ="Negotiate" requireClientCertificate ="false" realm =""/>
        </binding>
    </customBinding>
</bindings>

Only problem is we're creating our binding programmatically not via the config. So if someone could point me in the right direction in regards to changing my BasicHttpBinding into a custombinding that conforms to the .config value provided I'll give them a big shiny gold star for the day.

Cœur
  • 37,241
  • 25
  • 195
  • 267
D.Forrest
  • 845
  • 1
  • 9
  • 23

3 Answers3

38

Solved it!

Here's the winning code for those who are in a similar predicament.

Uri epUri = new Uri(_serviceUri);
CustomBinding binding = new CustomBinding();
SecurityBindingElement sbe = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
sbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;        
sbe.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
sbe.IncludeTimestamp = false;
sbe.SetKeyDerivation(true);
sbe.KeyEntropyMode = System.ServiceModel.Security.SecurityKeyEntropyMode.ServerEntropy;
binding.Elements.Add(sbe);
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8));
binding.Elements.Add(new HttpsTransportBindingElement());
EndpointAddress endPoint = new EndpointAddress(epUri);
D.Forrest
  • 845
  • 1
  • 9
  • 23
  • Thanks for this.. I had a similar issue where I had to create another class project that contained logic to perform an external service call. I really didn't (couldn't) move the config from the app.config to the underlying web.config - and so the above solutions is perfect for this instance, to override the service definition. – Dav.id May 08 '13 at 15:15
  • Thank you - Had a C# dll to be consumed by Coldfusion so ...no app.config :( Your example helped me with adding the TextMessage encoding and https transport to the Custom Binding - Much appreciated! – Scott Moniz Dec 18 '18 at 16:18
  • how do I add basic auth to this custom binding? – Mbithy Mbithy Jul 18 '19 at 09:52
8

@D. Forrest already found the solution, but a simple way to see what objects are involved for a given WCF configuration is to call .Endpoint.Binding.CreateBindingElements() on the client proxy you are using. You can the dump the object tree of each item in the list that is returned and see how the binding is configured.

Jeremy Wiebe
  • 3,894
  • 22
  • 31
  • Thanks a lot for mentioning this method! I'm using it to convert an existing `NetTcpBinding` to a custom binding at runtime in order to enable GZIP compression. This way I don't need to figure out how to do the conversion manually, nor do I need to hardcode the required binding elements. – Livven Jan 28 '19 at 17:03
  • 2
    Turns out it's even easier – you can simply pass any existing `Binding` to the `CustomBinding` constructor and don't need that method at all. Also documented [here](https://learn.microsoft.com/en-us/dotnet/framework/wcf/extending/how-to-customize-a-system-provided-binding#to-modify-a-system-provided-binding). Might be obvious to people who are familiar with WCF but maybe this helps some other confused souls like me :) – Livven Jan 28 '19 at 17:23
2

You can use :

        Uri epUri = new Uri("http://localhost/TestWCFService/Service.svc");
        CustomBinding binding = new CustomBinding()
        {
            Name = "anyname",
            ReceiveTimeout = new TimeSpan(0, 0, 10, 0, 0),
            SendTimeout = new TimeSpan(0, 0, 10, 0, 0),
        };
        var element1 = new TextMessageEncodingBindingElement()
        {
            ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
            {
                MaxDepth = 2147483647,
                MaxStringContentLength = 2147483647,
                MaxArrayLength = 2147483647,
                MaxBytesPerRead = 2147483647,
                MaxNameTableCharCount = 2147483647
            }
        };
        var element2 = new HttpsTransportBindingElement()
        {
            ManualAddressing = false,
            MaxReceivedMessageSize = 2147483647,
            AllowCookies = false,
            AuthenticationScheme = System.Net.AuthenticationSchemes.Anonymous,
            BypassProxyOnLocal = false,
            MaxBufferSize = 2147483647,
            ProxyAuthenticationScheme = System.Net.AuthenticationSchemes.Anonymous,
            TransferMode = TransferMode.Buffered,
            UseDefaultWebProxy = true
        };
        var element3 = new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8);

        binding.Elements.Add(element1);
        binding.Elements.Add(element2);
        binding.Elements.Add(element3);

        //binding.Elements.Add(new HttpsTransportBindingElement());

        EndpointAddress endPoint = new EndpointAddress(epUri);
        var client = new ServiceClient(binding, endPoint);
Jnyanendra Sethi
  • 1,055
  • 1
  • 8
  • 3