A file is still locked in the CachePath after Disposed

SyntaxEditor for Windows Forms Forum

Posted 11 years ago by Dude76 - Athic
Version: 13.1.0310
Platform: .NET 4.5
Environment: Windows 8 (64-bit)
Avatar

Hi.

On the close of our application, we want to clean the cache folder.

All files in CacheFolder are correctly deleted except one, always the same : mscorlib.210f58f6.Documentation.dat, "used by an other process".

Once the application is closed, the file can be manualy deleted.

We can open multiple instances of SyntaxEditor/DotNetProjectResolver at the same time, each of them in a new form hosted in a tab.

Each of the DotNetProjectResolver is PruneCache/Disposed, in the FormClosed event/method.

I tried differents things, with no result:

  • suppress the AddExternalReferenceForMSCorLib()
  • make a loop through every ExternalReferences to remove these
  • set CacheFolder to string.Empty

version : 4.0.290.0 (2012/03 - last of 2012).

Anything more to test ?

Any suggestion ?

 

Thx.

[Modified 11 years ago]

I am. I was not then I came to be. I cannot remember NOT being.

Comments (8)

Answer - Posted 11 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

I wouldn't recommend doing things that way.  You should probably change your code to only call the PruneCache method when the last of your forms is closed and your application is shutting down.


Actipro Software Support

Posted 11 years ago by Dude76 - Athic
Avatar

Hi; Thanks for the answer.

I just tested that (comment PruneCache in Forms, add a dotNetProjectResolver at the main closing, set its CacheFolder, call the PruneCache()), and that didn't make a difference.

I explained that there could be multiple instances of the SyntaxEditor/DotNetProjectResolver at the same time, but during all my tests, I only opened 1 of them and got the problem:

  • run the application, load a custom project (which containing C# codes)
  • open a form to create the cache
  • close the form ( - PruneCache :) )
  • close the app:
  • __ + new DotNetProjectResolver, set the CacheFolder, call PruneCache
  • __ Deletion of files in the Cache Folder, throw IOException file lock by other proccess on mscorlib.210f58f6.Documentation.dat (and only on it)

So i tried to declare/use only one DotNetProjectResolver in the whole application (in order to have this only one reference dispose/prunecache and delete the folder at this unique point), passing it to forms through a static class.

Like it, the cache is filled as soon as a project is load, i don't need to open a form any more to reproduce my problem:

  • run the application
  • load a custom project (which containing C# codes)
  • -> new DotNetProjectResolver, set the CacheFolder
  • close the app :
  • --> call Dispose / PruneCache,
  • --> Deletion of files in the Cache Folder, throw IOException file lock by other proccess on mscorlib.210f58f6.Documentation.dat (and only on it)

I finally did 2 things:

  • add a CodeEditor.Document.LangageData = null when closing a form (to be sure to unreference the DotNetProjectResolver from this instance)
  • comment the AddExternalReferenceForMSCorLib()

and ... IT WORKS !??!

When i un-comment the AddExternalReferenceForMSCorLib(), I have the problem again.

I reproduce the problem in the provided sample (the TestApplication - MainForm) :

  • adding a AddExternalReferenceForMSCorLib() before the AddAllAssembliesInAppDomainAsExternalReferences()
  • add a Directory.Delete(cachefolder, true) right after the PruneCache()
  • get the same IOException on the same file :)

I suppose that when i added this, i had a good reason, but i really don't remember why i added it (2009... it dates).

So, for the moment, i have commented the AddExternalReferenceForMSCorLib() and will cross my fingers in the wait for feedbacks for any dysfunctionning...

Enjoy !

[Modified 11 years ago]

I am. I was not then I came to be. I cannot remember NOT being.

Posted 11 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hello, ok I think I understand a little better now your scenario.  You are calling PrineCache and then trying to delete all files in the cache as well.

The point of the PruneCache call is to only delete cache files that are out of date.  It will keep the others in place, which is important since the next time the app loads, it will load much quicker since those remaining good cache files will remain.

Overall I would suggest that you remove your attempt to do the Directory.Delete and just do PruneCache alone.  Is that a problem?  It will give you your best app performance.


Actipro Software Support

Posted 11 years ago by Dude76 - Athic
Avatar

Good night :) (2:30 am here ^^ )

Well, yes, it's ok, i knew the role of the cache and PruneCache :)

And meeting this problem have lead me to reevaluate/upgrade some part of our design (no upgrade of the design since 2009's first integration)

If 2 instances of the application are running concurrency, what about having the same cache emplacement for both (for differents projects) ?

So we associated a specific cache folder when loading a project (a subdir with the name of the project).

But we can't let multiply these folders, so we need some cleaning rules; Basicaly, for now/1st step, the cache is deleted on project switching / application closing; I will put a better rule soon ("no delete as long as the project is in the "recent projects" list").

Nevertheless, the (minor) bug "file mscorlib.210f58f6.Documentation.dat is locked when used AddExternalReferenceForMSCorLib()" seems to be confirmed.

ok, time to sleep :)

I am. I was not then I came to be. I cannot remember NOT being.

Posted 11 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

If you could make a new simple sample project that shows it and email that over to our support address, then we can take a look and see what's happening.  Please reference this post and rename the .zip file extension so it doesn't get spam blocked.  Thanks!


Actipro Software Support

Posted 11 years ago by Dude76 - Athic
Avatar

Hi.

I sent the solution in a 7z file renamed as .doc.

Here is the amazing unbelievable code in the only one function :) :

using System.IO;
using System.Reflection;
using System.Windows.Forms;
using ActiproSoftware.SyntaxEditor;
using ActiproSoftware.SyntaxEditor.Addons.DotNet.Dom;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // Start the parser service (only call this once at the start of your application)
            SemanticParserService.Start();

            DotNetProjectResolver dotNetProjectResolver = new DotNetProjectResolver();
            dotNetProjectResolver.CachePath = Assembly.GetExecutingAssembly().Location + @"Cache\";
            // if AddExternalReferenceForMSCorLib() is commented, the further Directory.Delete() will not throw an IOException
            dotNetProjectResolver.AddExternalReferenceForMSCorLib();
            dotNetProjectResolver.AddAllAssembliesInAppDomainAsExternalReferences();

            SemanticParserService.Stop();

            // Dispose the project resolver... this releases all its resources
            dotNetProjectResolver.Dispose();

            // Prune the cache to remove files that no longer apply... note that you should only do this if you are closing your application down
            //   and are sure no other project resolvers are still using the cache... in the case of this sample project, 
            //   each QuickStart Form is modal so we know another window is still not accessing the cache
            dotNetProjectResolver.PruneCache();

            if (components != null)
                components.Dispose();
            //throw IOException on 'mscorlib.210f58f6.Documentation.dat' (used by another process).
            //because of AddExternalReferenceForMSCorLib()
            Directory.Delete(dotNetProjectResolver.CachePath, true);
        }
    }
}

 Bests regards.

Dude76 / 01011001.

I am. I was not then I came to be. I cannot remember NOT being.

Answer - Posted 11 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hello, thanks for the sample.  The problem here is that your first call adds an mscorlib ref to the project resolver.  The AssemblyCodeRepository loads this up.  Then the AddAllAssembliesInAppDomainAsExternalReferences call tries to add another ref to mscorlib.  The AssemblyCodeRespository ends up tracking two refs to that loaded assembly info while the project resolver isn't duplicating its reference.  So when you Dispose the project resolver later on, it's removing one of the AssemblyCodeRespository refs to mscorlib but not the other.

The solution here is to not call AddExternalReferenceForMSCorLib (as you saw) or add this after the project resolver Dispose call:

AssemblyCodeRepository.Clear();

We're also updating our code for the next 2013.1 maintenance release to not add that second ref in AssemblyCodeRepository if the project resolver doesn't end up referencing the assembly (due to it being a duplicate).


Actipro Software Support

Posted 11 years ago by Dude76 - Athic
Avatar

I suspected a such issue.

I didn't noticed this possiblity, nice.

thx you :)

I am. I was not then I came to be. I cannot remember NOT being.

The latest build of this product (v24.1.0) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.