I've written a custom implementation of VirtualPathProvider which allows me to pull images from Azure Blob Storage. The provider does its thing but calls GetFile
upon every request which isn't great for performance.
GetFile
public override VirtualFile GetFile(string virtualPath)
{
string path = this.FormatVirtualPath(virtualPath);
if (!path.StartsWith(this.pathPrefix, StringComparison.InvariantCultureIgnoreCase))
{
return base.GetFile(virtualPath);
}
string fileSystemPath = this.RemovePathPrefix(path);
return new FileSystemVirtualFile(
virtualPath,
() =>
this.fileSystem.Value.OpenFile(fileSystemPath));
}
Since I know the last modified date of the blob I thought it would be a good idea to add a bit of caching but I can't seem to get anything working.
Reading around it seems I need to override the methods GetCacheDependency
and GetFileHash
which I have done so as follows:
GetCacheDependency
public override CacheDependency GetCacheDependency(string virtualPath,
IEnumerable virtualPathDependencies,
DateTime utcStart)
{
string path = this.FormatVirtualPath(virtualPath);
if (!path.StartsWith(this.pathPrefix, StringComparison.InvariantCultureIgnoreCase))
{
return base.GetCacheDependency(virtualPath,
virtualPathDependencies,
utcStart);
}
return new BlobCacheDependency(
this.fileSystem
.Value.GetLastModified(path)
.DateTime.ToUniversalTime());
}
GetFileHash
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
{
string path = this.FormatVirtualPath(virtualPath);
if (!path.StartsWith(this.pathPrefix, StringComparison.InvariantCultureIgnoreCase))
{
return base.GetFileHash(virtualPath, virtualPathDependencies);
}
byte[] bytes = Encoding.Unicode.GetBytes(virtualPath.ToCharArray());
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] hash = md5.ComputeHash(bytes);
// Concatenate the hash bytes into one long String.
return hash.Aggregate(
new StringBuilder(32),
(sb, b) => sb.Append(b.ToString("X2",
CultureInfo.InvariantCulture)))
.ToString().ToLowerInvariant();
}
}
I also have a custom CacheDependency
implementation.
public class BlobCacheDependency : CacheDependency
{
public BlobCacheDependency(DateTime lastModifiedUtc)
{
this.SetUtcLastModified(lastModifiedUtc);
}
}
Unfortunately neither the of those other methods ever get called when requesting the images. I'm not sure what is missing. Any ideas?
Ok so an answer to this is to set the response cache within the
Open()
method in myVirtualFile
implementation. This allows the browser to cache the file.It's a little hacky but works. In my code it looks like this now.
See
http://forums.asp.net/t/1745003.aspx?VirtualPathProvider+files+do+not+have+cache+control+headers