Search code examples
c#nancyspark-view-engine

Prevent view caching in Nancy when using the Spark template engine


I'm using a self-hosted Nancy with Spark templates. I've disabled the cache specifically (though in DEBUG is should be disabled by default).

    protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, IPipelines pipelines)
    {
        base.ApplicationStartup(container, pipelines);

        ...

        StaticConfiguration.Caching.EnableRuntimeViewDiscovery = true;
        StaticConfiguration.Caching.EnableRuntimeViewUpdates = true;
    }

However, making changes to the templates while the app is running doesn't seem to work, as the template changes are not picked up.

Is there anything else required to disable views caching?


Solution

  • Ok, managed to get this to work by adding a custom ViewCache in the bootstrapper:

    public class MyBootstrapper : DefaultNancyBootstrapper
    {
    #if DEBUG
        protected override IRootPathProvider RootPathProvider
        {
            get
            {
                // this sets the root folder to the VS project directory
                // so that any template updates in VS will be picked up
                return new MyPathProvider();
            }
        }
    
        protected override NancyInternalConfiguration InternalConfiguration
        {
            get
            {
                return NancyInternalConfiguration.WithOverrides(
                    x =>
                        { x.ViewCache = typeof(MyViewCache); });
            }
        }
    #endif
    

    The new ViewCache just reloads the template on every request:

    public class MyViewCache : IViewCache
    {
    ...
        public TCompiledView GetOrAdd<TCompiledView>(
            ViewLocationResult viewLocationResult, Func<ViewLocationResult, TCompiledView> valueFactory)
        {
            //if (viewLocationResult.IsStale())
            //    {
                    object old;
                    this.cache.TryRemove(viewLocationResult, out old);
            //    }
    
            return (TCompiledView)this.cache.GetOrAdd(viewLocationResult, x => valueFactory(x));
        }
    }
    

    Somehow the viewLocationResult.IsStale() was always returning false.

    By default, this is an instance of FileSystemViewLocationResult which just compares the last update time of the view, but the timestamp this.lastUpdated was being updated before calling IsStale() from the DefaultViewCache, so the template was never removed from the cache

    public override bool IsStale()
    {
        return this.lastUpdated != this.fileSystem.GetLastModified(this.fileName);
    }