使用服务帐户的凭据的具有IHttpClientFactory的Net Core Windows服务

时间:2018-09-17 18:38:48

标签: c# windows .net-core windows-services

目标(避免X Y问题):创建一个Windows服务,该服务定期查询REST API。 REST API需要Windows(集成)身份验证。

我有一个Windows服务的工作框架,该框架使用IHostedService运行长时间运行的进程。该IHostedService使用IRestClient查询REST API。为了避免必须手动管理HttpClient的功能,我尝试使用AddHttpClient注入类型化的HttpClient。这有效,直到我尝试配置HttpMessageHandler。在任何可以找到将HttpClient设置为UseDefaultCredentials = true的地方,似乎都没有设置它们。

我可以在RestClient服务中手动配置此选项。这将传递标题,但是如果我尝试使用CredentialCache.DefaultCredentialsDefaultNetworkCredentails,它们将返回空值。

对于所有这些抽象如何相互作用,这可能也是我的误解。

Program.cs

private static async Task Main(string[] args)
{
    var builder = new HostBuilder()
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            // Settings
        })
        .ConfigureServices((hostContext, services) =>
        {
            // Other services omitted

            services.AddSingleton<ITimer, CustomTimersTimer>();

            services.AddHttpClient<IRestClient, RestClient>()
                .ConfigureHttpMessageHandlerBuilder(config => new HttpClientHandler()
                {
                    // Seems to have no effect
                    UseDefaultCredentials = true,
                    UseProxy = false,
                    UseCookies = false
                });
            services.AddHostedService<RestDataGatheringService>();
        })
        .ConfigureLogging((hostingContext, logging) =>
        {
            // Logging
        }

RestDataGatheringService.cs

public class RestDataGatheringService : IHostedService, IDisposable
{
    private ITimer _timer;
    private readonly ILogger<RestDataGatheringService> _logger;
    private readonly IRestClient _client;

    public RestDataGatheringService(IRestClient restClient, ITimer timer, ILogger<RestDataGatheringService> logger)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _timer = timer ?? throw new ArgumentNullException(nameof(timer));
        _client = restClient ?? throw new ArgumentNullException(nameof(restClient));
    }
}

RestClient.cs

public class RestClient : IRestClient
{
    private readonly HttpClient _client;
    private readonly ILogger<RestClient> _logger;
    private readonly IOptions<ConnectionSettings> _config;


    public RestClient(HttpClient httpClient, IOptions<ConnectionSettings> config, ILogger<RestClient> logger)
    {
        _client = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
        _config = config ?? throw new ArgumentNullException(nameof(config));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));

        _client.BaseAddress = new Uri(_config.Value.VCenterConnectionString);
    }

    public async Task Connect()
    {
        string login = "/rest/login";

        // Uncommenting this section adds the request header, although DefaultNetworkCredentials has an empty username and password.
        // Without it, the Authorization header is not present as I would expect it to be
        // _client.DefaultRequestHeaders.Authorization =
        //    new System.Net.Http.Headers.AuthenticationHeaderValue(
        //        "Basic",
        //        Convert.ToBase64String(
        //            System.Text.ASCIIEncoding.ASCII.GetBytes(
        //                string.Format("{0}:{1}",
        //                    System.Net.CredentialCache.DefaultNetworkCredentials.UserName,
        //                    System.Net.CredentialCache.DefaultNetworkCredentials.Password))));

        var result = await _client.PostAsync(login, null);

    }

我已经看到一些documentation指出在调试时无法从DefaultCredentials检索当前的用户名和密码,但是即使我dotnet publish -c Release -r win7-x64并运行可执行文件,此行为仍然存在。我还假设DefaultNetworkCredentials也是如此。

阅读this question后,我查看了RestDataGatheringService._client上的inner-inner-inner处理程序,它似乎没有应用Program.cs中指定的任何配置。

解决方案hereherehere不适用于我。

0 个答案:

没有答案