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.