Search code examples
c#asp.net-mvcasp.net-web-apiasp.net-web-api2memorycache

Memory Cache in web api


I was looking for Caching in my web api where i can use output of one api method(that changes once in 12hrs) for subsequesnt calls and then i found this solution on SO,but i am having a difficulty in understanding and using the below code

private IEnumerable<TEntity> GetFromCache<TEntity>(string key, Func<IEnumerable<TEntity>> valueFactory) where TEntity : class 
{
    ObjectCache cache = MemoryCache.Default;
    var newValue = new Lazy<IEnumerable<TEntity>>(valueFactory);            
    CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30) };
    //The line below returns existing item or adds the new value if it doesn't exist
    var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<IEnumerable<TEntity>>;
    return (value ?? newValue).Value; // Lazy<T> handles the locking itself
}

I am not sure how to call and use this method in below context? I have a method Get

  public IEnumerable<Employee> Get()
    {
        return repository.GetEmployees().OrderBy(c => c.EmpId);
    }

and i want to cache the output of Get and use it in my other methods GetEmployeeById() or Search()

        public Movie GetEmployeeById(int EmpId)
        {
           //Search Employee in Cached Get
        }

        public IEnumerable<Employee> GetEmployeeBySearchString(string searchstr)
        {
          //Search in Cached Get
        }

Solution

  • I updated your method to return classes instead of IEnumerable:

    private TEntity GetFromCache<TEntity>(string key, Func<TEntity> valueFactory) where TEntity : class 
    {
        ObjectCache cache = MemoryCache.Default;
        // the lazy class provides lazy initializtion which will evaluate the valueFactory expression only if the item does not exist in cache
        var newValue = new Lazy<TEntity>(valueFactory);            
        CacheItemPolicy policy = new CacheItemPolicy 
                                     {
                                         AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30) 
                                     };
    
        // The line below returns existing item or adds the new value if it doesn't exist
        var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<TEntity>;
    
        return (value ?? newValue).Value; // Lazy<T> handles the locking itself
    }
    

    Then you can use this method like this:

    public Movie GetMovieById(int movieId)
    {
        var cacheKey = "movie" + movieId;
    
        var movie = GetFromCache<Movie>(cacheKey, () => {       
            // load movie from DB
            return context.Movies.First(x => x.Id == movieId); 
        });
    
        return movie;
    }
    

    and to search movies

    [ActionName("Search")]
    public IEnumerable<Movie> GetMovieBySearchParameter(string searchstr)
    {
         var cacheKey = "movies" + searchstr;
         var movies = GetFromCache<IEnumerable<Movie>>(cacheKey, () => {               
              return repository.GetMovies().OrderBy(c => c.MovieId).ToList(); 
         });
    
         return movies;
    }