我想出了運作良好的解決方案。
我創建了一個靜態方法,它接受兩個參數,一個Func和一個對我的 認證對象的引用。 Authentication對象可以重新進行身份驗證,並保存用於進行API調用的身份驗證信息。我使用了ref,因爲我不希望一個帳戶的Authenticator的多個實例存在不同的驗證令牌,但我需要能夠同時支持多個帳戶,所以我無法將其設置爲靜態。
public static string ReauthenticateOn401(
Func<Authenticator, string> method,
ref Authenticator authenticator)
{
if (method == null)
throw new ArgumentNullException("action");
if (authenticator == null)
throw new ArgumentNullException("authenticator");
int attempts_remaining = 2;
bool reauth_attempted = false;
while (attempts_remaining > 0)
{
try
{
return method(authenticator);
}
catch (WebException e)
{
if (e.Response != null && reauth_attempted == false)
{
if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.Unauthorized)
{
authenticator.GetAuthToken();
reauth_attempted = true;
attempts_remaining--;
}
else
{
throw;
}
}
else
{
throw;
}
}
}
throw new Exception("The ReauthenticateOn401 method failed to return a response or catch/throw an exception. The log flowed outside the while loop (not expected to be possible) and is generating this generic exception");
}
然後我有不同的類來從API請求數據。以下是其中一個可能的樣子,其中_authenticator在類實例化時被傳遞到類中。
string json = Authenticator.ReauthenticateOn401((authenticator) =>
{
string apiUrl = "http:/blahblahblah.api.com"
HttpWebRequest request = WebRequest.Create(apiUrl) as HttpWebRequest;
//Add headers, or adjust the body as necessary for your API
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}, ref _authenticator);
的美妙之處在於,我可以在任何邏輯我想ReathenticateOn401通過,它將嘗試調用該方法,然後如果接收到401重新驗證。否則,它會成功或拋出我可以處理的異常。