Skip to content

An approach to implementing a 304 Not Modified leveraging DB change tracking

License

Notifications You must be signed in to change notification settings

SimonCropp/Delta

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Delta

Build status NuGet Status NuGet Status NuGet Status

Delta is an approach to implementing a 304 Not Modified leveraging DB change tracking.

The approach uses a last updated timestamp from the database to generate an ETag. All dynamic requests then have that ETag checked/applied.

This approach works well when the frequency of updates is relatively low. In this scenario, the majority of requests will leverage the result in a 304 Not Modified being returned and the browser loading the content its cache.

Effectively consumers will always receive the most current data, while the load on the server is reduced.

See Milestones for release notes.

Sponsors

Entity Framework Extensions

Entity Framework Extensions is a major sponsor and is proud to contribute to the development this project.

Entity Framework Extensions

JetBrains

JetBrains logo.

Jump to specific docs

Assumptions

Frequency of updates to data is relatively low compared to reads

304 Not Modified Flow

graph TD
    Request
    CalculateEtag[Calculate current ETag<br/>based on timestamp<br/>from web assembly and SQL]
    IfNoneMatch{Has<br/>If-None-Match<br/>header?}
    EtagMatch{Current<br/>Etag matches<br/>If-None-Match?}
    AddETag[Add current ETag<br/>to Response headers]
    304[Respond with<br/>304 Not-Modified]
    Request --> CalculateEtag
    CalculateEtag --> IfNoneMatch
    IfNoneMatch -->|Yes| EtagMatch
    IfNoneMatch -->|No| AddETag
    EtagMatch -->|No| AddETag
    EtagMatch -->|Yes| 304
Loading

DB implementation

Implementation is specific to the target database

ETag calculation logic

The ETag is calculated from a combination several parts

{AssemblyWriteTime}-{DbTimeStamp}-{Suffix}

AssemblyWriteTime

The last write time of the web entry point assembly

var webAssemblyLocation = Assembly.GetEntryAssembly()!.Location;
AssemblyWriteTime = File.GetLastWriteTime(webAssemblyLocation).Ticks.ToString();

snippet source | anchor

DB timestamp

Timestamp calculation is specific to the target database

Suffix

An optional string suffix that is dynamically calculated at runtime based on the current HttpContext.

var app = builder.Build();
app.UseDelta(suffix: httpContext => "MySuffix");

snippet source | anchor

Combining the above

internal static string BuildEtag(string timeStamp, string? suffix)
{
    if (suffix == null)
    {
        return $"\"{AssemblyWriteTime}-{timeStamp}\"";
    }

    return $"\"{AssemblyWriteTime}-{timeStamp}-{suffix}\"";
}

snippet source | anchor

Usage

Delta has two approaches to usage:

Raw DbConnection approach

Delivers functionality using DbConnection and DbTransaction.

NuGet: Delta

Documentation is specific to choice of database:

Entity Framework approach

Delivers functionality using Entity Framework.

NuGet: Delta.EF

Documentation is specific to choice of database:

UseResponseDiagnostics

Response diagnostics is an opt-out feature that includes extra log information in the response headers.

Disable by setting UseResponseDiagnostics to false at startup:

DeltaExtensions.UseResponseDiagnostics = false;

snippet source | anchor

Response diagnostics headers are prefixed with Delta-.

Example Response header when the Request has not If-None-Match header.

Verifying behavior

The behavior of Delta can be verified as follows:

  • Open a page in the site
  • Open the browser developer tools
  • Change to the Network tab
  • Refresh the page.

Cached responses will show as 304 in the Status:

In the headers if-none-match will show in the request and etag will show in the response:

Ensure cache is not disabled

If disable cache is checked, the browser will not send the if-none-match header. This will effectively cause a cache miss server side, and the full server pipeline will execute.

Certificates and Chromium

Chromium, and hence the Chrome and Edge browsers, are very sensitive to certificate problems when determining if an item should be cached. Specifically, if a request is done dynamically (type: xhr) and the server is using a self-signed certificate, then the browser will not send the if-none-match header. Reference. If self-signed certificates are required during development in lower environment, then use FireFox to test the caching behavior.

Programmatic client usage

Delta is primarily designed to support web browsers as a client. All web browsers have the necessary 304 and caching functionally required.

In the scenario where web apis (that support using 304) are being consumed using .net as a client, consider using one of the below extensions to cache responses.

Icon

Estuary designed by Daan from The Noun Project.

About

An approach to implementing a 304 Not Modified leveraging DB change tracking

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Contributors 6