문제

We wrote a ClickOnce application that runs on all the PCs at the office here. Today the .NET runtime crashed and logged the following event in the Event Log:

Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.UnauthorizedAccessException
Stack:
    at System.IO.Directory.DeleteHelper(System.String, System.String, Boolean)
    at System.IO.Directory.Delete(System.String, System.String, Boolean)
    at System.IO.Directory.Delete(System.String, Boolean)
    at System.Deployment.Application.TempFile.DisposeUnmanagedResources()
    at System.Deployment.Application.DisposableBase.Finalize()

The application does use System.Deployment to check for new version periodically and download them in the background. That way the new version is ready to go when they launch the application next time.

My BackgroundUpdater class looks like this (in case it's related):

class BackgroundUpdaterService : IBackgroundUpdaterService
{
    private readonly BackgroundWorker backgroundWorker = new BackgroundWorker();
    private readonly DispatcherTimer checkForUpdatesTimer = new DispatcherTimer();

    public BackgroundUpdaterService()
    {
        this.backgroundWorker.WorkerSupportsCancellation = true;
        this.backgroundWorker.DoWork += (s, e) =>
            {
                // Check if the application was deployed via ClickOnce.
                if (!ApplicationDeployment.IsNetworkDeployed)
                {
                    e.Result = UpdateStatus.NotDeployedViaClickOnce;
                    return;
                }

                if (this.backgroundWorker.CancellationPending) return;

                var updateCheck = ApplicationDeployment.CurrentDeployment;

                UpdateCheckInfo info;
                try
                {
                    info = updateCheck.CheckForDetailedUpdate();
                }
                catch (DeploymentDownloadException)
                {
                    e.Result = UpdateStatus.DeploymentDownloadException;
                    return;
                }
                catch (InvalidDeploymentException)
                {
                    e.Result = UpdateStatus.InvalidDeploymentException;
                    return;
                }
                catch (InvalidOperationException)
                {
                    e.Result = UpdateStatus.InvalidOperationException;
                    return;
                }

                if (this.backgroundWorker.CancellationPending) return;

                if (info.UpdateAvailable)
                {
                    e.Result = info.IsUpdateRequired 
                        ? UpdateStatus.UpdateRequired 
                        : UpdateStatus.UpdateAvailable;
                }
                else
                {
                    e.Result = UpdateStatus.NoUpdateAvailable;
                }
            };
        this.backgroundWorker.RunWorkerCompleted += (s, e) =>
            {
                var result = (UpdateStatus) (e.Result);
                this.UpdateRequired =
                    result == UpdateStatus.UpdateAvailable
                    || result == UpdateStatus.UpdateRequired;
                if(!this.UpdateRequired) // stop looking if there is one
                {
                    this.checkForUpdatesTimer.Start();
                }
            };

        this.checkForUpdatesTimer.Interval = new TimeSpan(hours: 0, minutes: 15, seconds: 0);
        this.checkForUpdatesTimer.Tick += (s, e) =>
            {
                this.checkForUpdatesTimer.Stop();
                this.backgroundWorker.RunWorkerAsync();
            };
        this.checkForUpdatesTimer.Start();
    }

    private readonly object updateRequiredLock = new object();
    private bool updateRequired;
    public bool UpdateRequired
    {
        get
        {
            lock(this.updateRequiredLock)
            {
                return this.updateRequired;
            }
        }
        private set
        {
            lock(this.updateRequiredLock)
            {
                this.updateRequired = value;
            }
        }
    }

    public bool Update()
    {
        if(!this.UpdateRequired)
        {
            return false;
        }
        bool result;
        try
        {
            var updateCheck = ApplicationDeployment.CurrentDeployment;
            updateCheck.Update();
            result = true;
        }
        catch (DeploymentDownloadException)
        {
            result = false;
        }
        return result;
    }

    public void Dispose()
    {
        this.checkForUpdatesTimer.Stop();
        this.backgroundWorker.CancelAsync();
        Thread.Sleep(100);
        this.backgroundWorker.Dispose();
    }
}

Anyone else run into this exception from the System.Deployment namespace? What could be the root cause of this?

도움이 되었습니까?

해결책

yes we did run into this issue :) see my answer here: https://stackoverflow.com/a/13711535/1246870 - in 2 words, it's a bug in ClickOnce related to frequent checks for updates.

the only workaround i was able to come up with was to increase timer interval to a larger value. If you have any better ideas i would love to hear them.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top