You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have run into a similar issue when updating from 3.2.
I was using Razor.Parse() which seems to check if its compiled and if not compile or update it.
I wish to do that without calling Razor.Parse().
My reasoning is that my templates can be changed will the application is running from within the application so when a user updates the cshtml i need to reload it upon next request with the changes.
How is this possible in the current version? Btw awesome code. :)
It is. What you want to do is provide your own ICachingProvider implementation. You can take the one from the RazorEngine codebase and edit it to your needs. You can now even recompile a template file when it was changed and silently replace it, so the next Run or RunCompile call will use it (without impacting the application performance while compiling).
If you manage to write a generic caching approach which others might find useful, I'd love to see that integrated in RazorEngine.
Hope this helps, if you have any problems with this approach feel free to ask.
Here is my solution for anyone wanting to update specific templates on the fly.
I created my own itemplate manager which almost a straight copy from delegate.
I changed the following code
/// <param name="source">the source-code of the template</param>publicvoidAddDynamic(ITemplateKeykey,ITemplateSourcesource){_dynamicTemplates.AddOrUpdate(key,source,(k,oldSource)=>{// This code is from the original template manager implementation.//if (oldSource.Template != source.Template)//{//source.Template //throw new InvalidOperationException("The same key was already used for another template!");//}returnsource;});}
And in the cases where i need to update i know to call compile in the code. Otherwise i call run. All is well. :)
Just for reference: Yes this works, but the reason the commented code is there is because without it you get weird behavior in the RunCompile and Run methods calls! For example when you call RunCompile with a new template source-code it implicitly calls AddDynamic and then uses the (outdated) cache. We throw a exception so you can catch such (subtle) situations.
I would not recommend depending on this specific behavior. It is possible that future versions throw on Compile when there is already a cached item present (which your solution depends on).
Instead I would encourage you to add an event to your ITemplateManager implementation and let a custom ICachingManager implementation depend on this event and invalidate the cache.
The current ITemplateManager and ICachingManager implementations are really not completely bullet proof (and thought-through) when it comes to cache invalidation and changing templates. So it is always the best in such situations to implement your own versions (as requirements are so different). However patches with more general implementations are welcome :) .
I agree its not the best i just needed a quick fix. I dont need to invalidate the entire cache just the template in question. Its interesting to me so i might take a look at implementing a solution more along the lines you suggest.
I believe there is still an issue around this. The following code throws the exception above. (I realize this causes a slow memory leak)
var cacheProvidxer=new InvalidatingCachingProvider();
var config = new TemplateServiceConfiguration();
config.CachingProvider = cacheProvidxer;
var service = RazorEngineService.Create(config);
Engine.Razor = service;
Engine.Razor.RunCompile("Some Text", "SomeKey", null, new { IsAuthenticated = true });
cacheProvidxer.InvalidateAll();
Engine.Razor.RunCompile("Some Different Text", "SomeKey", null, new { IsAuthenticated = true });
Is there something wrong with the above code? (Uses version 3.7.0)
The problem is that you only invalidate the Compile Cache and not the Template Manager.
The following would work and compile the template twice (note that this leaks as you already noted):
var cacheProvidxer=new InvalidatingCachingProvider();
var config = new TemplateServiceConfiguration();
config.CachingProvider = cacheProvidxer;
var service = RazorEngineService.Create(config);
Engine.Razor = service;
Engine.Razor.RunCompile("Some Text", "SomeKey", null, new { IsAuthenticated = true });
cacheProvidxer.InvalidateAll();
Engine.Razor.RunCompile("SomeKey", null, new { IsAuthenticated = true });
To get what you want you either need to use the DelegateTemplateManager (which has a RemoveDynamic method you need to call additionally to InvalidateAll). Or write your own CachingProvider-Wrapper and TemplateManager to directly connect them (so when InvalidateAll is called your Manager is cleared as well).
This whole caching and template manager stuff seems to be overly complex. Was hoping to simply read some values from a database and compile them..when they change..clear the cache. But it seems you have to write a template manager and a caching provider, etc. Most examples are around a 'file system'..do people use a file system a lot when using this product?
I will try this DelagateTemplateManager....but seems such overkill. I guess it is all around you trying to 'resolve references' to other templates inside the RunCompile method.
Sorry but AFAIK there is no way to make a simple API that "just works" (at least I cannot see it). It always boils down to carefully look at your performance/environment requirements and build a solution/workaround you can live with. Once you are at this point you can see why the complexity is necessary to get the perfect implementation you are searching for.
I would love to be proven wrong, just fix everything and send a pull request :). One thing to keep in mind is that we should provide a API that fails as fast as possible and not allow users to do things that will fail once the memory runs out...
Most examples are around a 'file system'..do people use a file system a lot when using this product?
I don't know. I do and it makes sense to save templates in files to have a hierarchical structure...
Activity
matthid commentedon Feb 2, 2015
It looks like you used the same template key (/name) for multiple different templates, this is not supported.
Use:
Or even better implement your own
name -> template
resolving strategy by implementingITemplateManager
. Then you can use the templates by name:Spaceman1861 commentedon Feb 3, 2015
Hi,
I have run into a similar issue when updating from 3.2.
I was using Razor.Parse() which seems to check if its compiled and if not compile or update it.
I wish to do that without calling Razor.Parse().
My reasoning is that my templates can be changed will the application is running from within the application so when a user updates the cshtml i need to reload it upon next request with the changes.
How is this possible in the current version? Btw awesome code. :)
matthid commentedon Feb 3, 2015
It is. What you want to do is provide your own ICachingProvider implementation. You can take the one from the RazorEngine codebase and edit it to your needs. You can now even recompile a template file when it was changed and silently replace it, so the next Run or RunCompile call will use it (without impacting the application performance while compiling).
If you manage to write a generic caching approach which others might find useful, I'd love to see that integrated in RazorEngine.
Hope this helps, if you have any problems with this approach feel free to ask.
Spaceman1861 commentedon Feb 5, 2015
Hey,
Here is my solution for anyone wanting to update specific templates on the fly.
I created my own itemplate manager which almost a straight copy from delegate.
I changed the following code
And in the cases where i need to update i know to call compile in the code. Otherwise i call run. All is well. :)
Hope this helps someone.
matthid commentedon Feb 5, 2015
Just for reference: Yes this works, but the reason the commented code is there is because without it you get weird behavior in the
RunCompile
andRun
methods calls! For example when you callRunCompile
with a new template source-code it implicitly callsAddDynamic
and then uses the (outdated) cache. We throw a exception so you can catch such (subtle) situations.I would not recommend depending on this specific behavior. It is possible that future versions throw on
Compile
when there is already a cached item present (which your solution depends on).Instead I would encourage you to add an event to your ITemplateManager implementation and let a custom ICachingManager implementation depend on this event and invalidate the cache.
The current
ITemplateManager
andICachingManager
implementations are really not completely bullet proof (and thought-through) when it comes to cache invalidation and changing templates. So it is always the best in such situations to implement your own versions (as requirements are so different). However patches with more general implementations are welcome :) .Spaceman1861 commentedon Feb 5, 2015
I agree its not the best i just needed a quick fix. I dont need to invalidate the entire cache just the template in question. Its interesting to me so i might take a look at implementing a solution more along the lines you suggest.
waynebrantley commentedon Jul 4, 2015
I believe there is still an issue around this. The following code throws the exception above. (I realize this causes a slow memory leak)
Is there something wrong with the above code? (Uses version 3.7.0)
matthid commentedon Jul 4, 2015
The problem is that you only invalidate the Compile Cache and not the Template Manager.
The following would work and compile the template twice (note that this leaks as you already noted):
To get what you want you either need to use the
DelegateTemplateManager
(which has aRemoveDynamic
method you need to call additionally toInvalidateAll
). Or write your ownCachingProvider
-Wrapper andTemplateManager
to directly connect them (so when InvalidateAll is called your Manager is cleared as well).waynebrantley commentedon Jul 4, 2015
This whole caching and template manager stuff seems to be overly complex. Was hoping to simply read some values from a database and compile them..when they change..clear the cache. But it seems you have to write a template manager and a caching provider, etc. Most examples are around a 'file system'..do people use a file system a lot when using this product?
I will try this DelagateTemplateManager....but seems such overkill. I guess it is all around you trying to 'resolve references' to other templates inside the RunCompile method.
matthid commentedon Jul 4, 2015
Most of the Complexity is a direct result of several CLR limitations we run into all the time:
Sorry but AFAIK there is no way to make a simple API that "just works" (at least I cannot see it). It always boils down to carefully look at your performance/environment requirements and build a solution/workaround you can live with. Once you are at this point you can see why the complexity is necessary to get the perfect implementation you are searching for.
I would love to be proven wrong, just fix everything and send a pull request :). One thing to keep in mind is that we should provide a API that fails as fast as possible and not allow users to do things that will fail once the memory runs out...
I don't know. I do and it makes sense to save templates in files to have a hierarchical structure...
13 remaining items