I am using httpClientFactory
to request a Wechat Pay API, but the Wechat Pay API needs a certificate. How can I configure httpClientFactory
to use the certificate?

- 3,752
- 35
- 31
- 35

- 31
- 1
- 2
3 Answers
First, you need register you HttpClient
:
services.AddHttpClient("signed")
.ConfigurePrimaryMessageHandler(() =>
{
var handler = new HttpClientHandler();
var certificate = new X509Certificate2(filename: "foo.pfx", password: "123");
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(certificate);
});
In the example the file foo.pfx contains a certificate with the password 123.
signed is the name of HttpClient
.
Second, you'll call IHttpClientFactory.CreateClient
to create the HttpClient
instance.
public class PayClient
{
private readonly IHttpClientFactory _httpClientFactory;
public PayClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task SomePayMethodAsync()
{
using (httpClient = _httpClientFactory.CreateClient("signed"))
{
// use httpClient
}
}
}
You need use same name signed as the parameter of CreateClient
.
LATER UPDATE
If you write SAAS with many certificates you may create and configure an HttpClient
manually every time you need it. It's the simplest way.
public class PayClient
{
private readonly ICurrentUserProvider _currentUserProvider;
public PayClient(ICurrentUserProvider _currentUserProvider)
{
_currentUserProvider = currentUserProvider;
}
private HttpClient CreateHttpClient()
{
var currentUser = _currentUserProvider.CurrentUser;
var filename = currentUser.CertificateFilename;
var password = currentUser.CertificatePassword;
var handler = new HttpClientHandler();
var certificate = new X509Certificate2(filename, password);
handler.ClientCertificateOptions = ClientCertificateOptions.Manual;
handler.ClientCertificates.Add(certificat);
return new HttpClient(handler);
}
public async Task SomePayMethodAsync()
{
using (httpClient = CreateHttpClient())
{
// use httpClient
}
}
}

- 1,823
- 6
- 15

- 7,937
- 1
- 25
- 29
-
But,How to config different cert with a same api url. because i have many different account and different cert to request a same api url. – junlei.lv Feb 06 '19 at 07:01
-
@junlei.lv You can register a few clients with different names. Each class like `PayClient` can create its own `HttpClient`. Usually you have single certificate for some remote service, so this decision should work. – Mark Shevchenko Feb 06 '19 at 07:07
-
Thanks you very much.but this method can not solve my question.because my software is a saas platform.we have many client.every client have different cert.but pay api address is same.So.register a few clients with different names is not very goods. – junlei.lv Feb 06 '19 at 07:14
-
do you have any other way? – junlei.lv Feb 06 '19 at 07:21
-
@junlei.lv I updated my answer with the alternate solution. May be it's more suitable for you. – Mark Shevchenko Feb 06 '19 at 08:12
-
actually,i am using this method now .but,this method will create many time_wait tcp – junlei.lv Feb 06 '19 at 08:41
-
can we talk about this question with email? – junlei.lv Feb 06 '19 at 08:45
-
@junlei.lv If you want optimize the code, you can cache `HttpClientHandler` instances. As the base you can get the implementation of `DefaultHttpClientFactory` class [here](https://github.com/aspnet/HttpClientFactory/blob/master/src/Microsoft.Extensions.Http/DefaultHttpClientFactory.cs). – Mark Shevchenko Feb 06 '19 at 09:33
-
7Won't the 'Later Update' approach lead to port exhaustion? – simon-pearson Apr 03 '20 at 16:17
-
3There should be no using statement for the httpClient – brett Nov 09 '21 at 14:16
-
@brett, why? It's not required, but it's not wrong too. If MS will change implementation of `HttpClient`, you don't need to rewrite the code. – Mark Shevchenko Nov 09 '21 at 14:37
-
2You will see performance problems with httpclient if you dispose it, as microsoft recommends to keep it long lived. I ended up registering several named HttpClients all with their own specific certificate set up. – brett Nov 09 '21 at 17:54
-
@brett, maybe you have read previous MS recommendations (related to .NET Framework)? Now `Dispose` is the almost empty method. https://stackoverflow.com/a/54326424/1051621 – Mark Shevchenko Nov 09 '21 at 19:59
-
I have doubts. The first approach looks good, but I don´t see where is the handler assigned to the factory flow... perhaps a "return handler;" line is missing? In the later update, I agree with @brett. I understood the HttpClientFactory exists to avoid the mentioned problem (port exhaustion). Even when you dispose the HttpClient, it remains open (dunno for how long). The factory, more or less, decides when is moment to reuse a connection and when to use a new one. – zameb Sep 21 '22 at 18:50
-
Very dangerous answer with that disposal in place. – julealgon Dec 16 '22 at 18:19
If you look at the Default factory returned in DI, it inherits from two interfaces, and when injecting you chose to only use one:
internal class DefaultHttpClientFactory : IHttpClientFactory, IHttpMessageHandlerFactory
Knowing this you can take a sneaky workaround:
_handlerFactory = _clientFactory as IHttpMessageHandlerFactory;
Now if you look at the handler factory, it has a method CreateHandler
with the same string argument as the CreateClient
method. Actually if you look at the implementation of CreateClient
, you can see it uses this method which then caches the handler.
So forget about Startup: Cast your client factory to handler factory, create a handler for your specific user, verify all properties on the handler (like is the certificate there or do you need to add it since it's a new instance) and then call CreateClient
as usual.
Edit: In startup you may still need to add ConfigurePrimaryHttpMessageHandler to actually create a HttpClientHandler, so you may have to make a consession of only registering one named HttpClient and just swapping the certificate. It still gives you the advantages of having the factory though.
Edit 2: know that the handler is wrapped a bunch of times in decorators, so you need to dig deep. The trick I use is:
var handler = _handlerFactory.CreateHandler("customer");
while (handler as DelegatingHandler != null)
{
handler = (handler as DelegatingHandler).InnerHandler;
}
var clientHandler = handler as HttpClientHandler;

- 12,981
- 8
- 59
- 68

- 21
- 3
-
This is great! I am using.NET Core 3.1 hand having issues and I think this solves it. I am trying to swap the certificate per request (similar to the OP). Can you please kindly expand on what the Startup would look like? It would help me out so much! – PKCS12 Sep 08 '20 at 09:10
-
I added services.AddHttpClient(); but when I used the DI IHttpMEssageHandlerFactory, it is null. Any advice please? Thanks – PKCS12 Sep 08 '20 at 11:56
-
HttpMessageHandler will be pooled till expiry time (default 2 mins), so before a request completes changing the handler properties will not cause any problem? – Nithya Feb 13 '21 at 09:36
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new SocketsHttpHandler()
{
UseCookies = false,
};
});

- 35
- 1
- 5