---
sidebar_position: 3
title: Création d'un service de données
---

Comme nous avons ajouter précedemment l'ajout d'un item, nous avons maintenant deux endroits dans le code dans notre code ou nous accédons à notre storage local.

Afin de simplifier la gestion de notre code nous allons donc utiliser l'IOC & DI.

Dans notre cadre, nous allons utiliser l'IOC native de AspNetCore, nous allons utiliser la DI pour gérer nos données.

Nous avons déjà utilisé l'IOC d'AspNetCore avec les propriétés utilisant l'attribut `[Inject]`, ceux-ci étant gérés par le système ou des librairies externe.

## Création de l'interface du service de données

Nous allons donc créer un répertoire `Services` à la racine de notre site et créer notre interface.

```csharp title="Services/IDataService.cs"
public interface IDataService
{
	Task Add(ItemModel model);

	Task<int> Count();

	Task<List<Item>> List(int currentPage, int pageSize);
}
```

Notre interface contient les méthodes pour gérer nos données.

## Création de l'implémentation du service de données

Nous allons désormais créer notre classe pour gérer nos données en local.

```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()
	{
		// 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")).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();
	}
}
```

Vous remarquerez que nous utilisons une autre façon d'injecter des dépendances dans cette classe en passant par le constructeur. 
`ILocalStorageService` & `HttpClient` & `IWebHostEnvironment` & `NavigationManager` sont automatiquement résolue par l'IOC.

## Modification des pages

Modifions nos pages pour prendre en compte notre nouveau 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);
		}
	}
}
```

## Définition du service de données

Désormais il faut que nous définitions dans l'IOC de notre application la résolution de notre interface / classe.

Ouvrez le fichier `Program.cs` et ajouter la ligne suivante :

```csharp title="Program.cs"
...

builder.Services.AddScoped<IDataService, DataLocalService>();

...
```

Plus tard nous implémenterons la gestion des données grâce à une API, il suffira simplement de créer une nouvelle classe `Services/DataApiService.cs` implémentant l'interface `IDataService` avec les appels API et de modifier l'IOC avec ce nouveau service.
