I have a couple of classes that look like this:
Class REST
public class REST
{
...
public async Task<Status> GetStatus()
{
var message = new HttpRequestMessage(HttpMethod.Get, "https://localhost...");
message.Headers.TryAddWithoutValidation("Authorization",
$"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes("admin:admin"))}");
HttpResponseMessage response = null;
try
{
response = await HttpClient.SendAsync(message, HttpCompletionOption.ResponseContentRead);
return JsonConvert.DeserializeObject<Status>(response.Content.ReadAsStringAsync().Result);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
Class Logger
public class Logger
{
private static ReaderWriterLockSlim writeLock = new ReaderWriterLockSlim();
public async Task Log(int number, LogMessage message)
{
var time = DateTime.Now.ToString("O");
var fileName = "C:/temp/random.log";
writeLock.EnterWriteLock();
try
{
if (File.Exists(fileName))
{
if (new FileInfo(fileName).Length >= 10000000)
{
await WaitForRestCall(fileName);
File.Move(fileName, $"C:/temp/random_{Current}.log");
Console.WriteLine($"Logging message {number}, timestamp = {message.TimeStamp}");
using (var sw = File.CreateText(fileName))
{
var log = $"{number}\t{time}\t{message.Message}";
sw.WriteLine(log);
}
Current++;
}
else
{
Console.WriteLine($"Logging message {number}, timestamp = {message.TimeStamp}");
using (var sw = File.AppendText(fileName))
{
var log = $"{number}\t{time}\t{message.Message}";
sw.WriteLine(log);
}
}
}
else
{
Console.WriteLine($"Logging message {number}, timestamp = {message.TimeStamp}");
using (var sw = File.CreateText(fileName))
{
var log = $"{number}\t{time}\t{message.Message}";
sw.WriteLine(log);
}
}
}
catch (Exception ex)
{
throw;
}
finally
{
writeLock.ExitWriteLock();
}
}
private async Task WaitForRestCall(string fileName)
{
var finishedReading = false;
do
{
var check = await REST.Instance().GetStatus();
if (!check.OK)
{
Console.WriteLine($"Waiting for task to finish.");
Thread.Sleep(1000);
}
else
{
finishedReading = true
}
} while (!finishedReading);
}
}
(Both are singleton classes, that's why the Instance() method is called there)
I'm testing this interaction between the classes with this Console app:
Console
class Program
{
static void Main(string[] args)
{
Log();
Console.ReadKey();
}
public static Task Log()
{
string oneKBMessage = "<1KB string here>"
var logger = Logger.Instance();
var tasks = Enumerable.Range(0, 100000).Select(i => Task.Run(async () =>
{
await logger.Log(i, new LogMessage() { Message = oneKBMessage, TimeStamp = DateTime.Now });
}));
return Task.WhenAll(tasks);
}
}
Now, I followed Stephen Cleary's advice to make everything async all the way up, but when the application has to check with the REST API if it doesn't return "Done" and goes to sleep, the next cycle of that do/while when the REST class calls the API it freezes everything there. I assume there's a deadlock, but I can't see why it's happening.
Any ideas?
Thanks