Server Caching

Server Caching

This concern allows to cache responses generated by a handler and to serve them from the cache when they are requested again. The following example will cache all responses generated by a website:

var website = Website.Create()
                     .Content(...)
                     .Add(ServerCache.Memory());

Host.Create()
    .Handler(website)
    .Console()
    .Defaults()
    .Run();

When to Cache

Caching usually introduces some overhead that might affect the performance of your web application in a negative manner. A cache will boost the performance of your application if the provided content does rarely change and the generation of the content is expensive.

Using a file system cache to cache a static website or to cache pages that will change on every request will slow down your application instead.

Backends

The server cache can utilize any backend provided by the cache infrastructure.

// uses RAM to cache generated responses
// trades memory utilization for fast performance
var cache = ServerCache.Memory();

// stores generated responses in a temporary directory
// uses memory to store the index meta data
// low RAM comsumption but way slower than memory
var cache = ServerCache.TemporaryFiles();

// stores generated responses in the given directory
// can be used to persist the cache across server restarts
var cache = ServerCache.Persistent("./cache");

Filtering

If you would like to cache only selected responses, you can pass a predicate to select them:

ServerCache.Memory()
           .Predicate((req, resp) => resp.ContentType?.KnownType == ContentType.TextHtml);

Invalidation

By default, the concern will always execute the inner handler to determine, whether the content served by the handler has changed and the cache needs to be updated. If the content generated by your handler is garantueed not to change, you can disable this invalidation to further improve the performance.

ServerCache.Memory()
           .Invalidate(false);

Variations

The server cache allows different versions of generated responses to be cached by evaluating the Vary header. For example, if your handler may both return responses compressed with gzip and br, the cache will retain a copy of both versions and evaluate the client headers to server the requested version.

If you would like to cache different versions for every user agent, just set the Vary header accordingly:

request.Respond()
       .Header("Vary", "User-Agent");

For more information, see this blog entry.

Expiration Handling

By default, the file system cache will keep discarded entries available for another 30 minutes to allow clients to finish their downloads. If you need to customize this value, you may create a custom instance with a pre-configured cache instead:

var meta = Cache.Memory<CachedResponse>();

var data = Cache.TemporaryFiles<Stream>()
                .AccessExpiration(TimeSpan.FromHours(4));

var cache = ServerCache.Create(meta, data);

Pre-compress Content

Typically, the compression concern is added to dynamically compress the content which is generated by your web application. If the content of your application is rather static, you can use the server cache to compress the content once with a higher compression level. This will result in slightly reduced traffic and greatly reduced CPU usage when serving requests:

var compression = CompressedContent.Default()
                                   .Level(CompressionLevel.Optimal);

var cache = ServerCache.TemporaryFiles()
                       .Invalidate(false);

var website = StaticWebsite.From(ResourceTree.FromDirectory("/var/www/"))
                           .Add(compression)
                           .Add(cache);

Host.Create()
    .Handler(website)
    .Console()
    .Defaults()
    .Run();