Reputation: 169
I am displaying images on my website which I have stored in a database. From my Razor view I write a line such as this.
<img alt ="" src='@Url.Action("ShowImage",
"Controller", new { imageID = Model.ImageID })'/>
The function that gets called looks like so.
public ActionResult ShowImage(string imageID)
{
WebServiceClient client = new WebServiceClient();
byte[] image = client.GetImage(Convert.ToInt64(imageID));
if (image == null)
{
return new EmptyResult();
}
return File(image,"image/png");
}
This works just fine, but my quesiton is if it is possible to cache these images somehow. I have seen ways to cache images using custom HttpHandler, but all those examples are if you have the actual file and not the binary data.
Upvotes: 1
Views: 938
Reputation: 12440
Here is a cache rapper you could use:
public class CacheManager
{
private static readonly string keyPrefix = typeof(CacheManager).FullName;
private static readonly object syncLock = new object();
private readonly Cache cache;
public CacheManager(Cache cache)
{
this.cache = HttpRuntime.Cache;
}
public TValue Get<TValue>(string key)
{
return (TValue)HttpRuntime.Cache[MakeKey(key)];
}
public void Set<TValue>(string key, Func<TValue> value)
{
Set(key, null, null, null, value, null);
}
public void Set<TValue>(string key, DateTime timestamp, TValue value)
{
Set(key, timestamp, null, null, value, null);
}
public void Set<TValue>(string key, TimeSpan duration, TValue value)
{
Set(key, null, duration, null, value, null);
}
public void Set<TValue>(string key, TValue value, Action<bool> onRemoveCallback)
{
Set(key, null, null, null, value, onRemoveCallback);
}
public void Set<TValue>(string key, DateTime timestamp, TValue value, Action<bool> onRemoveCallback)
{
Set(key, timestamp, null, null, value, onRemoveCallback);
}
public void Set<TValue>(string key, TimeSpan duration, TValue value, Action<bool> onRemoveCallback)
{
Set(key, null, duration, null, value, onRemoveCallback);
}
public void Set<TValue>(string key, IEnumerable<string> fileDependencies, TValue value)
{
Set(key, null, null, fileDependencies, value, null);
}
public void Set<TValue>(string key, DateTime timestamp, IEnumerable<string> fileDependencies, TValue value)
{
Set(key, timestamp, null, fileDependencies, value, null);
}
public void Set<TValue>(string key, TimeSpan duration, IEnumerable<string> fileDependencies, TValue value)
{
Set(key, null, duration, fileDependencies, value, null);
}
public void Set<TValue>(string key, IEnumerable<string> fileDependencies, TValue value, Action<bool> onRemoveCallback)
{
Set(key, null, null, fileDependencies, value, onRemoveCallback);
}
public void Set<TValue>(string key, DateTime timestamp, IEnumerable<string> fileDependencies, TValue value, Action<bool> onRemoveCallback)
{
Set(key, timestamp, null, fileDependencies, value, onRemoveCallback);
}
public void Set<TValue>(string key, TimeSpan duration, IEnumerable<string> fileDependencies, TValue value, Action<bool> onRemoveCallback)
{
Set(key, null, duration, fileDependencies, value, onRemoveCallback);
}
public TValue GetOrCreate<TValue>(string key, Func<TValue> factory)
{
return GetOrCreate(key, null, null, null, factory, null);
}
public TValue GetOrCreate<TValue>(string key, DateTime timestamp, Func<TValue> factory)
{
return GetOrCreate(key, timestamp, null, null, factory, null);
}
public TValue GetOrCreate<TValue>(string key, TimeSpan duration, Func<TValue> factory)
{
return GetOrCreate(key, null, duration, null, factory, null);
}
public TValue GetOrCreate<TValue>(string key, Func<TValue> factory, Action<bool> onRemoveCallback)
{
return GetOrCreate(key, null, null, null, factory, onRemoveCallback);
}
public TValue GetOrCreate<TValue>(string key, DateTime timestamp, Func<TValue> factory, Action<bool> onRemoveCallback)
{
return GetOrCreate(key, timestamp, null, null, factory, onRemoveCallback);
}
public TValue GetOrCreate<TValue>(string key, TimeSpan duration, Func<TValue> factory, Action<bool> onRemoveCallback)
{
return GetOrCreate(key, null, duration, null, factory, onRemoveCallback);
}
public TValue GetOrCreate<TValue>(string key, IEnumerable<string> fileDependencies, Func<TValue> factory)
{
return GetOrCreate(key, null, null, fileDependencies, factory, null);
}
public TValue GetOrCreate<TValue>(string key, DateTime timestamp, IEnumerable<string> fileDependencies, Func<TValue> factory)
{
return GetOrCreate(key, timestamp, null, fileDependencies, factory, null);
}
public TValue GetOrCreate<TValue>(string key, TimeSpan duration, IEnumerable<string> fileDependencies, Func<TValue> factory)
{
return GetOrCreate(key, null, duration, fileDependencies, factory, null);
}
public TValue GetOrCreate<TValue>(string key, IEnumerable<string> fileDependencies, Func<TValue> factory, Action<bool> onRemoveCallback)
{
return GetOrCreate(key, null, null, fileDependencies, factory, onRemoveCallback);
}
public TValue GetOrCreate<TValue>(string key, DateTime timestamp, IEnumerable<string> fileDependencies, Func<TValue> factory, Action<bool> onRemoveCallback)
{
return GetOrCreate(key, timestamp, null, fileDependencies, factory, onRemoveCallback);
}
public TValue GetOrCreate<TValue>(string key, TimeSpan duration, IEnumerable<string> fileDependencies, Func<TValue> factory, Action<bool> onRemoveCallback)
{
return GetOrCreate(key, null, duration, fileDependencies, factory, onRemoveCallback);
}
public void Remove(string key)
{
HttpRuntime.Cache.Remove(MakeKey(key));
}
private static string MakeKey(string key)
{
Check.Argument.IsNotNullOrEmpty(key, "key");
return keyPrefix + ":" + key;
}
private void Set<TValue>(string key, DateTime? timestamp, TimeSpan? duration, IEnumerable<string> fileDependencies, TValue value, Action<bool> onRemoveCallback)
{
string fullKey = MakeKey(key);
lock (syncLock)
{
cache.Remove(fullKey);
InsertInCache(fullKey, value, fileDependencies, timestamp, duration, onRemoveCallback);
}
}
private TValue GetOrCreate<TValue>(string key, DateTime? timestamp, TimeSpan? duration, IEnumerable<string> fileDependencies, Func<TValue> factory, Action<bool> onRemoveCallback)
{
string fullKey = MakeKey(key);
object value = cache.Get(fullKey);
if (value == null)
{
lock (syncLock)
{
value = cache.Get(fullKey);
if (value == null)
{
value = factory();
if (value != null)
{
InsertInCache(fullKey, value, fileDependencies, timestamp, duration, onRemoveCallback);
}
}
}
}
return (TValue)value;
}
private void InsertInCache(string key, object value, IEnumerable<string> fileDependencies, DateTime? timestamp, TimeSpan? duration, Action<bool> onRemoveCallback)
{
Action<string, object, CacheItemRemovedReason> raiseOnRemoveCallback = (cacheKey, state, reason) => onRemoveCallback(reason == CacheItemRemovedReason.DependencyChanged);
cache.Add(key, value, fileDependencies != null ? new CacheDependency(fileDependencies.ToArray()) : null, timestamp ?? Cache.NoAbsoluteExpiration, duration ?? Cache.NoSlidingExpiration, CacheItemPriority.Normal, onRemoveCallback != null ? new CacheItemRemovedCallback(raiseOnRemoveCallback) : null);
}
}
You can now change your code like so:
public ActionResult ShowImage(string imageID)
{
CacheManager cacheManager = new CacheManager();
byte[] image = cacheManager.GetOrCreate(
imageID, //Cache Key
DateTime.Now.AddMinutes(20), //Will be in Cache for 20 min
() => {
WebServiceClient client = new WebServiceClient();
return client.GetImage(Convert.ToInt64(imageID));
}); //Delegate to call if the cache is empty
if (image == null)
{
return new EmptyResult();
}
return File(image,"image/png");
}
Upvotes: 2
Reputation: 1039498
You could try decorating your controller action with the [OutputCache]
attribute:
[OutputCache(Duration = 3600, VaryByParam = "imageID")]
public ActionResult ShowImage(string imageID)
{
WebServiceClient client = new WebServiceClient();
byte[] image = client.GetImage(Convert.ToInt64(imageID));
if (image == null)
{
return new EmptyResult();
}
return File(image,"image/png");
}
You might also decide where you want those images to be cached using the Location property. The default value is Any
meaning that the output cache can be located on the browser client (where the request originated), on a proxy server (or any other server) participating in the request, or on the server where the request was processed.
Upvotes: 1