This document navigates WCF-based client connections, demonstrating adaptation for third-party web services demanding custom HTTP header-based authorization, enriching interconnectivity methods.
Introduction
Assume you are communicating with a WCF-based service using WCF-based client.
Due to security reasons, client connection usually requires authorization, so the client should provide some credentials for web service.
Basic Authentication mechanism for WCF is described here.
As you can see after creating a WCF client cc
for WCF service "Calculator
"...
CalculatorClient cc = new CalculatorClient(myBinding, ea);
...it's possible to pass credentials like this:
cc.ClientCredentials.UserName.UserName = "MyUserName";
cc.ClientCredentials.UserName.Password = "MyPassword";
It's quite simple and works fine if client communicates with web service that provides the same authentication mechanism.
However, sometimes you need to connect to third-party web services which provide their own authentication. Besides that, third-party web services can be non WCF-based at all.
In that case, you can still use WCF-based client, but you may need to write some additional code.
Assume the third-party web service requires authorization by http header.
As per this link, it means that client should provide the Authorization header that looks like:
Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l
where QWxhZGRpbjpPcGVuU2VzYW1l
is Base64-encoded string
that contains credentials - username and password formatted as "username:password
" before ones were Base64
-encoded.
Basic Authentication mechanism for WCF will not work in that case because WCF client data is encapsulated inside the http request.
That is WCF client data in XML format (envelop) is located in the "data
" part of http request, so no one http header can be modified by that data.
The solution to a problem is using OutgoingMessageProperties
and OperationContextScope.
Using the Code
Assume you already have WCF-based client cc
which communicates with a third-party service Calculator
that requires authorization by http header and you want to call method Add
mentioned here.
Use this code to do it:
using (new CalculatorOperationContextScope(cc.InnerChannel).ClientChannel(basicHttpAuth))
{
cc.Add(100, 1);
}
where:
string basicHttpAuth =
string.Format
(
"Basic {0}", Convert.ToBase64String(new UTF8Encoding().GetBytes("MyUserName:MyPassword"))
);
For .NET 4.6 or greater, you can use:
string basicHttpAuth =
$"Basic {Convert.ToBase64String(new UTF8Encoding().GetBytes("MyUserName:MyPassword"))}";
and CalculatorOperationContextScope
is a class that implements authorization by http header:
public class CalculatorOperationContextScope
{
private readonly OperationContextScope m_scope;
public CalculatorOperationContextScope(IClientChannel channel)
{
m_scope = new OperationContextScope(channel);
}
public IDisposable ClientChannel(string basicHttpAuth,
string customHttpHeaderName = null,
string customHttpHeaderValue = null)
{
return new ClientChannelItem
(m_scope, basicHttpAuth, customHttpHeaderName, customHttpHeaderValue);
}
private class ClientChannelItem : IDisposable
{
private readonly OperationContextScope m_scope;
public ClientChannelItem(OperationContextScope scope, string basicHttpAuth,
string customHttpHeaderName = null,
string customHttpHeaderValue = null)
{
m_scope = scope;
HttpRequestMessageProperty httpRequestProperty =
new HttpRequestMessageProperty();
httpRequestProperty.Headers[HttpRequestHeader.Authorization] = basicHttpAuth;
if (!string.IsNullOrEmpty(customHttpHeaderName) &&
customHttpHeaderName.Trim().Length > 0)
httpRequestProperty.Headers.Add(customHttpHeaderName, customHttpHeaderValue);
OperationContext.Current
.OutgoingMessageProperties[HttpRequestMessageProperty.Name] =
httpRequestProperty;
}
public void Dispose()
{
m_scope.Dispose();
}
}
}
In certain cases, third-party service can require additional http header(s) with specific name(s).
You can pass header name customHttpHeaderName
and header value customHttpHeaderValue
as optional parameters.
If you don't need support for such headers, simply remove that from code.
The check...
!string.IsNullOrEmpty(customHttpHeaderName) && customHttpHeaderName.Trim().Length > 0
...is for backward compatibility with .NET 3.5.
For .NET 4.0 or greater, you can check:
!string.IsNullOrWhiteSpace(customHttpHeaderName)
History
- 25th December, 2023: Initial version