目标(避免X Y问题):创建一个Windows服务,该服务定期查询REST API。 REST API需要Windows(集成)身份验证。
我有一个Windows服务的工作框架,该框架使用IHostedService运行长时间运行的进程。该IHostedService使用IRestClient查询REST API。为了避免必须手动管理HttpClient的功能,我尝试使用AddHttpClient
注入类型化的HttpClient。这有效,直到我尝试配置HttpMessageHandler。在任何可以找到将HttpClient设置为UseDefaultCredentials = true
的地方,似乎都没有设置它们。
我可以在RestClient服务中手动配置此选项。这将传递标题,但是如果我尝试使用CredentialCache.DefaultCredentials
或DefaultNetworkCredentails
,它们将返回空值。
对于所有这些抽象如何相互作用,这可能也是我的误解。
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中指定的任何配置。