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.
Entity Framework Extensions is a major sponsor and is proud to contribute to the development this project.
- SQL Server Docs when using SQL Server SqlClient
- PostgreSQL Docs when using PostgreSQL Npgsql
- EF with SQL Server Docs when using the SQL Server EF Database Provider
- EF with PostgreSQL Docs when using the PostgreSQL EF Database Provider
Frequency of updates to data is relatively low compared to reads
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
Implementation is specific to the target database
The ETag is calculated from a combination several parts
{AssemblyWriteTime}-{DbTimeStamp}-{Suffix}
The last write time of the web entry point assembly
var webAssemblyLocation = Assembly.GetEntryAssembly()!.Location;
AssemblyWriteTime = File.GetLastWriteTime(webAssemblyLocation).Ticks.ToString();
Timestamp calculation is specific to the target database
An optional string suffix that is dynamically calculated at runtime based on the current HttpContext
.
var app = builder.Build();
app.UseDelta(suffix: httpContext => "MySuffix");
internal static string BuildEtag(string timeStamp, string? suffix)
{
if (suffix == null)
{
return $"\"{AssemblyWriteTime}-{timeStamp}\"";
}
return $"\"{AssemblyWriteTime}-{timeStamp}-{suffix}\"";
}
Delta has two approaches to usage:
Delivers functionality using DbConnection and DbTransaction.
NuGet: Delta
Documentation is specific to choice of database:
- SQL Server Docs when using SQL Server SqlClient
- PostgreSQL Docs when using PostgreSQL Npgsql
Delivers functionality using Entity Framework.
NuGet: Delta.EF
Documentation is specific to choice of database:
- EF with SQL Server Docs when using the SQL Server EF Database Provider
- EF with PostgreSQL Docs when using the PostgreSQL EF Database Provider
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;
Response diagnostics headers are prefixed with Delta-
.
Example Response header when the Request has not If-None-Match
header.
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:
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.
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.
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.
Estuary designed by Daan from The Noun Project.