6

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
        }

1 Answer 1

11

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;
}
Sign up to request clarification or add additional context in comments.

5 Comments

@little it is done inside of the GetFromCache method
@little you should call your repository inside of the valueFactory function (it will be executed only if the object is not in the cache). Look at my answer i'm not calling a repository but directly the context so just replace the context with repository.
@little i updated the GetMovieBySearchParameter method in my example and now it is using a repository.
@F11, hi, what do you want to ask?
@F11 yes, send me a link to chat.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.