ravibpatel/AutoUpdater.NET

update process keeps repeating

Opened this issue · 3 comments

We are encountering an incomprehensible issue where the update process keeps repeating.

On the customer's PC, we observe that updates continue to repeat.
I also noticed this issue on my own PC, and it seemed to be resolved by adding ResponseCache.
However, the issue still persists on several of the customer's PCs.

The server is running on IIS with .NET 9. The client is installed using a Windows Installer and updated via AutoUpdater.NET.
Below is part of the server-side code:

[HttpGet("{tenantName}/{MacAddress}/{AppId}/Download")]
[DontWrapResult]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None, Duration = 0)]
public async Task DownloadAsync([FromRoute] string tenantName, [FromRoute] string MacAddress, [FromRoute] string AppId)
{
    HttpContext.Response.Clear();
    HttpContext.Response.ContentType = "application/octet-stream";
    HttpContext.Response.Headers.Append("Content-Disposition", $"attachment; filename=\"{System.IO.Path.GetFileName(deploy.FilePath!)}\"");
    HttpContext.Response.Headers.Append("Content-Length", fileinfo.Length.ToString());
    HttpContext.Response.Headers.Append("Content-Transfer-Encoding", "binary");
    HttpContext.Response.Headers.Append("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
    HttpContext.Response.Headers.Append("Pragma", "no-cache");
    HttpContext.Response.Headers.Append("Expires", "0");

    await HttpContext.Response.SendFileAsync(deploy.FilePath);
}

Although I used ResponseCache to prevent caching, it didn’t solve the problem, so I added the headers manually.
I confirmed that the headers are indeed being sent.

In the AutoUpdater.cs, I also found the following code:

internal static MyWebClient GetWebClient(Uri uri, IAuthentication basicAuthentication)
{
    var webClient = new MyWebClient
    {
        CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore)
    };

    if (Proxy != null)
    {
        webClient.Proxy = Proxy;
    }

    if (uri.Scheme.Equals(Uri.UriSchemeFtp))
    {
        webClient.Credentials = FtpCredentials;
    }
    else
    {
        basicAuthentication?.Apply(ref webClient);
        webClient.Headers[HttpRequestHeader.UserAgent] = HttpUserAgent;
    }

    return webClient;
}

As you can see, caching is explicitly disabled using RequestCacheLevel.NoCacheNoStore.

Despite all this, the update still appears to be cached, and I don’t understand why.
When using ClickOnce, we never experienced this kind of issue, even though we’re using the same IIS server instance.

Could it be related to temporary files used during the download process?

I was able to obtain the two PCs where the issue occurred.
Specifically, the problem was immediately resolved by clearing the temporary cache files in Edge. (keep cookies and other)
This is giving me a headache.
It seems need to either modify the download class or add a timestamp trick.

Can you try handling the update Manually? Just change the args.DownloadURL field and add a query string with timestamp at the end to see if that fixes the issue?

In the ParseUpdateInfoEvent event handler, I was directly assigning the URL to the args.DownloadURL property:

defaultDownloadUrl = $"{serverEndpoint}Updates/{tenantName}/{macAddress}/{appTypeName}/Download?currentVersion={currentVersion}&timeStamp={timeStamp}";
            
args.UpdateInfo = new UpdateInfoEventArgs
{
    CurrentVersion = json.Version,
    ChangelogURL = json.changelog,
    DownloadURL = json.DownloadUrl ?? defaultDownloadUrl,
    Mandatory = new()
    {
        Value = json.mandatory?.Value ?? true,
        UpdateMode = json.mandatory?.UpdateMode ?? Mode.ForcedDownload,
        MinimumVersion = json.mandatory?.MinimumVersion
    },
};

After encountering an issue where updates were being repeatedly triggered, I added the query parameters ?currentVersion={currentVersion}&timeStamp={timeStamp} to the download URL.

Since the update service is currently disabled, I haven’t been able to perform complete testing. So far, I’ve only tested it on the two PCs where the issue originally occurred—but those machines had already resolved the problem by clearing temporary files. Because of this, the test results are not reliable.

When the next update is released, I plan to roll it out gradually across thousands of PCs. Our customer support team will manually trigger the update on one machine at a time and monitor the results. This means it may take several months to fully verify whether the issue has been resolved.

While searching online, I found multiple reports of similar issues with WebClient, some dating back over 14 years.
https://stackoverflow.com/questions/3812089/c-sharp-webclient-disable-cache
https://blog.sverrirs.com/2016/04/webrequest-caching-in-csharp.html

It seems that ISPs, intermediary services, or network hardware may not always handle things as expected.

I’ll post an update once I reach a more definitive conclusion.