Creating Headers (wsse) Section of WCF Client Programmatically in C#

user402186 picture user402186 · Aug 30, 2011 · Viewed 25.5k times · Source

how do make a the following section of Service Settings of app.config in C# programmatically:

    <client>
  <endpoint address="https://someServiceUrl"
      binding="basicHttpBinding" bindingConfiguration="Contact"
      contract="ServiceReference.PostingWebService" name="PostingWebServicePort">
    <headers>
      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <wsse:UsernameToken>
          <wsse:Username>someusername</wsse:Username>
          <wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>somepassword</wsse:Password>
        </wsse:UsernameToken>
      </wsse:Security>
    </headers>
  </endpoint>
</client>

I have managed to generate binding section (not included above) and endpoint section from C#. I am unable to create the headers section.

The error that comes up is: (this is because I don't have headers section when I generate everything from C#)

This service requires <wsse:Security>, which is missing.

the headers section is important, as if I exclude it from the config and run the code using config it also gives the above error.

I don't want to use web.config/app.config. I have to run every thing from C#. (the above app.config works fine, but I want to do that same through C#)

NOTE: THE UPDATES BELOW ARE BASED ON THE SOLUTION PROVIDED BELOW PLEASE GO THROUGH THE COMMENTS ON THE SOLUTION BELOW, FOR BETTER UNDERSTANDING

UPDATE 1: (programmatically using BasicHttpBinding first)

BasicHttpBinding binding = new BasicHttpBinding();
        binding.Name = "Contact";
        binding.CloseTimeout = TimeSpan.FromMinutes(1);
        binding.OpenTimeout = TimeSpan.FromMinutes(1);
        binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
        binding.SendTimeout = TimeSpan.FromMinutes(1);
        binding.AllowCookies = false;
        binding.BypassProxyOnLocal = false;
        binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
        binding.MaxBufferSize = 524288;
        binding.MaxBufferPoolSize = 524288;
        binding.MaxReceivedMessageSize = 524288;
        binding.MessageEncoding = WSMessageEncoding.Text;
        binding.TextEncoding = System.Text.Encoding.UTF8;
        binding.TransferMode = TransferMode.Buffered;
        binding.UseDefaultWebProxy = true;

        binding.ReaderQuotas.MaxDepth = 32;
        binding.ReaderQuotas.MaxStringContentLength = 65536;
        binding.ReaderQuotas.MaxArrayLength = 131072;
        binding.ReaderQuotas.MaxBytesPerRead = 32768;
        binding.ReaderQuotas.MaxNameTableCharCount = 131072;

        binding.Security.Mode = BasicHttpSecurityMode.Transport;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
        binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
        binding.Security.Transport.Realm = "";
        binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
        binding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Default;

        CustomBinding customBinding = new CustomBinding(binding);
        SecurityBindingElement element = customBinding.Elements.Find<SecurityBindingElement>();
        // Remove security timestamp because it is not used by your original binding
        //element.IncludeTimestamp = false; (element is NULL in my case)

EndpointAddress endpoint = new EndpointAddress("https://myserviceaddress");

        PostingWebServiceClient client = new PostingWebServiceClient(customBinding, endpoint);

        client.ClientCredentials.UserName.UserName = "myusername";
        client.ClientCredentials.UserName.Password = "mypassword";

        client.getActiveChannels(new getActiveChannels());

Using Custom Bindgin Directly:

SecurityBindingElement securityElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
        securityElement.IncludeTimestamp = false;
        TextMessageEncodingBindingElement encodingElement = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
        HttpsTransportBindingElement transportElement = new HttpsTransportBindingElement();

        CustomBinding customBinding = new CustomBinding(securityElement, encodingElement, transportElement);


EndpointAddress endpoint = new EndpointAddress("https://myserviceaddress");

        PostingWebServiceClient client = new PostingWebServiceClient(customBinding, endpoint);

        client.ClientCredentials.UserName.UserName = "myusername";
        client.ClientCredentials.UserName.Password = "mypassword";

        client.getActiveChannels(new getActiveChannels());

Answer

Ladislav Mrnka picture Ladislav Mrnka · Aug 31, 2011

You don't have to configure header directly in this case because your scenario should be supported by BasicHttpBinding or CustomBinding directly.

If you need to configure it from C# you must create binding in code:

// Helper binding to have transport security with user name token
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
// Rest of your binding configuration comes here

// Custom binding to have access to more configuration details of basic binding
CustomBinding customBinding = new CustomBinding(binding);
SecurityBindingElement element = customBinding.Elements.Find<SecurityBindingElement>();
// Remove security timestamp because it is not used by your original binding
element.IncludeTimestamp = false;

EndpointAddress address = new EndpointAddress("https://...");

ProxyWebServiceClient client = new ProxyWebServiceClient(customBinding, address);
client.ClientCredentials.UserName.UserName = "...";
client.ClientCredentials.UserName.Password = "...";

Other solution is building custom binding directly instead of starting with basic binding:

SecurityBindingElemetn securityElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
securityElement.IncludeTimestamp = false; 
TextMessageEncodingBindingElement encodingElement = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
HttpsTransportBindingElement tranportElement = new HttpsTransportBindingElement();

// Other configurations of basic binding are divided into properties of 
// encoding and transport elements

CustomBinding customBinding = new CustomBinding(securityElement, encodingElement, transportElement);

EndpointAddress address = new EndpointAddress("https://...");

ProxyWebServiceClient client = new ProxyWebServiceClient(customBinding, address);
client.ClientCredentials.UserName.UserName = "...";
client.ClientCredentials.UserName.Password = "...";