My name is Carl. I am a software engineer and architect. I blog about C#, .NET, Javascript, AngularJS, nodejs, and more. Thanks for visiting!



Buy me a coffeeBuy me a coffee

Tags

Applying The Strategy Pattern To Vary Data Access Methods In C#

The strategy pattern is a design pattern that allows for multiple implementations, or strategies, to be used interchangeably. Below is a diagram of the overall design.



A data access layer can make good use of the strategy pattern because it can abstract out the implementation of the actual data access mechanism from the consumer of the data access layer. The actual data store can be a file, a relational database, an in memory object, or something else. The caller only knows about the actions exposed by the interface. This is no different from any other use of abstraction with one key advantage. The caller can choose which implementation to use at runtime or through dependency injection configuration. This allows the app to use different data access mechanisms without changing the actual application code. For example, an in memory object can be used while a more robust implementation that uses a relational database is being developed. Maybe early on it's not clear what is needed so a simple csv file is used at first and then expanded or changed later or maybe not. In theory, this flexibility is offered without breaking the calling code.

To show this in action I created a simple CRUD web app using a dotnet core mvc project. The source code is available on github. The application keeps track of a list of books.



I created 2 data access strategies for this application. One that uses an in memory object and one that uses a csv file. Here is a class diagram.



The data access project starts with a simple Model to represent a book.


public class Book
{
     public int Id { get; set; }
     public string Title { get; set; }
     public string Author { get; set; }
     public DateTime PublishDate { get; set; }
     public int PageLength { get; set; }
}


The IBookData interface defines the actions.

public interface IBookData
{
     IEnumerable Books { get; }
     Book GetById(int id);
     Book Save(Book b);
     Book DeleteById(int id);
}


There are 2 implementations of the interface. CsvBookData and InMemoryBookData. I am not going to show the implementation details of those here but they can be found in the GitHub repository. The MVC controllers use constructor dependency injection to inject the IBookData dependency. Below is the constructor for the HomeController as an example. There is also an update controller to handle create, update, and delete but the constructors work the same.

// Home Controller
private IBookData _bda;
public HomeController(IBookData b)
{
     _bda = b;
}


This allows me to switch data access strategies by updating one line in the Startup.ConfigureServices method to change which implementation gets instantiated for IBookData, either the in memory option or the csv option.

public void ConfigureServices(IServiceCollection services)
{
     services.AddMvc();
     services.AddTransient<IBookData, InMemoryBookData>();
}


In conclusion, the strategy pattern is straight forward and can be very powerful in adding flexibility to a code base. The strategy pattern works well for a data access layer because there are so many options for data access and it usually changes throughout a project's lifecycle. The full code for this example is available on GitHub.




If you enjoyed this article...

Buy me a coffeeBuy me a coffee



© 2025 Carl Layton Creative Commons License Disclaimer
An unhandled error has occurred. Reload 🗙