Fishcake
Fishcake

Reputation: 10754

Unable to delete assembly (.exe)

I've written a small app to get version numbers of files contained within a .cab file.

I extract all files from the cab to a temp directory and loop through all the files and retrieve version numbers as follows:

//Attempt to load .net assembly to retrieve information
Assembly assembly = Assembly.LoadFile(tempDir + @"\" + renameTo);
Version version = assembly.GetName().Version;
DataRow dr = dt.NewRow();
dr["Product"] = renameTo;
dr["Version"] = version.ToString();
dt.Rows.Add(dr); 

Then when finished I want to delete all the files that have been extracted as follows:

        foreach (string filePath in filePaths)
        {
            //Remove read-only attribute if set
            FileAttributes attributes = File.GetAttributes(filePath);

            if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
            {
                File.SetAttributes(filePath, attributes ^ FileAttributes.ReadOnly);
            }

            File.Delete(filePath);
        }

This works for all files except except sometimes fails on .net .exe's. I can manually delete the file so it does not appear to be locked.

What should I be looking for to make this work? Is Assembly.LoadFile perhaps locking the file?

Upvotes: 4

Views: 889

Answers (3)

Mike Zboray
Mike Zboray

Reputation: 40818

AssemblyName.GetAssemblyName will get the AssemblyName object without locking the file on you. see msdn. You can get the version from there.

Upvotes: 2

Alexei Levenkov
Alexei Levenkov

Reputation: 100527

Another approach (in addition to using Load from file in separate AppDomain) is to load assembly from a MemoryStream copy of file using Assembly.Load from bytes into main AppDomain.

Note that for code to be completely correct you still may need separate AppDomains for each assembly if there are assemblies with the same identity in one file (i.e. 2 not-strongly-signed assemblies with same file name).

Even with separate AppDomains it would be safer to load from bytes with LoadReflectionOnlyFrom for your scenario since in this case there is no chance that failure to unload AppDomain will keep file locked and you have full control over locking of the file yourself. For regular loading of assemblies using load from bytes requires significant reading to understand associated problems and better be avoided.

Upvotes: 1

Chris Shain
Chris Shain

Reputation: 51329

Assembly.LoadFile does indeed lock the file. If you need to load assemblies from files and then subsequently delete the files, what you need to do is:

  1. Start a new AppDomain
  2. Load the assembly in that appdomain
  3. Only work with it there- do not use any types from the assembly in your main appdomain.
  4. Call AppDomain.Unload to tear down the AppDomain
  5. Then delete the file

You cannot delete a file containing an assembly while that assembly is loaded into an executing AppDomain.

Upvotes: 6

Related Questions