2010-07-25 4 views
4

J'ai mon application MVC câblé de telle sorte que la couche dépôt des requêtes LINQ aux classes SQL, la couche de service interroge la couche du référentiel, et les contrôleurs appellent la couche de service.ASP.NET MVC - Est-il un moyen facile d'ajouter des données à mon Caching couche de service?

Fondamentalement, j'ai le code comme suit

dépôt

Public Function GetRegions() As IQueryable(Of Region) Implements IRegionRepository.GetRegions 
     Dim region = (From r In dc.Regions 
       Select r) 
     Return region.AsQueryable 
    End Function 

service

Public Function GetRegionById(ByVal id As Integer) As Region Implements IRegionService.GetRegionById 
     Return _RegionRepository.GetRegions() _ 
      .Where(Function(r) (r.ID = id _ 
           And r.isActive)) _ 
      .FirstOrDefault() 
    End Function 

    Public Function GetRegionByNameAndParentID(ByVal region As String, ByVal parentid As Integer) As Region Implements IRegionService.GetRegionByNameAndParentID 
     Return _RegionRepository.GetRegions() _ 
      .Where(Function(r) (r.Region = region _ 
           And r.ParentID = parentid _ 
           And r.isActive)) _ 
      .FirstOrDefault() 
    End Function 

    Public Function GetActiveRegions() As List(Of Region) Implements IRegionService.GetActiveRegions 
     Return _RegionRepository.GetRegions() _ 
      .Where(Function(r) r.isActive) _ 
      .ToList 
    End Function 

    Public Function GetAllRegions() As List(Of Region) Implements IRegionService.GetAllRegions 
     Return _RegionRepository.GetRegions().ToList 
    End Function 

Je me demande s'il y a un bon moyen/efficace d'ajouter Caching la Couche de service pour ne pas toujours avoir besoin d'appeler le REPO si les appels sont moi.

+0

PS: J'ai trouvé cette question, mais il ne répond pas vraiment à ma question: http://stackoverflow.com/questions/102913/ cache-data-objects-quand-utilise-repository-service-pattern-and-mvc –

Répondre

1

rockinthesixstring - oui, vous pouvez ajouter un cache HTTP dans cette couche en utilisant une fonction anonyme soit tirer de la prise en pension ou tirer du cache. Au fond, vous le feriez allong les lignes suivantes (ce qui est d'une application que je travaille sur tout à l'heure qui utilise subsonique, mais la prémisse de ce que vous êtes après est identique.

/// <summary> 
    /// Returns an IQueryable based on the passed-in Expression Database 
    /// </summary> 
    IQueryable<T> IRepository<T>.Find(Expression<Func<T, bool>> expression) 
    { 
     // set up our object cacheKey 
     string keyValue = ParseExpression(expression); 

     if(keyValue==null) 
     { 
      return _repository.Find(expression); 
     } 

     string cacheKey = string.Format(EntityrootList, _className, "Find", keyValue, DateTime.UtcNow.Ticks.ToString(), string.Empty); 

     // try to populate from the cache 
     // rockinthesixstring - this is the part that is most relevant to you 
     var result = Cache.Get(cacheKey, 
           () => _repository.Find(expression), 
           CacheDuration); 

     return result; 
    } 

[ modifier] dans le contrôleur, vous appelleriez comme si (est réglé le contrôleur _repository comme:

readonly IRepository<Booking> _repository; 

dans l'exemple):

[Authorize] 
[AcceptVerbs(HttpVerbs.Post)] 
public ContentResult ListBookings(int shareholderid) 
{ 
    Expression<Func<Booking, bool>> exprTree = x => x.FundShareholderEntity.ShareholderID == shareholderid; 
    var bookings = _repository.Find(exprTree).OrderByDescending(x => x.BookingDetailEntity.ActualDateFrom).OrderBy(x => x.BookingTypeID); 
    return Content(this.RenderPartialToString("BookingListNoPaging", bookings)); 
} 

dans l'exemple ci-dessus, C mal (c'est-à-dire Cache.Get()) est une classe qui enveloppe le cache httpcontext d'une manière plus conviviale.

espérons que cette aide ...

jim

[modifier] - interface cache ajoutée à ajouter au 'débat' :)

public interface ISessionCache 
{ 
    T Get<T>(string key); 
    T Get<T>(string key, Func<T> getUncachedItem, int cacheDuration); 
    void Insert(string key, object obj, int cacheDuration, CacheDependency arg0, TimeSpan arg2); 
    void Remove(string key); 
    object this[string key] { get; } // default indexer 
    IDictionaryEnumerator GetEnumerator(); 
} 

dans la classe injectable serait utilisé comme suit:

public class FakeCache : ISessionCache 
{... all inteface members implemented here etc..} 

ou pour HttpCache:

public class HttpContextCache : ISessionCache 
{... all inteface members implemented here etc..} 

etc, etc .. acclamations encore - jim

+0

désolé pour mon ignorance, mais pouvez-vous expliquer comment vous l'utilisez par rapport à votre couche de dépôt et comment vous l'appelez par exemple vos contrôleurs? –

+0

pas de problème, je vais ajouter l'appel du contrôleur à l'exemple de code ci-dessus ... –

+0

La mise en cache devrait vraiment être dans un aspect séparé. Croyez-moi. Vous ne voulez pas lier votre couche de service à HttpCache. Utilisez votre conteneur IoC pour injecter des intercepteurs prenant en charge le cache pour les méthodes que vous souhaitez mettre en cache. Cela facilite non seulement les tests, mais vous permet également d'échanger rapidement les moteurs de cache (HttpCache, Memcached, etc.) sans modifier tous les services. – Ryan

1

Comme la mise en cache est une préoccupation transversale (faire une recherche dans Wikipedia), vous pouvez utiliser l'injection de politique pour mettre en œuvre la mise en cache sur votre dépôt couche, mais la contrainte est que vous utilisez un cadre de DI comme le château, l'unité, ... l'avantage de ce concept est que vous gardez dans votre code propre couche de dépôt. Je vais commencer par It Depends, mais dans les scénarios simples où aucune interaction avec d'autres agents de service n'est requise, il est recommandé de mettre en cache l'accès à la base de données, car l'accès à la base de données est le plus lent. C'est pourquoi je recommande de ne pas mettre en cache l'accès à la couche de service, mais plutôt à la couche de référentiel. C'est également ce que décrit Martin Fowler dans son modèle de mappeur de données.Si vous êtes dans un scénario distribué, où votre contrôleur et votre service s'exécutent sur des serveurs différents, vous pouvez également opter pour la mise en cache sur votre contrôleur afin d'empêcher la sérialisation des données de référence chaque fois que vous chargez, par exemple. liste déroulante de votre liste de pays ou valeurs de code de taxe.

Dans votre scénario, j'attacher un CachingHandler à votre référentiel GetRegions(), et créer une CacheKey qui combine par ex. la méthode et les paramètres (le cas échéant). Dans une approche simpliste, enregistrez CacheKey et la liste des résultats dans une table Hashtable (dans la vraie vie, utilisez le bloc Application Practices Caching Patterns ou System.Web.Cache) et, pour chaque requête à votre référentiel, vérifiez si la clé de cache est dans votre Hashtable, puis retournez la liste en cache.

Une recherche rapide sur Google vous donne ceci pour commencer: http://entlib.codeplex.com/Thread/View.aspx?ThreadId=34190

Questions connexes