title: How to add ws-security header in .net core?
body: <p>I'm trying to make a call to a webservice and want to manually add the ws-security headers into the request because .net core 2.2 currently does not support ws-security.</p>
  
  <p>I have created my custom security header class:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public class SoapSecurityHeader : MessageHeader
      {
          private readonly string _password, _username;
  
          public SoapSecurityHeader(string id, string username, string password)
          {
              _password = password;
              _username = username;
          }
          public override bool MustUnderstand =&gt; true;
  
          public override string Name
          {
              get { return "Security"; }
          }
  
          public override string Namespace
          {
              get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
          }
  
          protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
          {
              writer.WriteStartElement("wsse", Name, Namespace);
              writer.WriteAttributeString("s", "mustUnderstand", "http://schemas.xmlsoap.org/soap/envelope/", "1");
              writer.WriteXmlnsAttribute("wsse", Namespace);
          }
  
          protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
          {
              writer.WriteStartElement("wsse", "UsernameToken", Namespace);
              writer.WriteAttributeString("wsu", "Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "UsernameToken-32");
              // Username
              writer.WriteStartElement("wsse", "Username", Namespace);
              writer.WriteValue(_username);
              writer.WriteEndElement();
              // Password
              writer.WriteStartElement("wsse", "Password", Namespace);
              writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
              writer.WriteValue(_password);
              writer.WriteEndElement();
              writer.WriteEndElement();
          }
      }
  </code></pre>
  
  <p>And this is my method calling the SOAP service:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public ActionResult&lt;Ted_Result&gt; Get(DateTime dateFrom, DateTime dateTo, int? pageFrom, int? pageTo)
          {
              BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
              basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
              EndpointAddress endpointAddress = new EndpointAddress(new Uri("https://localhost/SomeService.svc"));
              ChannelFactory&lt;IConnectPublicService&gt; factory = new ChannelFactory&lt;IConnectPublicService&gt;(basicHttpBinding, endpointAddress);
              GetContractNoticesResponseMessage result = null;
  
              // Bypass SSL/TLS secure channel validation
  #if DEBUG
              factory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication
              {
                  CertificateValidationMode = X509CertificateValidationMode.None,
                  RevocationMode = X509RevocationMode.NoCheck
              };
  #endif
              // Debugging inspector
              factory.Endpoint.EndpointBehaviors.Add(new InspectorBehavior());
  
              IConnectPublicService serviceProxy = factory.CreateChannel();
              ((ICommunicationObject)serviceProxy).Open();
              var opContext = new OperationContext((IClientChannel)serviceProxy);
              var soapSecurityHeader = new SoapSecurityHeader("UsernameToken-32", "sampleUsername", "samplePassword123");
              // Adding the security header
              opContext.OutgoingMessageHeaders.Add(soapSecurityHeader);
              var prevOpContext = OperationContext.Current; // Optional if there's no way this might already be set
              OperationContext.Current = opContext;
  
              var info = new ExternalIntegrationRequestMessageInfo
              {
                  UserCode = "1000249",
                  CompanyCode = "200000040"
              };
              var request = new GetContractNoticesRequestMessage
              {
                  Info = info,
                  DateFrom = dateFrom,
                  DateTo = dateTo,
                  PageFrom = pageFrom,
                  PageTo = pageTo
              };
              result = serviceProxy.GetContractNoticesAsync(request).ConfigureAwait(false).GetAwaiter().GetResult();
  
              return Ok(result);
          }
  </code></pre>
  
  <p>If I put a breakpoint inside the inspector at BeforeSendRequest I can see that the security header is added to the request:</p>
  
  <pre class="lang-xml prettyprint-override"><code> &lt;wsse:Security s:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"&gt;
        &lt;wsse:UsernameToken wsu:Id="UsernameToken-32" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"&gt;
          &lt;wsse:Username&gt;sampleUsername&lt;/wsse:Username&gt;
          &lt;wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"&gt;samplePassword123&lt;/wsse:Password&gt;
        &lt;/wsse:UsernameToken&gt;
      &lt;/wsse:Security&gt;
  </code></pre>
  
  <p>And putting a breakpoint inside the inspector at AfterReceiveReply, I get the CORRECT result, but I still get an exception.
  The result:</p>
  
  <pre class="lang-xml prettyprint-override"><code>&lt;...&gt;
    &lt;s:Header&gt;
    &lt;...&gt;
      &lt;o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"&gt;
        &lt;u:Timestamp u:Id="_0"&gt;
          &lt;u:Created&gt;2019-01-11T19:42:53.606Z&lt;/u:Created&gt;
          &lt;u:Expires&gt;2019-01-11T19:47:53.606Z&lt;/u:Expires&gt;
        &lt;/u:Timestamp&gt;
      &lt;/o:Security&gt;
    &lt;/s:Header&gt;
    &lt;s:Body&gt;
      &lt;GetContractNoticesResponseMessage&gt;
        &lt;ContractNotices&gt;....&lt;/ContractNotices&gt;
      &lt;/GetContractNoticesResponseMessage&gt;
    &lt;/s:Body&gt;
  
  </code></pre>
  
  <p>The exception:</p>
  
  <pre><code>An unhandled exception occurred while processing the request.
  
  ProtocolException: The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed. This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process. Please ensure that the configuration of the client's binding is consistent with the service's binding.
  </code></pre>
  
  <p>Why do I still get an exception after calling the webservice successfully?</p>