* Add support for HttpClientFactory with KubernetesClientConfiguration * Add an example with http client factory * ensure sample uses the latest version of C#
This commit is contained in:
committed by
Kubernetes Prow Robot
parent
fcd8c166da
commit
e00f67abd4
43
examples/httpClientFactory/PodListHostedService.cs
Normal file
43
examples/httpClientFactory/PodListHostedService.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using k8s;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace httpClientFactory
|
||||||
|
{
|
||||||
|
// Learn more about IHostedServices at https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.2&tabs=visual-studio
|
||||||
|
internal class PodListHostedService : IHostedService
|
||||||
|
{
|
||||||
|
private readonly IKubernetes _kubernetesClient;
|
||||||
|
private readonly ILogger<PodListHostedService> _logger;
|
||||||
|
|
||||||
|
public PodListHostedService(IKubernetes kubernetesClient, ILogger<PodListHostedService> logger)
|
||||||
|
{
|
||||||
|
_kubernetesClient = kubernetesClient ?? throw new ArgumentNullException(nameof(kubernetesClient));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Starting Request!");
|
||||||
|
|
||||||
|
var list = await _kubernetesClient.ListNamespacedPodAsync("default", cancellationToken: cancellationToken);
|
||||||
|
foreach (var item in list.Items)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(item.Metadata.Name);
|
||||||
|
}
|
||||||
|
if (list.Items.Count == 0)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Empty!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Nothing to stop
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
examples/httpClientFactory/Program.cs
Normal file
46
examples/httpClientFactory/Program.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using k8s;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace httpClientFactory
|
||||||
|
{
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
// Learn more about generic hosts at https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host
|
||||||
|
using (var host = new HostBuilder()
|
||||||
|
.ConfigureLogging((logging) =>
|
||||||
|
{
|
||||||
|
logging.AddConsole();
|
||||||
|
})
|
||||||
|
.ConfigureServices((hostBuilderContext, services) =>
|
||||||
|
{
|
||||||
|
// Ideally this config would be read from the .net core config constructs,
|
||||||
|
// but that has not been implemented in the KubernetesClient library at
|
||||||
|
// the time this sample was created.
|
||||||
|
var config = KubernetesClientConfiguration.BuildDefaultConfig();
|
||||||
|
services.AddSingleton(config);
|
||||||
|
|
||||||
|
// Setup the http client
|
||||||
|
services.AddHttpClient("K8s")
|
||||||
|
.AddTypedClient<IKubernetes>((httpClient, serviceProvider) =>
|
||||||
|
{
|
||||||
|
return new Kubernetes(
|
||||||
|
serviceProvider.GetRequiredService<KubernetesClientConfiguration>(),
|
||||||
|
httpClient);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the class that uses the client
|
||||||
|
services.AddHostedService<PodListHostedService>();
|
||||||
|
})
|
||||||
|
.Build())
|
||||||
|
{
|
||||||
|
await host.StartAsync().ConfigureAwait(false);
|
||||||
|
await host.StopAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
examples/httpClientFactory/httpClientFactory.csproj
Normal file
19
examples/httpClientFactory/httpClientFactory.csproj
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\KubernetesClient\KubernetesClient.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 15.0.26430.16
|
VisualStudioVersion = 16.0.29230.47
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{B70AFB57-57C9-46DC-84BE-11B7DDD34B40}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{B70AFB57-57C9-46DC-84BE-11B7DDD34B40}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -31,7 +31,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{879F8787-C3B
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesWatchGenerator", "gen\KubernetesWatchGenerator\KubernetesWatchGenerator.csproj", "{542DC30E-FDF7-4A35-B026-6C21F435E8B1}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesWatchGenerator", "gen\KubernetesWatchGenerator\KubernetesWatchGenerator.csproj", "{542DC30E-FDF7-4A35-B026-6C21F435E8B1}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "patch", "examples\patch\patch.csproj", "{04DE2C84-117D-4E21-8B45-B7AE627697BD}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "patch", "examples\patch\patch.csproj", "{04DE2C84-117D-4E21-8B45-B7AE627697BD}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpClientFactory", "examples\httpClientFactory\httpClientFactory.csproj", "{A07314A0-02E8-4F36-B233-726D59D28F08}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@@ -175,6 +177,18 @@ Global
|
|||||||
{04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x64.Build.0 = Release|Any CPU
|
{04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x86.ActiveCfg = Release|Any CPU
|
{04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x86.Build.0 = Release|Any CPU
|
{04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -191,6 +205,7 @@ Global
|
|||||||
{806AD0E5-833F-42FB-A870-4BCEE7F4B17F} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
|
{806AD0E5-833F-42FB-A870-4BCEE7F4B17F} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
|
||||||
{542DC30E-FDF7-4A35-B026-6C21F435E8B1} = {879F8787-C3BB-43F3-A92D-6D4C7D3A5285}
|
{542DC30E-FDF7-4A35-B026-6C21F435E8B1} = {879F8787-C3BB-43F3-A92D-6D4C7D3A5285}
|
||||||
{04DE2C84-117D-4E21-8B45-B7AE627697BD} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
|
{04DE2C84-117D-4E21-8B45-B7AE627697BD} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
|
||||||
|
{A07314A0-02E8-4F36-B233-726D59D28F08} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {049A763A-C891-4E8D-80CF-89DD3E22ADC7}
|
SolutionGuid = {049A763A-C891-4E8D-80CF-89DD3E22ADC7}
|
||||||
|
|||||||
@@ -13,84 +13,68 @@ namespace k8s
|
|||||||
{
|
{
|
||||||
public partial class Kubernetes
|
public partial class Kubernetes
|
||||||
{
|
{
|
||||||
#if MONOANDROID8_1
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Kubernetes" /> class.
|
/// Initializes a new instance of the <see cref="Kubernetes" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name='config'>
|
/// <param name='config'>
|
||||||
/// Optional. The delegating handlers to add to the http client pipeline.
|
/// The kube config to use.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="handlers">
|
/// <param name="httpClient">
|
||||||
/// Optional. The delegating handlers to add to the http client pipeline.
|
/// The <see cref="HttpClient" /> to use for all requests.
|
||||||
/// </param>
|
/// </param>
|
||||||
public Kubernetes(KubernetesClientConfiguration config, params DelegatingHandler[] handlers) : this(new Xamarin.Android.Net.AndroidClientHandler(), handlers)
|
public Kubernetes(KubernetesClientConfiguration config, HttpClient httpClient) : this(config, httpClient, false)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(config.Host))
|
|
||||||
{
|
|
||||||
throw new KubeConfigException("Host url must be set");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
BaseUri = new Uri(config.Host);
|
|
||||||
}
|
|
||||||
catch (UriFormatException e)
|
|
||||||
{
|
|
||||||
throw new KubeConfigException("Bad host url", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
CaCerts = config.SslCaCerts;
|
|
||||||
SkipTlsVerify = config.SkipTlsVerify;
|
|
||||||
|
|
||||||
if (BaseUri.Scheme == "https")
|
|
||||||
{
|
|
||||||
if (config.SkipTlsVerify)
|
|
||||||
{
|
|
||||||
System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (CaCerts == null)
|
|
||||||
{
|
|
||||||
throw new KubeConfigException("a CA must be set when SkipTlsVerify === false");
|
|
||||||
}
|
|
||||||
|
|
||||||
var certList = new System.Collections.Generic.List<Java.Security.Cert.Certificate>();
|
|
||||||
|
|
||||||
foreach (X509Certificate2 caCert in CaCerts)
|
|
||||||
{
|
|
||||||
using (System.IO.MemoryStream certStream = new System.IO.MemoryStream(caCert.RawData))
|
|
||||||
{
|
|
||||||
Java.Security.Cert.Certificate cert = Java.Security.Cert.CertificateFactory.GetInstance("X509").GenerateCertificate(certStream);
|
|
||||||
|
|
||||||
certList.Add(cert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Xamarin.Android.Net.AndroidClientHandler handler = (Xamarin.Android.Net.AndroidClientHandler)this.HttpClientHandler;
|
|
||||||
|
|
||||||
handler.TrustedCerts = certList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set credentails for the kubernernet client
|
|
||||||
SetCredentials(config, HttpClientHandler);
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Kubernetes" /> class.
|
/// Initializes a new instance of the <see cref="Kubernetes" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name='config'>
|
/// <param name='config'>
|
||||||
/// Optional. The delegating handlers to add to the http client pipeline.
|
/// The kube config to use.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="httpClient">
|
||||||
|
/// The <see cref="HttpClient" /> to use for all requests.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="disposeHttpClient">
|
||||||
|
/// Whether or not the <see cref="Kubernetes"/> object should own the lifetime of <paramref name="httpClient"/>.
|
||||||
|
/// </param>
|
||||||
|
public Kubernetes(KubernetesClientConfiguration config, HttpClient httpClient, bool disposeHttpClient) : this(httpClient, disposeHttpClient)
|
||||||
|
{
|
||||||
|
ValidateConfig(config);
|
||||||
|
CaCerts = config.SslCaCerts;
|
||||||
|
SkipTlsVerify = config.SkipTlsVerify;
|
||||||
|
InitializeFromConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Kubernetes" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='config'>
|
||||||
|
/// The kube config to use.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="handlers">
|
/// <param name="handlers">
|
||||||
/// Optional. The delegating handlers to add to the http client pipeline.
|
/// Optional. The delegating handlers to add to the http client pipeline.
|
||||||
/// </param>
|
/// </param>
|
||||||
public Kubernetes(KubernetesClientConfiguration config, params DelegatingHandler[] handlers) : this(handlers)
|
public Kubernetes(KubernetesClientConfiguration config, params DelegatingHandler[] handlers)
|
||||||
|
#if MONOANDROID8_1
|
||||||
|
: this(new Xamarin.Android.Net.AndroidClientHandler(), handlers)
|
||||||
|
#else
|
||||||
|
: this(handlers)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
ValidateConfig(config);
|
||||||
|
CaCerts = config.SslCaCerts;
|
||||||
|
SkipTlsVerify = config.SkipTlsVerify;
|
||||||
|
InitializeFromConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateConfig(KubernetesClientConfiguration config)
|
||||||
|
{
|
||||||
|
if (config == null)
|
||||||
|
{
|
||||||
|
throw new KubeConfigException("KubeConfig must be provided");
|
||||||
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(config.Host))
|
if (string.IsNullOrWhiteSpace(config.Host))
|
||||||
{
|
{
|
||||||
throw new KubeConfigException("Host url must be set");
|
throw new KubeConfigException("Host url must be set");
|
||||||
@@ -104,10 +88,10 @@ namespace k8s
|
|||||||
{
|
{
|
||||||
throw new KubeConfigException("Bad host url", e);
|
throw new KubeConfigException("Bad host url", e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CaCerts = config.SslCaCerts;
|
private void InitializeFromConfig(KubernetesClientConfiguration config)
|
||||||
SkipTlsVerify = config.SkipTlsVerify;
|
{
|
||||||
|
|
||||||
if (BaseUri.Scheme == "https")
|
if (BaseUri.Scheme == "https")
|
||||||
{
|
{
|
||||||
if (config.SkipTlsVerify)
|
if (config.SkipTlsVerify)
|
||||||
@@ -115,7 +99,7 @@ namespace k8s
|
|||||||
#if NET452
|
#if NET452
|
||||||
((WebRequestHandler) HttpClientHandler).ServerCertificateValidationCallback =
|
((WebRequestHandler) HttpClientHandler).ServerCertificateValidationCallback =
|
||||||
(sender, certificate, chain, sslPolicyErrors) => true;
|
(sender, certificate, chain, sslPolicyErrors) => true;
|
||||||
#elif XAMARINIOS1_0
|
#elif XAMARINIOS1_0 || MONOANDROID8_1
|
||||||
System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
|
System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -129,9 +113,8 @@ namespace k8s
|
|||||||
{
|
{
|
||||||
if (CaCerts == null)
|
if (CaCerts == null)
|
||||||
{
|
{
|
||||||
throw new KubeConfigException("a CA must be set when SkipTlsVerify === false");
|
throw new KubeConfigException("A CA must be set when SkipTlsVerify === false");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NET452
|
#if NET452
|
||||||
((WebRequestHandler) HttpClientHandler).ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
|
((WebRequestHandler) HttpClientHandler).ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
|
||||||
{
|
{
|
||||||
@@ -143,6 +126,22 @@ namespace k8s
|
|||||||
var cert = new X509Certificate2(certificate);
|
var cert = new X509Certificate2(certificate);
|
||||||
return Kubernetes.CertificateValidationCallBack(sender, CaCerts, cert, chain, sslPolicyErrors);
|
return Kubernetes.CertificateValidationCallBack(sender, CaCerts, cert, chain, sslPolicyErrors);
|
||||||
};
|
};
|
||||||
|
#elif MONOANDROID8_1
|
||||||
|
var certList = new System.Collections.Generic.List<Java.Security.Cert.Certificate>();
|
||||||
|
|
||||||
|
foreach (X509Certificate2 caCert in CaCerts)
|
||||||
|
{
|
||||||
|
using (var certStream = new System.IO.MemoryStream(caCert.RawData))
|
||||||
|
{
|
||||||
|
Java.Security.Cert.Certificate cert = Java.Security.Cert.CertificateFactory.GetInstance("X509").GenerateCertificate(certStream);
|
||||||
|
|
||||||
|
certList.Add(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var handler = (Xamarin.Android.Net.AndroidClientHandler)this.HttpClientHandler;
|
||||||
|
|
||||||
|
handler.TrustedCerts = certList;
|
||||||
#else
|
#else
|
||||||
HttpClientHandler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
|
HttpClientHandler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
|
||||||
{
|
{
|
||||||
@@ -155,7 +154,6 @@ namespace k8s
|
|||||||
// set credentails for the kubernernet client
|
// set credentails for the kubernernet client
|
||||||
SetCredentials(config, HttpClientHandler);
|
SetCredentials(config, HttpClientHandler);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
private X509Certificate2Collection CaCerts { get; }
|
private X509Certificate2Collection CaCerts { get; }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user