Using the data cache in an API controller action method

Now,we are going to make use of the questions cache in the GetQuestion method in our API controller:

  1. First, we need to make the cache available for dependency injection so that we can inject it into the API controller. So, let's register this in the Startup class:
public void ConfigureServices(IServiceCollection services)
{
...

services.AddMemoryCache();
services.AddSingleton<IQuestionCache, QuestionCache>();
}

We enable the ASP.NET Core memory cache and then register our cache as a singleton in the dependency injection system. This means that a single instance of our class will be created for the lifetime of the app. So, separate HTTP requests will access the same class instance and, therefore, the same cached data. This is exactly what we want for a cache.

  1. In QuestionsController, let's inject the cache:
...
private readonly IQuestionCache _cache;

public QuestionsController(..., IQuestionCache questionCache)
{
...
_cache = questionCache;
}
  1. Let's change the implementation of GetQuestion to the following:
[HttpGet("{questionId}")]
public ActionResult<QuestionGetSingleResponse>
GetQuestion(int questionId)
{
var question = _cache.Get(questionId);
if (question == null)
{
question = _dataRepository.GetQuestion(questionId);
if (question == null)
{
return NotFound();
}
_cache.Set(question);
}
return question;
}
  1. When a question changes, we need to remove the item from the cache if it exists in the cache. This is so that subsequent requests for the question get the updated question from the database:
[HttpPut("{questionId}")]
public ActionResult<QuestionGetSingleResponse>
PutQuestion(int questionId, QuestionPutRequest questionPutRequest)
{
...

_cache.Remove(savedQuestion.QuestionId);

return savedQuestion;
}
  1. Similarly, when a question is deleted, we need to remove it from the cache if it exists in the cache:
HttpDelete("{questionId}")]
public ActionResult DeleteQuestion(int questionId)
{
...

_cache.Remove(questionId);

return NoContent();
}
  1. We also need to remove the question from the cache when an answer is being posted:
[HttpPost("answer")]
public ActionResult<AnswerGetResponse>
PostAnswer(AnswerPostRequest answerPostRequest)
{
...

_cache.Remove(answerPostRequest.QuestionId.Value);

_questionHubContext.Clients.Group(
$"Question-{answerPostRequest.QuestionId.Value}")
.SendAsync(
"ReceiveQuestion",
_dataRepository.GetQuestion(answerPostRequest.QuestionId.Value));

return savedAnswer;
}
  1. Let's start our REST API by pressing F5 in Visual Studio.
  2. Let's load test the /api/questions/1 endpoint again with our improved implementation, keeping the duration and number of threads in the test the same.
  3. When the test has finished, we'll get our results, confirming the improvement:

  1. Stop the REST API in Visual Studio by pressing Shift F5.

This completes our implementation of the question endpoint with data caching.

It is important to remember to invalidate the cache when the data changes. In our example, this was straightforward, but it can be more complex, particularly if there are other processes outside of the REST API that change the data. So, if we don't have full control of the data changes in the REST API, a cache may not be worth implementing.

Another consideration for whether to use a cache is if the data changes very frequently. In this case, the caching process can actually negatively impact performance because lots of the requests will result in database calls anyway and we have all of the overhead of managing the cache.

However, if the data behind an endpoint changes infrequently and we have control over these changes, then caching is a great way to positively impact performance.

What if the REST API is distributed across several servers? Well, because the memory cache is local to each web server, this could result in database calls where the data is cached on a different server. A solution to this is to implement a distributed cache with IDistributedCache in ASP.NET Core, which would have a very similar implementation to our memory cache. The complexity is that this needs to connect to a third-party cache such as Redis, which adds financial costs and complexity to the solution. For high-traffic REST APIs, a distributed cache is well worth considering, though.

The last topic we are going to look at is garbage collection and how this can negatively impact performance.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.231.184