Caching in DotNet Core WebAPI using Strategy Pattern3 min read

Let me write today about Caching, Repository pattern and finally about CacheRepository by using Strategy pattern.

So, I’ve seen a lot of developers use caching pretty differently. 

And mostly what I’ve seen, was, them using cache inside the Controller or BLL, if there is one.

I don’t think this is a proper way of doing it. Since business layer nor controller shouldn’t be aware of caching logic.

Cache is related to database, so I guess there is no need for caching logic in BLL or Controller.

It should be part of a DAL layer and all caching logic should be pointed there.

So, here we have 3 things:

  • caching
  • repository pattern
  • strategy pattern

I’ll cover just a brief introduction to all of these 3 things and then I’ll show you how to implement them in DotNet Core WebAPI.

Caching

So what is caching, why do we need one and what is it for?

Caching is a mechanism which is basically storing all the information we need about object or objects inside a memory.

By using a cache we reduce the number of requests going to our database, which makes our application much faster and scalable.

For caching mechanism in this example, we shall be using MemoryCache ( https://docs.microsoft.com/en-us/dotnet/api/system.runtime.caching.memorycache?view=dotnet-plat-ext-5.0).

Repository pattern

It’s an abstraction, pattern, which can be used in many different languages, not just C#. It’s also one of the most popular patterns.

Benefits are testability and possibility to easily swap data stores. I’ll stop right here and if you want to know more, go to: https://codewithshadman.com/repository-pattern-csharp/#what-is-repository-pattern-csharp

In case you want me to write about these things more in-depth, drop me an email.

Strategy pattern

Also known as the policy pattern, is one of the behavioral patterns which enables us to select algorithm at runtime.

This means it lets the algorithm vary independently from clients that use it. More about it: (https://en.wikipedia.org/wiki/Strategy_pattern)

Show me the code

Enough theory (although it was pretty short anyways :)), I’ll show you the code. But before I proceed I’ll assume you know how to create all interfaces, unit of work, and repositories. If not, stay tuned for upcoming Youtube videos.

Currently, I will focus only on cached repository class and how to inject it into DotNet Core WebAPI.

Cached repository class:

   public class CachedClientRepository: IClientRepository
    {
        private readonly IClientRepository clientRepository;
        private readonly IMemoryCache memoryCache;

        private readonly string CacheKeyPrefix = $"{nameof(CachedClientRepository)}"; // we are avoiding magic strings

        public CachedClientRepository(IClientRepository clientRepository, IMemoryCache memoryCache)
        {
            this.clientRepository = ClientRepository;
            this.memoryCache = memoryCache;
        }

        public async Task<IReadOnlyList<Client>> GetAllAsync()
        {
            // if data is in cache, retrieve it
            if (this.memoryCache.TryGetValue($"{CacheKeyPrefix}", out IReadOnlyList<Client> cachedData))
            {
                return cachedData;
            }

            // if no data in cache available go to database and retrieve data
            var dbData = await this.clientRepository.GetAllAsync();

            this.memoryCache.Set($"{CacheKeyPrefix}", dbData, DateTimeOffset.Now.AddDays(1));

            return dbData;
        }
    }

And finally, vital piece of code to glue our CachedClientRepository class with ClientRepository class, in our Startup.cs class we inject our class like this:

	services.AddScoped<ClientRepository>();
	services.AddScoped<IClientRepository, CachedClientRepository>(serviceProvider =>
	{
		IClientRepository? nonCachedClientRepository = serviceProvider.GetService<ClientRepository>();
		IMemoryCache? memoryCache = serviceProvider.GetService<IMemoryCache>();

		return new CachedClientRepository(nonCachedClientRepository, memoryCache);
	});

Usage

Now we have no caching logic in our BLL layer or Controller. We just call the repo method like:

 var dbData = await this.UnitOfWork.ClientRepository.GetAll();

 And all the caching logic is now done under the hood inside DAL layer. 

Meaning, CachedClientRepository is going to be used first and if no cached values are available it will trigger the actual code to retrieve real database values and set the cache.

 I hope you did get a clearer picture how to use the caching in a proper way.

Maybe this example is not clear enough, especially for newcomers, since it assumes you have experience with some patterns. Anyways, I will definitely post a more in-depth video about this example.

So stay tuned and until the next reading!

Cheers

(Visited 46 times, 1 visits today)

Leave a comment

Your email address will not be published. Required fields are marked *