Question

I want my static content (images, javascript files, css files etc) to served in full only after the file has been updated.

If a file has not changed since it was last requested (as determined by the ETag and Last-Modified response header values) then I want the cached versions of the files to be used by the client browser.

Does Nancy support this functionality?

Was it helpful?

Solution

Nancy does partially support the ETag and the Last-Modified headers. It sets them for all static files but as of version 0.13 it does nothing with these values. here is the Nancy code:

Nancy.Responses.GenericFileResponse.cs

if (IsSafeFilePath(rootPath, fullPath))
{
    Filename = Path.GetFileName(fullPath);

    var fi = new FileInfo(fullPath);
    // TODO - set a standard caching time and/or public?
    Headers["ETag"] = fi.LastWriteTimeUtc.Ticks.ToString("x");
    Headers["Last-Modified"] = fi.LastWriteTimeUtc.ToString("R");
    Contents = GetFileContent(fullPath);
    ContentType = contentType;
    StatusCode = HttpStatusCode.OK;
    return;
}

To make use of the ETag and Last-Modified header values you need to add a couple of modified extensions methods. I borrowed these directly from the Nancy source code in GitHub (as this functionality is planned for a future release) but the original idea came from Simon Cropp - Conditional responses with NancyFX

Extension Methods

public static void CheckForIfNonMatch(this NancyContext context)
{
    var request = context.Request;
    var response = context.Response;

    string responseETag;
    if (!response.Headers.TryGetValue("ETag", out responseETag)) return;
    if (request.Headers.IfNoneMatch.Contains(responseETag))
    {
        context.Response = HttpStatusCode.NotModified;
    }
}

public static void CheckForIfModifiedSince(this NancyContext context)
{
    var request = context.Request;
    var response = context.Response;

    string responseLastModified;
    if (!response.Headers.TryGetValue("Last-Modified", out responseLastModified)) return;
    DateTime lastModified;

    if (!request.Headers.IfModifiedSince.HasValue || !DateTime.TryParseExact(responseLastModified, "R", CultureInfo.InvariantCulture, DateTimeStyles.None, out lastModified)) return;
    if (lastModified <= request.Headers.IfModifiedSince.Value)
    {
        context.Response = HttpStatusCode.NotModified;
    }
}

Finally you need to call these methods using the AfterRequest hook in your Nancy BootStrapper.

BootStrapper

public class MyBootstrapper :DefaultNancyBootstrapper
{
    protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
    {
        pipelines.AfterRequest += ctx =>
        {
            ctx.CheckForIfNoneMatch();
            ctx.CheckForIfModifiedSince();
        };
        base.ApplicationStartup(container, pipelines);
    }
    //more stuff
}

Watching the responses with Fiddler you will see the first hit to your static files downloads them with a 200 - OK Status Code.

Thereafter each request returns a 304 - Not Modified Status Code. After a file is updated, requesting it once again downloads it with a 200 - OK Status Code ... and so on.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top