1

I'm trying to use

using (StreamWriter sw = File.AppendText(filePath))
{
    sw.WriteLine(n.InnerText);
}

inside a method which has I think must be async, because it's calling a await on an async method GetByteArrayAsync()

PollSite Function:

private async void PollSite(string filePath, string siteURL)
{
    response = await http.GetByteArrayAsync(siteURL);
    source = WebUtility.HtmlDecode(Encoding
        .GetEncoding("utf-8")
        .GetString(response, 0, response.Length - 1));
    result = new HtmlDocument();
    result.LoadHtml(source);

    gNode = result.GetElementbyId("SomeTable");

    using (StreamWriter sw = File.AppendText(filePath))
    {
        foreach (HtmlNode n in gNode.Descendants("td"))
        {
            sw.WriteLine(n.InnerText);
        }
    }
}

Trying to write gives me the error:

The process cannot access the file 'filePath' because it is being used by another process.

I'm assuming this is because of the async calls, but have no idea how to get round this and achieve the file write - is it because of the using statement?

Liam
  • 27,717
  • 28
  • 128
  • 190
jamheadart
  • 5,047
  • 4
  • 32
  • 63
  • 1
    Are you sure the file located at `filePath` isn't opened by another part of the application, or another application entirely? The way you're using StreamWriter in the provided code should be fine. – WSC Sep 28 '20 at 10:05
  • 3
    This has nothing to do with it being async, its exactly as the error says - you cant write to the path as something (probably your own program) is already using it - you're probably forgetting somewhere else to close the write stream – Jamiec Sep 28 '20 at 10:05
  • 1
    [`async void` is wrong, this should be `async Task`](https://stackoverflow.com/questions/45447955/why-exactly-is-void-async-bad) – Liam Sep 28 '20 at 10:06
  • 1
    When you call the method regularly (aka you are polling) do you call the method with await? I asume you are polling without waiting (awaiting) for the method and you have multiple PollSite methods running in parallel. – Ralf Sep 28 '20 at 10:08
  • To clarify what Liam and Ralf are getting at; if you don't `await` this method (i.e. make it return a `Task`) you could fire the method multiple times, all whilst looking at the same file and thus have multiple processes trying to write to the same file. – WSC Sep 28 '20 at 10:10
  • Ahh guys, thank you, it was because right at the start outside of these threads I'd used `File.Create("MyFilePath");` - if I comment that out, it works fine so I guess `File.Create` keeps the file open and I need to close it somehow. – jamheadart Sep 28 '20 at 10:15
  • [Avoid async void](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void). – Theodor Zoulias Sep 28 '20 at 10:19

1 Answers1

0

Just make a semaphore and wait.

private readonly SemaphoreSlim _gate = new SemaphoreSlim(1);

private async void PollSite(string filePath, string siteURL)
{
    response = await http.GetByteArrayAsync(siteURL);
    source = WebUtility.HtmlDecode(Encoding
        .GetEncoding("utf-8")
        .GetString(response, 0, response.Length - 1));
    result = new HtmlDocument();
    result.LoadHtml(source);

    var gNode = result.GetElementbyId("SomeTable");
    await _gate.WaitAsync();
    try
    {
        using (var sw = File.AppendText(filePath))
        {
            foreach (var n in gNode.Descendants("td"))
            {
                 sw.WriteLine(n.InnerText);
            }
        }
    }
    finally
    {
        _gate.Release();
    }
}
eocron
  • 6,885
  • 1
  • 21
  • 50