我是.net的新手,我真的很想了解应用程序的这种行为。我有一个名为GetOrg()
的函数,该函数基本上会请求API端点并获取数据,以获取我需要在每个请求中传递Auth令牌的数据。要获取Auth令牌,我还有另一个函数调用GetAccessToken
获取令牌并将其保存在缓存中。我创建了一个名为httpclient
的令牌,该令牌将令牌附加到对NonProductionEnv
客户端的每个请求中。
现在的问题是,当我在托管服务中设置GetOrg()
时,如下所示,它没有附加令牌并请求没有auth令牌的API端点,但是如果我在控制器中设置了GetOrg()
,它就可以正常工作。 / p>
托管服务:
public class TokenService : DelegatingHandler, IHostedService
{
public IConfiguration Configuration { get; }
protected IMemoryCache _cache;
private Timer _timer;
public IHttpClientFactory _clientFactory;
protected HttpClient _client_NP;
private readonly IServiceScopeFactory _scopeFactory;
public TokenService(IConfiguration configuration, IMemoryCache memoryCache, IHttpClientFactory clientFactory, IServiceScopeFactory scopeFactory)
{
Configuration = configuration;
_cache = memoryCache;
_clientFactory = clientFactory;
_scopeFactory = scopeFactory;
// NamedClients foreach Env.
_client_NP = _clientFactory.CreateClient("NonProductionEnv");
}
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(GetAccessToken, null, 0, 3300000);
// Thread.Sleep(2000);
_timer = new Timer(Heartbeat, null, 1000, 1000);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
//Timer does not have a stop.
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public async Task<Token> GetToken(Uri authenticationUrl, Dictionary<string, string> authenticationCredentials)
{
HttpClient client = new HttpClient();
FormUrlEncodedContent content = new FormUrlEncodedContent(authenticationCredentials);
HttpResponseMessage response = await client.PostAsync(authenticationUrl, content);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
string message = String.Format("POST failed. Received HTTP {0}", response.StatusCode);
throw new ApplicationException(message);
}
string responseString = await response.Content.ReadAsStringAsync();
Token token = JsonConvert.DeserializeObject<Token>(responseString);
return token;
}
private void GetAccessToken(object state)
{
Dictionary<string, string> authenticationCredentials_np = Configuration.GetSection("NonProductionEnvironment:Credentials").GetChildren().Select(x => new KeyValuePair<string, string>(x.Key, x.Value)).ToDictionary(x => x.Key, x => x.Value);
Token token_np = GetToken(new Uri(Configuration["NonProductionEnvironment:URL"]), authenticationCredentials_np).Result;
_cache.Set("np", token_np.AccessToken);
}
public void Heartbeat(object state)
{
// Discard the result
_ = GetOrg();
}
public async Task GetOrg()
{
var request = new HttpRequestMessage(HttpMethod.Get, "organizations");
var response = await _client_NP.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
OrganizationsClass.OrgsRootObject model = JsonConvert.DeserializeObject<OrganizationsClass.OrgsRootObject>(json);
using (var scope = _scopeFactory.CreateScope())
{
var _DBcontext = scope.ServiceProvider.GetRequiredService<PCFStatusContext>();
foreach (var item in model.resources)
{
var g = Guid.Parse(item.guid);
var x = _DBcontext.Organizations.FirstOrDefault(o => o.OrgGuid == g);
if (x == null)
{
_DBcontext.Organizations.Add(new Organizations
{
OrgGuid = g,
Name = item.name,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Timestamp = DateTime.Now,
Foundation = 3
});
}
else if (x.UpdatedAt != item.updated_at)
{
x.CreatedAt = item.created_at;
x.UpdatedAt = item.updated_at;
x.Timestamp = DateTime.Now;
}
}
await GetSpace();
await _DBcontext.SaveChangesAsync();
}
}
}
启动中的命名客户端:
services.AddHttpClient("NonProductionEnv", client =>
{
client.BaseAddress = new Uri(Configuration["NonProductionEnvironment:NP_API_URL"]);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", (String)_cache.Get("np"));
});
下面的日志每秒生成一次,因为我需要每秒调用api端点。
现在收听:https://localhost:5001现在收听: http://localhost:5000应用程序已启动。按Ctrl + C关闭。 信息:System.Net.Http.HttpClient.NonProductionEnv.LogicalHandler [100] 开始处理HTTP请求GET https://api.sample.io/v3/organizations信息: System.Net.Http.HttpClient.NonProductionEnv.ClientHandler [100] 发送HTTP请求GET https://api.sample.io/v3/organizations信息:System.Net.Http.HttpClient.NonProductionEnv.ClientHandler [101] 53.3973毫秒后收到HTTP响应-未经授权
PS:我对.net及其工作原理并不了解。
答案 0 :(得分:0)
您的HttpClient
正在注册,并且在应用启动时从缓存中检索了静态值。此时,您的托管服务尚未运行,因此缓存中没有任何值。一旦缓存中终于有了一个值,标头就已经设置很久了,您再也不会重置它。
这里实际上完全不需要缓存。您也不需要在实际的客户注册中设置Authorization
标头。相反,只需将您的GetAccessToken
方法修改为:
private void GetAccessToken(object state)
{
Dictionary<string, string> authenticationCredentials_np = Configuration.GetSection("NonProductionEnvironment:Credentials").GetChildren().Select(x => new KeyValuePair<string, string>(x.Key, x.Value)).ToDictionary(x => x.Key, x => x.Value);
Token token_np = GetToken(new Uri(Configuration["NonProductionEnvironment:URL"]), authenticationCredentials_np).Result;
_client_NP.DefaultRequestHeaders.Add("Authorization", $"Bearer {token_np.AccessToken}");
}