在以下代码中:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS4014:Await.Warning")]
private async Task<bool> Refresh()
{
log.Info("Refreshing Token.");
Debug.WriteLine("Refreshing Token.");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(TOKEN_URL);
request.Method = "POST";
request.ContentType = "application/json; charset=UTF-8";
request.Headers.Add("Authorization", "basic " + authCode);
request.Accept = "application/json, text/javascript, */*; q=0.01";
request.ContentLength = payload.Length;
log.Debug(request.Headers["Authorization"]);
Debug.WriteLine(request.Headers["Authorization"]);
using (Stream writeStream = request.GetRequestStream())
{
await writeStream.WriteAsync(payload, 0, payload.Length);
}
lock (tokenLock)
{
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
tokenLock.EnterWriteLock();
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
}
try
{
string body;
using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
{
int numericStatusCode = (int)response.StatusCode;
Debug.WriteLine($"Response Code: {numericStatusCode}");
if (response.StatusCode != HttpStatusCode.OK)
{
log.Error($"!!!!! Request failed. Received HTTP {response.StatusCode}");
body = string.Empty;
}
else
{
string responseValue = string.Empty;
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream))
{
responseValue = await reader.ReadToEndAsync();
}
}
}
body = responseValue;
Debug.WriteLine($"Response Body = {body}");
log.Trace($"Response Body = {body}");
}
}
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
if (!string.IsNullOrEmpty(body))
{
_token = JsonConvert.DeserializeObject<AuthTokenInfo>(body, serializerSettings);
refreshUri = _token.RefreshTokenServerUri;
payload = Encoding.GetEncoding("utf-8").GetBytes(
JsonConvert.SerializeObject(new { grant_type = "refresh_token", _token.RefreshToken })
);
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
Debug.WriteLine($"Token Refreshed, Expires In = {_token.ExpiresIn}");
Debug.WriteLine($"Access Token = {_token.AccessToken}");
Debug.WriteLine($"New Token Refresh URI: {refreshUri}");
Debug.WriteLine($"New Refresh Token: {_token.RefreshToken}");
if (_token != null)
{
int refreshTime = 60 * 1000; // (Token.ExpiresIn.Value - (15 * 60)) * 1000;
log.Info($"Refreshing token in {refreshTime} milliseconds.");
Debug.WriteLine($"Refreshing token in {refreshTime} milliseconds.");
Task.Delay(refreshTime).ContinueWith(async (action) =>
{
log.Info("Refreshing token NOW.");
Debug.WriteLine("Refreshing token NOW.");
await Refresh();
});
Debug.WriteLine("Refresh scheduled.");
}
}
}
finally
{
lock(tokenLock)
{
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
tokenLock.ExitWriteLock();
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
}
}
return true;
}
当我执行此代码时,我的调试输出显示:
Refreshing Token.
Write Lock enabled? False
Write Lock enabled? True
Response Code: 200
Write Lock enabled? False
Write Lock enabled? False
Token Refreshed, Expires In = 3600
Refreshing token in 60000 milliseconds.
Refresh scheduled.
Write Lock enabled? False
Exception thrown: 'System.Threading.SynchronizationLockException' in System.Core.dll
Exception thrown: 'System.AggregateException' in mscorlib.dll
Exception thrown: 'System.TypeInitializationException' in InContactApi.dll
Exception thrown: 'System.TypeInitializationException' in mscorlib.dll
Exception thrown: 'System.AggregateException' in mscorlib.dll
An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll
One or more errors occurred.
Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.TypeInitializationException: The type initializer for 'InContact.Auth' threw an exception. ---> System.AggregateException: One or more errors occurred. ---> System.Threading.SynchronizationLockException: The write lock is being released without being held.
at System.Threading.ReaderWriterLockSlim.ExitWriteLock()
at InContact.AuthToken.<Refresh>d__12.MoveNext() in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\Auth.cs:line 206
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at InContact.AuthToken..ctor() in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\Auth.cs:line 106
at InContact.Auth..cctor() in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\Auth.cs:line 236
--- End of inner exception stack trace ---
at InContact.Auth.get_BaseURL()
at InContact.InContactApi.MakeRequestURL(String subURL, Dictionary`2 query, String callerName) in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\InContactApi.cs:line 127
at InContact.InContactApi.<GetFolderListing>d__26.MoveNext() in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\InContactApi.cs:line 607
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at CallLogger.ICRecordings.<DirTraverse>d__8.MoveNext() in C:\Users\chill\source\repos\interactive_intelligence\CallLogger\CallLogger\ICRecordings.cs:line 73
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at CallLogger.Program.Main() in C:\Users\chill\source\repos\interactive_intelligence\CallLogger\CallLogger\Program.cs:line 32
The program '[34036] PhoneLogger.exe' has exited with code 0 (0x0).
我不明白我的写锁是如何在代码中途解锁的,只有一个写解锁线我在最后一个块的末尾。
任何人都可以为我阐明这一点,并/或建议更好的方法吗?
我正在处理一个OAuth系统,该系统具有必须每小时刷新一次的访问令牌(当我最终完成它时)。我已实现此Refresh方法来完成目标,并使用Task.Delay().ContinueWith()
调用来安排刷新自动运行。我正在使用ReadWriterLockSlim,以便我可以在刷新发生时锁定读取继续。否则我希望它们正常工作。我需要锁定它们,因为一旦我在刷新时从服务器请求新令牌,我就不能再使用旧的身份验证令牌了。
答案 0 :(得分:0)
Aleks Andreev,谢谢你。
所以解决方案是不使用ReadWriterLockSlim,而是安装Nito.AsyncEx NuGet模块,然后使用它的AsyncReadWriterLock。因为ReadWriterLockSlim不能与async / await一起使用。