Home > Software design >  How to switch repositories from View ASP.NET MVC 6
How to switch repositories from View ASP.NET MVC 6

Time:05-08

I have database and xml repositories. How I can from view switch repositories for application? For example, the view has a select:

<select>
    <option value="xml">XML Storage</option>
    <option value="sqldb">SQL Database</option>
</select>

Program.cs

// builder.Services.AddSingleton<ITaskRepository, TaskRepositoryXML>();
// builder.Services.AddSingleton<ICategoryRepository, CategoryRepositoryXML>();

builder.Services.AddSingleton<ITaskRepository, TaskRepositoryDB>();
builder.Services.AddSingleton<ICategoryRepository, CategoryRepositoryDB>();

You may have some ideas? Thank you!

CodePudding user response:

First of all, you should register your services to use them in runtime, even though you want to have an option to select later on the fly.

A straightforward yet lovely approach is to use a simple Factory pattern. I added implementation for your TaskRepository, but you should do the exact implementation for the CategoryRepository:

public interface ITaskRepository
{
    IEnumerable<string> GetTasks();
}

public class XmlTaskRepository : ITaskRepository
{
    public IEnumerable<string> GetTasks() =>
        new[] { "Task1 from xml", "Task2 from xml" };
}

public class SqlTaskRepository : ITaskRepository
{
    public IEnumerable<string> GetTasks() =>
        new[] { "Task1 from sql", "Task2 from sql" };
}

Now you need a Factory which I implemented a simple version of it for your convenience:

public class TaskRepositoryFactory
{
    public ITaskRepository GetTaskRepository(string userSelection) =>
        userSelection.ToLowerInvariant() switch
        {
            "xml" => new XmlTaskRepository(),
            "sql" => new SqlTaskRepository(),
            _ => throw new ArgumentException(nameof(userSelection))
        };
}

Finally, you have to register your Factory, which I suggest using Scope instead of Singletone (Assuming that your persistence layer is based on EF Core)

builder.Services.AddScoped<TaskRepositoryFactory>();

This is all you need to do for DI. However, for illustration purposes, I added a simple page and injected the factory's concrete class, and switched to the preferred service based on QueryString (Its absurd, but I think enough for presenting the usage)

public class IndexModel : PageModel
{
    private readonly TaskRepositoryFactory _factory;

    public IndexModel(TaskRepositoryFactory factory)
    {
        _factory = factory;
    }

    public List<string> TasksData { get; set; } = new();

    public void OnGet([FromQuery] string selection = "")
    {
        if (!string.IsNullOrEmpty(selection))
        {
            var repo = _factory.GetTaskRepository(selection);
            TasksData = repo.GetTasks().ToList();
        }
    }
}

And razor page has a simple iteration as per below:

@page
@model IndexModel

@foreach (var dt in Model.TasksData)
{
    <span>@dt</span><br />
}

We can resolve all dependencies, yet we can decide which TaskRepository would be instantiated via the help of Factory Pattern.

  • Related