ClickOnce deployment is leaving multiple versions (yes, more than two)
I've got a ClickOnce application that is leaving all old versions on my disk. It's an internal corporate application that gets frequent updates, so this is a disaster for rapidly inflating our backup size.
According to the documentation and other Stack Overflow questions, it is supposed to only leave the current and previous versions on disk. However, each time I deploy the project and upgrade a client, I get another copy of all EXE, DLL and data files. I'm not making any changes whatsoever to the application, just pushing deploy again in Visual Studio.
How do I fix this problem?
The problem seems to happen on both Windows 7 and Windows XP, as well as 64-bit and 32-bit Windows.
I've done a diff of the folders where the version is installed and the follo开发者_如何转开发wing files are different:
MyApp.exe.manifest
MyApp.exe.cdf-ms
MyDll1.cdf-ms
MyDll2.cdf-ms
No actual executable files are different, nor the MyApp.manifest
, MyDll1.manifest
, etc.
How about an alternative. Is it safe to look for other folders containing my application at runtime and delete them? Is that going to break anything?
Is ClickOnce just an apparent mysterious black box?
I think I've actually finally figured this one out. For some unknown (and unacceptable, frankly) reason, the cleanup of older versions will not happen if the newer version is running -- it just fails silently.
The cleanup attempts to run as the old version exits, but because I restarted the app, the new version is already starting, blocking the cleanup.
Also, note that the "scavenger service" mentioned in other answers appears to be a total fabrication. I've found no documentation of any such service, nor any evidence of it running. The cleanup appears to happen inline as part of the clickonce update process.
The scavenger service is part of the ClickOnce engine; it runs automatically, and isn't something you can access directly. It should be coming around and cleaning up the old versions.
Question about the min version. If you deploy new version & set min required version to new version#, does it update the app to that version? Then leaves the former one(s) on disk?
Is there any pattern that you can see? Is there a limit to the number of deployments that it is caching?
There's also something about shadow folders that is tickling the edges of my memory; the files aren't really there. I'll do a little research and look through my notes and see what I can find.
What kind of app is it? WinForms/WPF/VSTO?
When you say it is caching folders, which folder is it? For a winforms app, for example, there are two folders created for each version (xxxxtion... and xxxxexe... or something like that) plus a bunch of folders -- one for each assembly included in the deployment -- these are cached versions of the assemblies, to keep from having to download them every time if they haven't changed. Is it the xxxxtion and xxxxexe folders that you are seeing multiples of?
This is a function to clean old ClickOnce versions in the client side.
In my machine I've freed 6Gb of space. I don't want to even know the total space used by old versions org wide...
/// <summary>
/// Delete directories of old ClickOnce versions leaving newest in place.
/// NOTE: Users have privileges for installing and deleting folders in their local deployment directory.
/// </summary>
public static void CleanOldVersions()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
int lastSlash = path.LastIndexOf(@"\");
path = path.Substring(0, lastSlash );
lastSlash = path.LastIndexOf(@"\");
path = path.Substring(0, lastSlash);
var dirInfo = new DirectoryInfo(path);
var directories = dirInfo.EnumerateDirectories()
.OrderByDescending(d => d.CreationTime)
.ToList();
List<string> DeletedAppIDs = new List<string>();
foreach (DirectoryInfo subDirInfo in directories)
{
int first_ = subDirInfo.Name.IndexOf("_");
if (first_ < 0) continue;
string appID = subDirInfo.Name.Substring(first_+1, 21);
if (DeletedAppIDs.Contains(appID)) continue;
var subdirectories = subDirInfo.Parent.EnumerateDirectories()
.Where(d => d.Name.Contains(appID))
.OrderByDescending(d => d.CreationTime)
.ToList();
bool isNewest = true;
foreach (DirectoryInfo subDirName in subdirectories)
{
if (isNewest)
{
isNewest = false;
}
else
{
try
{
SetAttributesToNormal(subDirName); //Set attributes to normal to prevent failures
subDirName.Delete(true);
if (!DeletedAppIDs.Contains(appID))
{
DeletedAppIDs.Add(appID);
}
}
catch (UnauthorizedAccessException)
{
//Catch unauthorized access to prevent exit if a previous version has any open dll
}
}
}
}
}
private static void SetAttributesToNormal(DirectoryInfo dir)
{
foreach (var subDir in dir.GetDirectories())
SetAttributesToNormal(subDir);
foreach (var file in dir.GetFiles())
{
file.Attributes = FileAttributes.Normal;
}
}
It can be called at launch like this:
private async void InitTasks()
{
try
{
await Task.Run(() => CleanOldVersions());
}
catch (Exception ex)
{
//Error handling
}
}
Are you checking it immediately? They don't even go away after a day or so? The ClickOnce scavenger service is supposed to come around and remove the old versions. If you push the most recent version as a required update, does it remove the other versions? (To do this, set the minimum required version in the Updates dialog to the same version you are deploying).
How to Delete
Clear Click-Once (versioning) Cache
From the docs:
ClickOnce applications that are hosted online are restricted in the amount of space they can occupy by a quota that constrains the size of the ClickOnce cache. The cache size applies to all the user's online applications; a single partially-trusted, online application is limited to occupying half of the quota space. Installed applications are not limited by the cache size and do not count against the cache limit. For all ClickOnce applications, the cache retains only the current version and the previously installed version. By default, client computers have 250 MB of storage for online ClickOnce applications. Data files do not count toward this limit. A system administrator can enlarge or reduce this quota on a particular client computer by changing the registry key, HKEY_CURRENT_USER\Software\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\OnlineAppQuotaInKB, which is a DWORD value that expresses the cache size in kilobytes. For example, in order to reduce the cache size to 50 MB, you would change this value to 51200
精彩评论