You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
6.5 KiB
252 lines
6.5 KiB
![]()
2 years ago
|
---
|
||
|
sidebar_position: 3
|
||
|
title: 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.
|
||
|
|
||
|
```csharp title="Services/IDataService.cs"
|
||
|
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.
|
||
|
|
||
|
```csharp title="Services/DataLocalService.cs"
|
||
|
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:
|
||
|
|
||
|
```csharp title="Pages/List.razor.cs"
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
```csharp title="Pages/Add.razor.cs"
|
||
|
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:
|
||
|
|
||
|
```csharp title="Program.cs"
|
||
|
...
|
||
|
|
||
|
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.
|