How to consume a web service, through client certification and Oauth2 Authentication, writing c# code.

Versione Italiana.
Who has done similar task , using visual studio, knows the IDE helps the developers, providing some classes useful to easly call a webservice. If the developer has available the WSDL file defining the service, Visual studio parses it , and automatically builds the libraries

But, if the call must use a channel, encrypted by a client certificate, and further the server expect an Oauth2 authentication token , enclosed in the request, the task becomes quite harder

With C# it’s quite simple to make an HTTP request using a client certificate to make the call, on the same HTTP request and also simple to add the OAuth2 token among the Headers.
If the request is simple (It has few parameters and is not structured on several levels), the developer can send a raw HTTP request, inserting the parameters in the body of this.
If instead the parameters of the request are many and very structured, doing such a thing would take a lot of time.

I found a way to use the libraries generated by Visual studio, on an encrypted channel and with the Oauth2 authentication token.

Below, is the code that would be used for a call with the usual method:

var Binding = new BasicHttpBinding();
EndpointAddress ServiceEndPoint = new EndpointAddress("http://EndpointAddress.com");
ServiceReference.Serviceclient client = new ServiceReference.Serviceclient(Binding, ServiceEndPoint);
ServiceReference.ServiceResult result = client.Method(ServiceParameter);

If you want to make the call on an encrypted channel, you must first create a certificate object:

X509Certificate2 certificate = new X509Certificate2("filePath.p12", "Password");

Where the file containing the certificate must be in p12 format and the insertion of its relative password is mandatory.
Next you need to create a binding type object different from the usual one, while the endpoint object will remain on the same type:

var Binding = new WSHttpBinding();
Binding.Security.Mode = SecurityMode.Transport;
Binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
EndpointAddress ServiceEndPoint = new EndpointAddress(https://EndpointAddress.com);

Note: This time the endpoint is on HTTPS, no longer on HTTP, indeed this type of binding is compatible only with https.

Then you need to create the client object and set the certificate on it:

ServiceReference.Serviceclient client = new ServiceReference.Serviceclient(Binding, ServiceEndPoint);
ServiceReference.ServiceResult result = client.Method(ServiceParameter);

Client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = 
new System.ServiceModel.Security.X509ServiceCertificateAuthentication();
System.ServiceModel.Security.X509CertificateInitiatorClientCredential certificateInitiator = 
Client.ClientCredentials.ClientCertificate;
certificateInitiator.Certificate = certificate;

With this we have set up communication through the certified channel, now we must make sure that a token at our convenience is also included in the header of the generated HTTPS request. This is quite complicated, to be able to do it you need to act on the context of the call:

using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
       MessageHeader<string> header = new MessageHeader<string>("Bearer " + Oautoken);
       var untyped = header.GetUntypedHeader("Authorization", "");
       OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
       HttpRequestMessageProperty requestMessage = new 
       HttpRequestMessageProperty();
       requestMessage.Headers["Authorization"] = "Bearer " + "TokenString";          
       OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] 
       = requestMessage;
       result = client.method(serviceParameter);
}