I have a controller that returns a FileStreamResult
. Part of the processing looks to see if the 'if-modified-since' header is less that current date in the database to return either NotModified()
or the actual FileStreamResult
. The problem is, the client (in this case Swagger) doesn't even submit to my server so I can check the database date against the passed in header. I haven't set any 'caching' information in Startup
. Given the code below, any ideas how to make sure it submits back to my web api so I can do the database compare?
Here is screenshot of Chrome network tab. You can see the first one (displayed as test ) submitted to server (I had disable cache turned on), then submitted again and it was served by (disk cache) - never hitting the server.
Note, I followed these links as my template:
[ApiController]
public class DownloadSpecificVersion : ControllerBase
{
private readonly IDbConnectionFactory dbConnectionFactory;
public DownloadSpecificVersion( IDbConnectionFactory dbConnectionFactory ) => this.dbConnectionFactory = dbConnectionFactory;
public record Parameters
{
private string _folder;
[FromRoute]
public string Folder
{
get => _folder.KatAppFolder();
set => _folder = value;
}
[FromRoute]
public string Name { get; init; }
[FromRoute]
public string Version { get; init; }
}
[HttpGet( "/api/kat-apps/{folder}/{name}/version/{version}" )]
[SwaggerOperation(
Summary = "Download specific version of KatApp kaml file",
Description = "Download specific version of KatApp kaml file",
OperationId = "KatApps.DownloadSpecificVersion",
Tags = new[] { "KatApps" } )]
[ProducesResponseType( typeof( FileStreamResult ), StatusCodes.Status200OK )]
[ProducesResponseType( StatusCodes.Status304NotModified )]
[ProducesResponseType( typeof( ValidationProblemDetails ), StatusCodes.Status401Unauthorized )]
[ProducesResponseType( typeof( ValidationProblemDetails ), StatusCodes.Status404NotFound )]
public async Task<IActionResult> HandleAsync( [FromQuery] Parameters parameters )
{
using ( var cn = await dbConnectionFactory.CreateDataLockerConnectionAsync() )
{
var keyInfo = await cn.QueryBuilder( $@"omitted, query to find item in db" ).QueryFirstOrDefaultAsync<CacheDownloadInfo>();
return keyInfo != null
? await CachedOrModifiedAsync( keyInfo, dbConnectionFactory )
: NotFound();
}
}
}
protected async Task<IActionResult> CachedOrModifiedAsync( CacheDownloadInfo cacheDownloadInfo, IDbConnectionFactory dbConnectionFactory )
{
var lastModifiedDate = cacheDownloadInfo.LastModifiedDate.Value.ToUniversalTime();
// https://rehansaeed.com/asp-net-core-caching-in-practice/#last-modified--if-modified-since
// https://www.geekytidbits.com/efficient-caching-dynamic-resources-asp-net-304-not-modified/
var requestHeaders = HttpContext.Request.GetTypedHeaders();
// HTTP does not provide milliseconds, so remove it from the comparison
if ( requestHeaders.IfModifiedSince.HasValue && lastModifiedDate.AddMilliseconds( -lastModifiedDate.Millisecond ) <= requestHeaders.IfModifiedSince.Value )
{
return NotModified();
}
var responseHeaders = HttpContext.Response.GetTypedHeaders();
responseHeaders.LastModified = lastModifiedDate;
var fs = File.OpenRead( "c:\test.txt" ); // This is really code that gets a 'stream' from the database
return new FileStreamResult( fs, "text/plain" );
}
My issue was I was testing this in browser console with simple $.ajax()
call. I needed to set the ifModified: true
in the configuration for it call the server with the if-modified-since
header.
I discovered another issue when using Swagger. It only seemed to work if I set the following:
responseHeaders.CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue
{
Public = true,
MustRevalidate = true,
MaxAge = new TimeSpan( 0, 0, 0 ),
};
responseHeaders.Expires = DateTime.UtcNow;
This will result in:
Cache-Control:public, must-revalidate, max-age=0 Last-Modified:Sun, 10 Jun 2012 20:19:21 GMT
In this if-statement, you are comparing a datetime for an exact match ==
instead of a >=
comparison, so most of the time you are probably going to get a not modified response.
if (lastModifiedDate.AddMilliseconds(-lastModifiedDate.Millisecond) ==
requestHeaders.IfModifiedSince.Value)
{
return NotModified();
}
This comparison should be more like this:
if (requestHeaders.IfModifiedSince.HasValue &&
requestHeaders.IfModifiedSince.Value >= lastModifiedDate)
{
return NotModified();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.