DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Building a RESTful Service Using ASP.NET Core and dotConnect for PostgreSQL
  • Working With dotConnect for Oracle in ASP.NET Core
  • Working With dotConnect for SQL Server in ASP.NET Core
  • Implementing the Repository Pattern Using C# and Entity Developer in ASP.NET Core

Trending

  • How to Configure and Customize the Go SDK for Azure Cosmos DB
  • Agentic AI for Automated Application Security and Vulnerability Management
  • How the Go Runtime Preempts Goroutines for Efficient Concurrency
  • Transforming AI-Driven Data Analytics with DeepSeek: A New Era of Intelligent Insights
  1. DZone
  2. Data Engineering
  3. Data
  4. Implementing Cache Dependency in ASP.NET Core

Implementing Cache Dependency in ASP.NET Core

This article takes a look at how we can work with cache dependency with in-memory caching in ASP.NET Core.

By 
Joydip Kanjilal user avatar
Joydip Kanjilal
DZone Core CORE ·
Feb. 24, 21 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
10.7K Views

Join the DZone community and get the full member experience.

Join For Free

Caching is a feature that has been introduced in ASP.NET. The latest versions of ASP.NET, as well as ASP.NET Core, provides support for caching. In ASP.NET Core, in particular, you’ve supported three different types of caching. These are response caching, in-memory caching, and distributed caching.

This article takes a look at how we can work with cache dependency with in-memory caching in ASP.NET Core. This article discusses the features and benefits of dotConnect for SQL, why caching is important, what cache dependency is all about, and why it is important.

In this example, we’ll connect to SQL Server using dotConnect for SQL Server (earlier known as SQLDirect.NET) which is a high performance and enhanced data provider for SQL Server that is built on top of ADO.NET and SqlClient and can work on both connected and disconnected modes.

Prerequisites

To be able to work with the code examples demonstrated in this article, you should have the following installed in your system:

  • Visual Studio 2019 Community Edition
  • SQL Server 2019 Developer Edition
  • dotConnect for SQL Server

You can download .NET Core from here: https://dotnet.microsoft.com/download/archives

You can download Visual Studio 2019 from here: https://visualstudio.microsoft.com/downloads/

You can download SQL Server 2019 Developer Edition from here: https://www.microsoft.com/en-us/sql-server/sql-server-downloads

Create the Database

Now that the ASP.NET Core Web API project has been created in Visual Studio 2019; the next step is to create the database. Note that for the sake of simplicity we’ll use a database with just two tables with a simple design in this example.

Launch the SQL Server Management Studio and create a new database called Demo. Next, use the following script to create two tables named Products and Categories inside the Demo database.

SQL
x
9
 
1
CREATE TABLE [dbo].[Department](
2
  [Id] [int] NOT NULL, 
3
  [Name] [nvarchar](max) NOT NULL, 
4
  CONSTRAINT [PK_Department] PRIMARY KEY CLUSTERED ([Id] ASC) WITH (
5
    PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
6
    IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
7
    ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF
8
  ) ON [PRIMARY]
9
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]


We’ll use this database in the subsequent sections of this article to demonstrate how we can work with caching and cache dependency in ASP.NET Core.

Create a New ASP.NET Core Web API Project in Visual Studio 2019

Once you’ve installed the necessary software and/or tools needed to work with dotConnect for SqlServer, follow the steps given below to create a new ASP.NET Core Web API project.

  1. First off, open the Visual Studio 2019 IDE
  2. Next, click "Create a new project" once the IDE has loaded
  3. Click "Create a new project"
  4. Next, select "ASP.NET Core Web Application"
  5. Click the "Next" button
  6. Specify the project name and location - where it should be stored in your system
  7. Optionally, click the "Place solution and project in the same directory" checkbox.
  8. Next, click the "Create" button
  9. In the "Create a new ASP.NET Core Web Application" dialog window that is shown next, select "API" as the project template.
  10. Select ASP.NET Core 3.1 or later as the version.
  11. You should disable the "Configure for HTTPS" and "Enable Docker Support" options by disabling the respective checkboxes.
  12. Since we'll not be using authentication in this example, specify authentication as "No Authentication".
  13. Finally, click on the "Create" button to finish the process.

Create a new controller class in this project and name it as DepartmentController. We’ll use this class in the sections that follow.

Enable InMemory Caching in ASP.NET Core

You can take advantage of the two interfaces IMemoryCache and IDistributedCache for working with caching in ASP.NET. We'll use IMemory cache in this article.

To be able to use in-memory caching in ASP.NET Core, you must enable it as shown in the code snippet given below:

C#
 




x


 
1
public void ConfigureServices(IServiceCollection services)
2

          
3
{
4

          
5
  services.AddControllers();
6

          
7
  services.AddMemoryCache();
8

          
9
}



As you can see in the preceding code snippet, we’ve enables in-memory caching in the ConfigureServices method of the Startup class.

Store and Retrieve Items Using IMemoryCache

You can take advantage of the Set<T>() method to store an object in the cache using the IMemoryCache interface as shown below:

C#
 




xxxxxxxxxx
1


 
1
_cache.Set("ThisIsMyKey", DateTime.Now.ToString());



The Set method accepts two parameters - the first one is the key that is an identifier using which you can identify the objects stored in the cache and the second one is the object to be cached.

The Get(object key) method can be used to retrieve a cached object.

C#
 




xxxxxxxxxx
1


 
1
_cache.Get("ThisIsMyKey");



The Get method returns an object so you'd need to cast the returned instance as appropriate.

You can also use the Get<T>(object key) method to retrieve an object from the cache as shown below:

C#
 




xxxxxxxxxx
1


 
1
_cache.Get<string>("ThisIsMyKey");



You can also use the TryGetValue<T>() method if you're not sure if a specific key is available in the cache.

C#
 




x


 
1
DateTime currentDateTime;
2

          
3
if (!cache.TryGetValue < string > ("ThisIsMyKey", out currentDateTime))
4

          
5
{
6

          
7
  currentDateTime = DateTime.UtcNow;
8

          
9
}



The GetOrCreate() method verifies if the key passed as an argument is available, if not, it creates it.

C#
 




x


 
1
return _cache.GetOrCreate < DateTime > ("ABCXYZ", cacheEntry =>
2

          
3
  {
4

          
5
    return DateTime.UtcNow;
6

          
7
  });



Implementing Cache Dependency in ASP.NET Core

Note that there is no Cache object in ASP.NET Core. You should implement caching using the IMemoryCache interface pertaining to Microsoft.Extensions.Caching.Memory namespace.

C#
 




x


 
1
public interface IMemoryCache: IDisposable
2

          
3
{
4

          
5
  bool TryGetValue(object key, out object value);
6

          
7
  ICacheEntry CreateEntry(object key);
8

          
9
  void Remove(object key);
10

          
11
}



In this example we’ll take advantage of dotConnect for SQL Server – it’s a high performant framework which can be used for writing efficient code and build flexible data access applications.

Creating a New Connection

To create a new Sql Connection object at runtime, you should first add references to the Devart.Data.SqlServer.dll and Devart.Data.dll assemblies.

The following code snippet illustrates how you can create SqlConnection at runtime.

C#
 




xxxxxxxxxx
1
17


 
1
using Devart.Data.SqlServer;
2

          
3
using Devart.Data;
4

          
5
SqlConnection connection = new SqlConnection();
6

          
7
connection.DataSource = "LAPTOP-DEMO\MSSQLSERVER";
8

          
9
connection.Database = "Test";
10

          
11
connection.UserId = "some user name";
12

          
13
connection.Password = "some password";
14

          
15
connection.MaxPoolSize = 150;
16

          
17
connection.ConnectionTimeout = 30;



Alternatively, you can specify all of the above properties in a single statement as shown below:

SQL
 




xxxxxxxxxx
1


 
1
SqlConnection connection = new SqlConnection();
2

          
3
connection.ConnectionString = "User Id=sa;Password=some password;DataSource=LAPTOP-DEMO\MSSQLSERVER";



Create the Repository

We’ll now create a class named DepartmentRepository that follows the repository design pattern. The repository design pattern is a popular pattern that is used to abstract the calls to the database. It does this by exposing the necessary methods that the application can use to perform CRUD operations against the underlying database. In this example we’ll be having just one method named GetData that would return a list of departments. The DepartmentRepository class is given below:

C#
 




x


 
1
public class DepartmentRepository
2

          
3
{
4

          
5
  public List < Department > GetData()
6

          
7
  {
8

          
9
    try
10

          
11
    {
12

          
13
      List < Department > departments = new List < Department > ();
14

          
15
      string connectionString =
16

          
17
        "Specify your database connection string here.";
18

          
19
      Devart.Data.SqlServer.SqlConnection dbConnection =
20

          
21
        new Devart.Data.SqlServer.SqlConnection(connectionString);
22

          
23
      Devart.Data.SqlServer.SqlDataAdapter dataAdapter =
24

          
25
        new Devart.Data.SqlServer.SqlDataAdapter
26

          
27
      ("SELECT * From Department", dbConnection);
28

          
29
      DataSet dataSet = new DataSet();
30

          
31
      dataAdapter.Fill(dataSet, "Department");
32

          
33
      foreach(DataTable dataTable in dataSet.Tables)
34

          
35
      {
36

          
37
        foreach(DataRow dataRow in dataTable.Rows)
38

          
39
        {
40

          
41
          Department department = new Department();
42

          
43
          department.Id =
44

          
45
            int.Parse(dataRow["Id"].ToString());
46

          
47
          department.Name = dataRow["Name"].ToString();
48

          
49
          departments.Add(department);
50

          
51
        }
52

          
53
      }
54

          
55
      return departments;
56

          
57
    } catch
58

          
59
    {
60

          
61
      throw;
62

          
63
    }
64

          
65
  }
66

          
67
}



You can take advantage of dependency injection to be able to use an instance of the DepartmentRepository in your controller classes. We’ll skip this discussion here anyway.

Set Expiration Policies on Cached Data

When working with in-memory cache using the IMemoryCache interface, you can take advantage of MemoryCacheEntryOptions class to manage the expiration of cache data. You can either mention a fixed time (absolute expiration) after which the cached item would expire, or mention a certain time (sliding expiration) after which the cached item will expire. The following code snippet illustrates how you can store items in the cache with absolute expiration:

C#
 




xxxxxxxxxx
1


 
1
DepartmentRepository repository = new DepartmentRepository();
2

          
3
var data = repository.GetData();
4

          
5
_cache.Set("ABCXYZ", data, TimeSpan.FromDays(1));



The following code snippet shows how you can do the same with sliding expiration:

C#
 




x


 
1
DepartmentRepository repository = new DepartmentRepository();
2

          
3
var data = repository.GetData();
4

          
5
_cache.Set("ABCXYZ", data, new MemoryCacheEntryOptions
6

          
7
  {
8

          
9
    SlidingExpiration = TimeSpan.FromDays(1)
10

          
11
  });



You can use both absolute and sliding expiration together. The following code snippet illustrates how this can be achieved:

C#
 




x


 
1
DepartmentRepository repository = new DepartmentRepository();
2

          
3
var data = repository.GetData();
4

          
5
_cache.Set("ABCXYZ", data, new MemoryCacheEntryOptions
6

          
7
  {
8

          
9
    AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(5),
10

          
11
      SlidingExpiration = TimeSpan.FromDays(1)
12

          
13
  });



Cache Dependencies and Callbacks

The MemoryCacheEntryOptions class provides support for registering callbacks, which would be executed when an item is removed from the memory cache. The following code snippet shows how it can be used:

C#
 




x


 
1
MemoryCacheEntryOptions cacheOption = new MemoryCacheEntryOptions()
2

          
3
{
4

          
5
  AbsoluteExpirationRelativeToNow = (DateTime.Now.AddMinutes(1) - DateTime.Now),
6

          
7
};
8

          
9
cacheOption.RegisterPostEvictionCallback(
10

          
11
  (key, value, reason, substate) =>
12

          
13
  {
14

          
15
    Console.Write("Cache expired!");
16

          
17
  });



The DefaultController class should look like the code snippet given below – just delete all other methods in it to keep things simple.

C#
 




x


 
1
[Route("api/[controller]")]
2

          
3
[ApiController]
4

          
5
public class DefaultController: ControllerBase
6

          
7
{
8

          
9
  private IMemoryCache _cache;
10

          
11
  public DefaultController(IMemoryCache cache)
12

          
13
  {
14

          
15
    _cache = cache;
16

          
17
  }
18

          
19
  //Other methods
20

          
21
}



The following action method calls the GetDepartments method to retrieve all records of the Department table and then calls the AddDataToCache method to add the data retrieved to the in-memory cache. Lastly, it returns all records of the Department table.

C#
 




x


 
1
[HttpGet("GetData")]
2

          
3
public ActionResult < List < Department >> GetData()
4

          
5
{
6

          
7
  var data = GetDepartments();
8

          
9
  AddDataToCache(data);
10

          
11
  return Ok(data);
12

          
13
}
14

          
15
The GetDepartments and AddDataToCache methods are given below:
16

          
17
  private List < Department > GetDepartments()
18

          
19
{
20

          
21
  DepartmentRepository repository = new DepartmentRepository();
22

          
23
  return repository.GetDepartments();
24

          
25
}
26

          
27
private void AddDataToCache(List < Department > departments)
28

          
29
{
30

          
31
  var memoryCacheEntryOptions = new MemoryCacheEntryOptions();
32

          
33
  memoryCacheEntryOptions.RegisterPostEvictionCallback
34

          
35
  (CacheExpired_Callback);
36

          
37
  memoryCacheEntryOptions.AddExpirationToken(new
38

          
39
    CancellationChangeToken(new
40

          
41
      CancellationTokenSource(TimeSpan.FromSeconds(45)).Token));
42

          
43
  _cache.Set("ABCXYZ", departments, memoryCacheEntryOptions);
44

          
45
}



The CacheExpired_Callback is triggered when data in the cache has expired.

C#
 




x


 
1
private void CacheExpired_Callback(object key, object value, EvictionReason reason, object state)
2

          
3
{
4

          
5
  var existingDataInCache =
6

          
7
    _cache.Get < List < Department >> ("ABCXYZ");
8

          
9
  if (existingDataInCache == null)
10

          
11
  {
12

          
13
    AddDataToCache(value as List < Department > );
14

          
15
  }
16

          
17
}



The complete source code of the DepartmentController is given below:

C#
 




x


 
1
[Route("api/[controller]")]
2

          
3
[ApiController]
4

          
5
public class DefaultController: ControllerBase
6

          
7
{
8

          
9
  private IMemoryCache _cache;
10

          
11
  public DefaultController(IMemoryCache cache)
12

          
13
  {
14

          
15
    _cache = cache;
16

          
17
  }
18

          
19
  [HttpGet("GetData")]
20

          
21
  public List < Department > GetData()
22

          
23
  {
24

          
25
    var data = GetDepartments();
26

          
27
    AddDataToCache(data);
28

          
29
    return data;
30

          
31
  }
32

          
33
  private List < Department > GetDepartments()
34

          
35
  {
36

          
37
    DepartmentRepository repository = new DepartmentRepository();
38

          
39
    return repository.GetDepartments();
40

          
41
  }
42

          
43
  private void AddDataToCache(List < Department > departments)
44

          
45
  {
46

          
47
    var memoryCacheEntryOptions = new MemoryCacheEntryOptions();
48

          
49
    memoryCacheEntryOptions.RegisterPostEvictionCallback
50

          
51
    (CacheExpired_Callback);
52

          
53
    memoryCacheEntryOptions.AddExpirationToken(new
54

          
55
      CancellationChangeToken(new
56

          
57
        CancellationTokenSource(TimeSpan.FromSeconds(45)).Token));
58

          
59
    _cache.Set("ABCXYZ", departments, memoryCacheEntryOptions);
60

          
61
  }
62

          
63
  private void CacheExpired_Callback(object key, object value,
64

          
65
    EvictionReason reason, object state)
66

          
67
  {
68

          
69
    var existingDataInCache =
70

          
71
      _cache.Get < List < Department >> ("ABCXYZ");
72

          
73
    if (existingDataInCache == null)
74

          
75
    {
76

          
77
      AddDataToCache(value as List < Department > );
78

          
79
    }
80

          
81
  }
82

          
83
}



Summary

CacheDependency is a great feature in ASP.NET as well as ASP.NET Core. You can take advantage of cache dependency to ensure that the data in the cache is always in sync with that of the database. You can write a callback function that is triggered at fixed intervals of time to fetch data from the database as soon as data in the cache has expired. Alternatively, you can refresh data in the cache after a fixed interval of time irrespective of whether there is data in the cache or the data in the cache is null.

In addition, we used dotConnect for SQL Server, a flexible framework that offers high-performance native SQL Server connectivity, but you can choose whichever alternative works best for you.

ASP.NET Cache (computing) ASP.NET Core Database Dependency injection

Opinions expressed by DZone contributors are their own.

Related

  • Building a RESTful Service Using ASP.NET Core and dotConnect for PostgreSQL
  • Working With dotConnect for Oracle in ASP.NET Core
  • Working With dotConnect for SQL Server in ASP.NET Core
  • Implementing the Repository Pattern Using C# and Entity Developer in ASP.NET Core

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!