Можно все еще использовать кэш (общий для все ответы) и сессия (уникальный на пользователя) для устройства хранения данных.
мне нравится следующая "попытка, добираются от, кэшируют/создают и хранят" шаблон (c#-like псевдокод):
public static class CacheExtensions
{
public static T GetOrStore<T>(this Cache cache, string key, Func<T> generator)
{
var result = cache[key];
if(result == null)
{
result = generator();
cache[key] = result;
}
return (T)result;
}
}
Вы использовали бы это как так:
var user = HttpRuntime
.Cache
.GetOrStore<User>(
$"User{_userId}",
() => Repository.GetUser(_userId));
можно адаптировать этот шаблон к Сессии, ViewState (тьфу) или любой другой механизм кэширования. Можно также расширить ControllerContext. HttpContext (то, которое я думаю, является одной из оберток в Системе. Сеть. Расширения), или создают новый класс, чтобы сделать это с некоторой комнатой для насмешки кэша.
Если Вы хотите кэшируемый для длины запроса, помещаете это в Ваш базовый класс контроллера:
public User User {
get {
User _user = ControllerContext.HttpContext.Items["user"] as User;
if (_user == null) {
_user = _repository.Get<User>(id);
ControllerContext.HttpContext.Items["user"] = _user;
}
return _user;
}
}
, Если Вы хотите кэшироваться для дольше, используйте замену вызов ControllerContext с одним для Кэширования []. Если Вы действительно примете решение использовать объект Кэша кэшироваться дольше, необходимо будет использовать уникальный ключ кэша, поскольку он будет совместно использован через запросы/пользователей.
Если Вам не нужны определенные функции аннулирования кэширования ASP.NET, статические поля довольно хороши, легки и просты в использовании. Однако, как только Вам были нужны расширенные функции, можно переключиться на ASP.NET Cache
объект для устройства хранения данных.
подход, который я использую, должен создать свойство и private
поле. Если поле будет null
, свойство заполнит его и возвратит его. Я также обеспечиваю InvalidateCache
метод, который вручную устанавливает поле на null
. Преимущество этого подхода это, что механизм кэширования инкапсулируется в свойстве и можно переключиться на другой подход, если Вы хотите.
Мне нравится скрывать то, что данные кэшируются в репозитории. Можно получить доступ к кэшу через HttpContext. Текущий. Свойство Cache и хранилище информация о Пользователе с помощью "Пользователя" +id. ToString () как ключ.
Это означает, что весь доступ к Пользовательским данным из репозитория будет использовать кэшированные данные при наличии и не требует никаких изменений кода в модели, контроллере или представлении.
я использовал этот метод для исправления серьезных проблем производительности в системе, которая запрашивала базу данных для каждого Свойства пользователя и уменьшила время загрузки страницы с минут до единственных секунд цифры.
Я взял ответ Уилла и изменил его, чтобы сделать класс CacheExtensions
статическим и предложить небольшое изменение, чтобы иметь дело с возможностью Func
является null
:
public static class CacheExtensions
{
private static object sync = new object();
public const int DefaultCacheExpiration = 20;
/// <summary>
/// Allows Caching of typed data
/// </summary>
/// <example><![CDATA[
/// var user = HttpRuntime
/// .Cache
/// .GetOrStore<User>(
/// string.Format("User{0}", _userId),
/// () => Repository.GetUser(_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="cache">calling object</param>
/// <param name="key">Cache key</param>
/// <param name="generator">Func that returns the object to store in cache</param>
/// <returns></returns>
/// <remarks>Uses a default cache expiration period as defined in <see cref="CacheExtensions.DefaultCacheExpiration"/></remarks>
public static T GetOrStore<T>( this Cache cache, string key, Func<T> generator ) {
return cache.GetOrStore( key, (cache[key] == null && generator != null) ? generator() : default( T ), DefaultCacheExpiration );
}
/// <summary>
/// Allows Caching of typed data
/// </summary>
/// <example><![CDATA[
/// var user = HttpRuntime
/// .Cache
/// .GetOrStore<User>(
/// string.Format("User{0}", _userId),
/// () => Repository.GetUser(_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="cache">calling object</param>
/// <param name="key">Cache key</param>
/// <param name="generator">Func that returns the object to store in cache</param>
/// <param name="expireInMinutes">Time to expire cache in minutes</param>
/// <returns></returns>
public static T GetOrStore<T>( this Cache cache, string key, Func<T> generator, double expireInMinutes ) {
return cache.GetOrStore( key, (cache[key] == null && generator != null) ? generator() : default( T ), expireInMinutes );
}
/// <summary>
/// Allows Caching of typed data
/// </summary>
/// <example><![CDATA[
/// var user = HttpRuntime
/// .Cache
/// .GetOrStore<User>(
/// string.Format("User{0}", _userId),_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="cache">calling object</param>
/// <param name="key">Cache key</param>
/// <param name="obj">Object to store in cache</param>
/// <returns></returns>
/// <remarks>Uses a default cache expiration period as defined in <see cref="CacheExtensions.DefaultCacheExpiration"/></remarks>
public static T GetOrStore<T>( this Cache cache, string key, T obj ) {
return cache.GetOrStore( key, obj, DefaultCacheExpiration );
}
/// <summary>
/// Allows Caching of typed data
/// </summary>
/// <example><![CDATA[
/// var user = HttpRuntime
/// .Cache
/// .GetOrStore<User>(
/// string.Format("User{0}", _userId),
/// () => Repository.GetUser(_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="cache">calling object</param>
/// <param name="key">Cache key</param>
/// <param name="obj">Object to store in cache</param>
/// <param name="expireInMinutes">Time to expire cache in minutes</param>
/// <returns></returns>
public static T GetOrStore<T>( this Cache cache, string key, T obj, double expireInMinutes ) {
var result = cache[key];
if ( result == null ) {
lock ( sync ) {
result = cache[key];
if ( result == null ) {
result = obj != null ? obj : default( T );
cache.Insert( key, result, null, DateTime.Now.AddMinutes( expireInMinutes ), Cache.NoSlidingExpiration );
}
}
}
return (T)result;
}
}
Я бы также подумал о том, чтобы сделать еще один шаг, чтобы реализовать тестируемое решение для сеанса, которое расширяет абстрактный класс System.Web.HttpSessionStateBase.
public static class SessionExtension
{
/// <summary>
///
/// </summary>
/// <example><![CDATA[
/// var user = HttpContext
/// .Session
/// .GetOrStore<User>(
/// string.Format("User{0}", _userId),
/// () => Repository.GetUser(_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="cache"></param>
/// <param name="key"></param>
/// <param name="generator"></param>
/// <returns></returns>
public static T GetOrStore<T>( this HttpSessionStateBase session, string name, Func<T> generator ) {
var result = session[name];
if ( result != null )
return (T)result;
result = generator != null ? generator() : default( T );
session.Add( name, result );
return (T)result;
}
}
@njappboy: Хорошая реализация. Я бы только отложил вызов Generator ()
до последнего ответственного момента. таким образом, вы также можете кэшировать вызовы методов.
/// <summary>
/// Allows Caching of typed data
/// </summary>
/// <example><![CDATA[
/// var user = HttpRuntime
/// .Cache
/// .GetOrStore<User>(
/// string.Format("User{0}", _userId),
/// () => Repository.GetUser(_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="Cache">calling object</param>
/// <param name="Key">Cache key</param>
/// <param name="Generator">Func that returns the object to store in cache</param>
/// <returns></returns>
/// <remarks>Uses a default cache expiration period as defined in <see cref="CacheExtensions.DefaultCacheExpiration"/></remarks>
public static T GetOrStore<T>( this Cache Cache, string Key, Func<T> Generator )
{
return Cache.GetOrStore( Key, Generator, DefaultCacheExpiration );
}
/// <summary>
/// Allows Caching of typed data
/// </summary>
/// <example><![CDATA[
/// var user = HttpRuntime
/// .Cache
/// .GetOrStore<User>(
/// string.Format("User{0}", _userId),
/// () => Repository.GetUser(_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="Cache">calling object</param>
/// <param name="Key">Cache key</param>
/// <param name="Generator">Func that returns the object to store in cache</param>
/// <param name="ExpireInMinutes">Time to expire cache in minutes</param>
/// <returns></returns>
public static T GetOrStore<T>( this Cache Cache, string Key, Func<T> Generator, double ExpireInMinutes )
{
var Result = Cache [ Key ];
if( Result == null )
{
lock( Sync )
{
if( Result == null )
{
Result = Generator( );
Cache.Insert( Key, Result, null, DateTime.Now.AddMinutes( ExpireInMinutes ), Cache.NoSlidingExpiration );
}
}
}
return ( T ) Result;
}