We have moved to GitHub Issues
Created by Peter Gregory 01 Sep 2015, 01:57:51 Updated by Stephan 15 Sep 2015, 08:02:46
Created template in back office. Then overwrote template on disk. New template not picked up in back office. old template still displayed. Coming from DB rather than from disk?
Only seems to happen to templates that have a master set.
If you update and save any of the templates all templates update.
Cannot repro for a standalone MVC view, nor a standalone WebForms master. Could repro for a with-a-master WebForms master. Not sure about with-a-master MVC view. So, confirming that something's wrong, and looking into it.
Edit: can repro for any type of template. Edit in Settings, save something, then edit the file on disk, then go back to Settings and the edits are not visible. Probable cause is the in-memory caching of templates, that fails to detect that the actual disk file has changed.
Templates (as well as scripts, partial views and stylesheets) are IFile entities, which are memory-cached in their corresponding repositories. Which means that once the entity has been loaded once, it will not change until the cache is cleared, which does not happen if the disk file only is modified.
This is similar to what happens when some content is changed by editing it directly in the database. So, one answer could be that the behaviour is expected and normal. And to make sure there is a way to notify Umbraco that some files have changed, so that the cache can be cleared. However, files are different from database, as it is quite usual to edit files using a tool other than Umbraco's backend.
Therefore, we must make sure that we do not cache the content of templates, scripts, etc. in the runtime cache. This, in addition, makes sense as it is of no use to have all the texts of all templates, scripts, etc. in-memory where they would be essentially never used.
When an entity is stored into the runtime cache, it is deep-cloned. And when it is retrieved from that cache, it is deep-cloned too. We make sure that content is not cloned. Therefore, the cached entity has no content, and retrieved entities have no content. Getting the content of an entity triggers a lazy loading of that content from disk.
Loading the content from the entity, means that the entity needs to have access to the IFileService (or, at least, to its repository, or the underlying filesystems). However, it is valid to write code such as the following, and we do not want to obsolete it:
var script = new Script("script.js");
That created entity has no way of reaching the service/repository/filesystem. Therefore, it all works that way:
This applies to anything that is a File, ie a Stylesheet, Script, PartialView or Template.
When the file content is loaded, we should ''in theory'' also refresh the UpdateDate of the entity. However, there is no way we can do it properly without conflicting with the dirty properties tracking mechanism. So, that date is never going to change.
Warning: the code also refactors and clears the PhysicalFileSystem, addressing some security issues. Which means we are much more strict wrt the filesystem. All tests are passing, though.
We have a way to disable dirty property tracking and re-enabling it... not sure if that would allow us to make this work or not ? (we do this in the deep cloning logic of an entity)
Damn, I ''know'' and yet I overlooked that one. Assuming I already have (or maybe not) some dirty properties... does it "just" suspend the tracking, eg would the following code transparently update the date without tracking?
file.DisableChangeTracking(); file.UpdateDate = DateTime.Now; file.EnableChangeTracking();
IIRC :) might be worth adding an assert to a test or something
Pushed 6b5057b8708eb82f2af278225e3e0075dbb7f2b4 doing more fixes. The update date trick above is still commented out as I'd need to test that it works - will remain TODO for the time being.
Closing in its current state for 7.3.
Backwards Compatible: True
Affected versions: 7.3.0
Due in version: 7.3.0