我有一个有效的方法,看起来基本上是这样的:
public IObservable<List<Stuff>> GetGoodStuff()
{
return Observable.FromAsync(GetAccessTokenAsync)
.SelectMany(accessToken =>
{
return httpClient.SendAsync(request);
})
.SelectMany(response =>
{
response.EnsureSuccessStatusCode();
return response.Content.ReadAsStringAsync();
})
.Select(json =>
{
return JsonConvert.DeserializeObject<List<Stuff>>(json);
});
}
“ GetAccessTokenAsync”返回api的缓存访问令牌,否则,第一次将获取令牌。就httpclient和Rx而言,其余的都是非常标准的。
事情是这样的:我想捕获401错误,更新访问令牌,然后重试整个过程。但是只有一次-之后,它将异常抛出给调用者。
在该中间块中,我可以这样做:
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
InvalidateAccessToken();
// what now???
}
但是那又怎样呢?没有看到递归调用将如何工作。不知何故包裹了整个东西?还没看到...
到目前为止,两个答案都不错。更具声明性的方法似乎没有多大变化,并且能够隐藏很多“管道”,但是我无法完全使它在所有情况下都能正常工作。
因此,根据@Timothy Shields的建议,我想到了此代码,它看起来不错,并且很好地隐藏了管道(是的,它可以工作:-)
/// <summary>
/// Makes an httpclient request using the access token. If Unauthorized is received the access
/// token will be reacquired and the request will be retried once.
/// </summary>
/// <returns>The json result from a successful request.</returns>
async Task<string> MakeRequestWithAccessToken(string requestUri, CancellationToken cancellationToken)
{
const int RetryCount = 1;
HttpResponseMessage response = null;
for (int i = 0; i <= RetryCount; i++)
{
var accessToken = await GetAccessTokenAsync();
var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
request.Headers.Add("Authorization", "Bearer " + accessToken);
var client = new RemoteService(ApiUrl).NewClient();
response = await client.SendAsync(request, cancellationToken);
if (i < RetryCount && response.StatusCode == HttpStatusCode.Unauthorized)
{
InvalidateAccessToken();
continue;
}
response.EnsureSuccessStatusCode();
}
return await response.Content.ReadAsStringAsync();
}
public IObservable<List<Stuff>> GetGoodStuff(int maxCount)
{
return Observable.FromAsync(async cancellationToken =>
{
var requestUri = string.Format("mypath.json?count={0}", maxCount);
var json = await MakeRequestWithAccessToken(requestUri, cancellationToken);
return JsonConvert.DeserializeObject<List<Stuff>>(json);
});
}
您应该使用async
-await
来做到这一点:
public IObservable<List<Stuff>> GetGoodStuff()
{
return Observable.FromAsync(async cancellationToken =>
{
const int RetryCount = 1;
for (int i = 0; i <= RetryCount; i++)
{
var accessToken = await GetAccessTokenAsync();
var request = MakeRequest(accessToken);
var response = await httpClient.SendAsync(request, cancellationToken);
if (i < RetryCount && response.StatusCode == HttpStatusCode.Unauthorized)
{
InvalidateAccessToken();
continue;
}
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync(cancellationToken);
return JsonConvert.DeserializeObject<List<Stuff>>(json);
}
});
}
这项技术使您可以编写标准命令式代码,并公开为nice IObservable<T>
。
请注意,我只是在猜测您的“重试”外观。调用后尚不清楚您要做什么InvalidateAccessToken()
,所以我猜测了一下并发明了该MakeRequest
方法。您应该很容易将其适应于完全符合您想要的代码。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句