6.5 KiB
sidebar_position | title |
---|---|
3 | Creating a data service |
As we previously added the addition of an item, we now have two places in the code in our code where we access our local storage.
In order to simplify the management of our code, we will therefore use the IOC & DI.
In our framework, we are going to use the native IOC of AspNetCore, we are going to use the DI to manage our data.
We have already used the AspNetCore IOC with properties using the [Inject]
attribute, these being managed by the system or external libraries.
Creating the data service interface
We will therefore create a Services
directory at the root of our site and create our interface.
public interface IDataService
{
Task Add(ItemModel model);
Task<int> Count();
Task<List<Item>> List(int currentPage, int pageSize);
}
Our interface contains the methods to manage our data.
Creating the Data Service Implementation
We will now create our class to manage our data locally.
public class DataLocalService : IDataService
{
private readonly HttpClient _http;
private readonly ILocalStorageService _localStorage;
private readonly NavigationManager _navigationManager;
private readonly IWebHostEnvironment _webHostEnvironment;
public DataLocalService(
ILocalStorageService localStorage,
HttpClient http,
IWebHostEnvironment webHostEnvironment,
NavigationManager navigationManager)
{
_localStorage = localStorage;
_http = http;
_webHostEnvironment = webHostEnvironment;
_navigationManager = navigationManager;
}
public async Task Add(ItemModel model)
{
// Get the current data
var currentData = await _localStorage.GetItemAsync<List<Item>>("data");
// Simulate the Id
model.Id = currentData.Max(s => s.Id) + 1;
// Add the item to the current data
currentData.Add(new Item
{
Id = model.Id,
DisplayName = model.DisplayName,
Name = model.Name,
RepairWith = model.RepairWith,
EnchantCategories = model.EnchantCategories,
MaxDurability = model.MaxDurability,
StackSize = model.StackSize,
CreatedDate = DateTime.Now
});
// Save the image
var imagePathInfo = new DirectoryInfo($"{_webHostEnvironment.WebRootPath}/images");
// Check if the folder "images" exist
if (!imagePathInfo.Exists)
{
imagePathInfo.Create();
}
// Determine the image name
var fileName = new FileInfo($"{imagePathInfo}/{model.Name}.png");
// Write the file content
await File.WriteAllBytesAsync(fileName.FullName, model.ImageContent);
// Save the data
await _localStorage.SetItemAsync("data", currentData);
}
public async Task<int> Count()
{
return (await _localStorage.GetItemAsync<Item[]>("data")).Length;
}
public async Task<List<Item>> List(int currentPage, int pageSize)
{
// Load data from the local storage
var currentData = await _localStorage.GetItemAsync<Item[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data
var originalData = await _http.GetFromJsonAsync<Item[]>($"{_navigationManager.BaseUri}fake-data.json");
await _localStorage.SetItemAsync("data", originalData);
}
return (await _localStorage.GetItemAsync<Item[]>("data")).Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
}
}
You will notice that we use another way to inject dependencies into this class through the constructor.
ILocalStorageService
& HttpClient
& IWebHostEnvironment
& NavigationManager
are automatically resolved by the IOC.
Editing Pages
Let's modify our pages to take into account our new service:
public partial class List
{
private List<Item> items;
private int totalItem;
[Inject]
public IDataService DataService { get; set; }
[Inject]
public IWebHostEnvironment WebHostEnvironment { get; set; }
private async Task OnReadData(DataGridReadDataEventArgs<Item> e)
{
if (e.CancellationToken.IsCancellationRequested)
{
return;
}
if (!e.CancellationToken.IsCancellationRequested)
{
items = await DataService.List(e.Page, e.PageSize);
totalItem = await DataService.Count();
}
}
}
public partial class Add
{
/// <summary>
/// The default enchant categories.
/// </summary>
private List<string> enchantCategories = new List<string>() { "armor", "armor_head", "armor_chest", "weapon", "digger", "breakable", "vanishable" };
/// <summary>
/// The current item model
/// </summary>
private ItemModel itemModel = new()
{
EnchantCategories = new List<string>(),
RepairWith = new List<string>()
};
/// <summary>
/// The default repair with.
/// </summary>
private List<string> repairWith = new List<string>() { "oak_planks", "spruce_planks", "birch_planks", "jungle_planks", "acacia_planks", "dark_oak_planks", "crimson_planks", "warped_planks" };
[Inject]
public IDataService DataService { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
private async void HandleValidSubmit()
{
await DataService.Add(itemModel);
NavigationManager.NavigateTo("list");
}
private async Task LoadImage(InputFileChangeEventArgs e)
{
// Set the content of the image to the model
using (var memoryStream = new MemoryStream())
{
await e.File.OpenReadStream().CopyToAsync(memoryStream);
itemModel.ImageContent = memoryStream.ToArray();
}
}
private void OnEnchantCategoriesChange(string item, object checkedValue)
{
if ((bool)checkedValue)
{
if (!itemModel.EnchantCategories.Contains(item))
{
itemModel.EnchantCategories.Add(item);
}
return;
}
if (itemModel.EnchantCategories.Contains(item))
{
itemModel.EnchantCategories.Remove(item);
}
}
private void OnRepairWithChange(string item, object checkedValue)
{
if ((bool)checkedValue)
{
if (!itemModel.RepairWith.Contains(item))
{
itemModel.RepairWith.Add(item);
}
return;
}
if (itemModel.RepairWith.Contains(item))
{
itemModel.RepairWith.Remove(item);
}
}
}
Register the data service
Now we have to define in the IOC of our application the resolution of our interface / class.
Open the Program.cs
file and add the following line:
...
builder.Services.AddScoped<IDataService, DataLocalService>();
...
Later we will implement data management through an API, it will simply be enough to create a new class Services/DataApiService.cs
implementing the interface IDataService
with API calls and modify the IOC with this new service.