diff --git a/src/AdventureWorksDemo.MudBlazor.Tests/AdventureWorksDemo.MudBlazor.Tests.csproj b/src/AdventureWorksDemo.MudBlazor.Tests/AdventureWorksDemo.MudBlazor.Tests.csproj
new file mode 100644
index 0000000..1493528
--- /dev/null
+++ b/src/AdventureWorksDemo.MudBlazor.Tests/AdventureWorksDemo.MudBlazor.Tests.csproj
@@ -0,0 +1,54 @@
+
+
+
+ net9.0
+ latest
+ enable
+ enable
+
+ true
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AdventureWorksDemo.MudBlazor.Tests/CommonResponseGetTests.cs b/src/AdventureWorksDemo.MudBlazor.Tests/CommonResponseGetTests.cs
new file mode 100644
index 0000000..71f3c0f
--- /dev/null
+++ b/src/AdventureWorksDemo.MudBlazor.Tests/CommonResponseGetTests.cs
@@ -0,0 +1,92 @@
+using System.Net;
+using System.Text.Json;
+
+using AdventureWorksDemo.MudBlazor.Common;
+
+using Moq;
+using Moq.Protected;
+
+using MudBlazor;
+
+namespace AdventureWorksDemo.MudBlazor.Tests
+{
+ [TestClass]
+ public sealed class CommonResponseGetTests
+ {
+ private HttpClient? _httpClient;
+ private Mock? _mockHttpHandler;
+ private Mock? _mockUrl;
+ private CommonResponseGet? _service;
+
+ [TestMethod]
+ public async Task FindAllAsync_ReturnsDataOnSuccess()
+ {
+ // Arrange
+ var testData = new List
+ {
+ new() { Id = 1, Name = "Test1" },
+ new() { Id = 2, Name = "Test2" }
+ };
+
+ var jsonResponse = JsonSerializer.Serialize(testData);
+ var httpResponse = new HttpResponseMessage
+ {
+ StatusCode = HttpStatusCode.OK,
+ Content = new StringContent(jsonResponse, System.Text.Encoding.UTF8, "application/json")
+ };
+ httpResponse.Headers.Add("X-Pagination", "CurrentPage:1,PageSize:25,TotalCount:50,TotalPages:2");
+
+ _mockHttpHandler!.Protected()
+ .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny())
+ .ReturnsAsync(httpResponse);
+
+ var gridState = new GridState { Page = 0, PageSize = 25 };
+
+ // Act
+ var result = await _service!.FindAllAsync(gridState, "Id ASC", _httpClient!);
+
+ // Assert
+ Assert.AreEqual(50, result.TotalItems);
+ Assert.AreEqual(2, result.Items.Count());
+ Assert.AreEqual("Test1", result.Items.First().Name);
+ }
+
+ [TestMethod]
+ public async Task FindAllAsync_ReturnsEmptyDataOnFailure()
+ {
+ // Arrange
+ var httpResponse = new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest };
+
+ _mockHttpHandler!.Protected()
+ .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny())
+ .ReturnsAsync(httpResponse);
+
+ var gridState = new GridState { Page = 0, PageSize = 25 };
+
+ // Act
+ var result = await _service!.FindAllAsync(gridState, "Id ASC", _httpClient!);
+
+ // Assert
+ Assert.AreEqual(0, result.TotalItems);
+ Assert.AreEqual(0, result.Items.Count());
+ }
+
+ [TestInitialize]
+ public void Setup()
+ {
+ _mockUrl = new Mock();
+ _mockUrl.Setup(u => u.Administration_ProductDescription).Returns("https://api.example.com/productdescription");
+
+ _mockHttpHandler = new Mock();
+ _httpClient = new HttpClient(_mockHttpHandler.Object);
+
+ _service = new CommonResponseGet(_mockUrl.Object);
+ }
+
+ private class TestModel
+ {
+ public int Id { get; set; }
+ public string? Name { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AdventureWorksDemo.MudBlazor.Tests/MSTestSettings.cs b/src/AdventureWorksDemo.MudBlazor.Tests/MSTestSettings.cs
new file mode 100644
index 0000000..aaf278c
--- /dev/null
+++ b/src/AdventureWorksDemo.MudBlazor.Tests/MSTestSettings.cs
@@ -0,0 +1 @@
+[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
diff --git a/src/AdventureWorksDemo.sln b/src/AdventureWorksDemo.sln
index dc3ccbf..7ebc3d7 100644
--- a/src/AdventureWorksDemo.sln
+++ b/src/AdventureWorksDemo.sln
@@ -30,6 +30,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdventureWorksDemo.Data.Tes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdventureWorksDemo.MudBlazor", "FrontEnd\AdventureWorksDemo.MudBlazor\AdventureWorksDemo.MudBlazor.csproj", "{C4D0ABE5-0E84-4112-B4C7-3067B23A2F26}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{56ED2B2C-32A6-4251-A025-22CD1DC336FA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdventureWorksDemo.MudBlazor.Tests", "AdventureWorksDemo.MudBlazor.Tests\AdventureWorksDemo.MudBlazor.Tests.csproj", "{27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -64,6 +68,10 @@ Global
{C4D0ABE5-0E84-4112-B4C7-3067B23A2F26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4D0ABE5-0E84-4112-B4C7-3067B23A2F26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4D0ABE5-0E84-4112-B4C7-3067B23A2F26}.Release|Any CPU.Build.0 = Release|Any CPU
+ {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -77,6 +85,8 @@ Global
{8F4D9C82-7600-48A8-B8D0-19BF96DDE28C} = {9D6855CA-A743-45EC-BB4B-8BDE8A160DBD}
{AA4A04F0-04B2-46BF-917D-6B4E40CB56BF} = {9D6855CA-A743-45EC-BB4B-8BDE8A160DBD}
{C4D0ABE5-0E84-4112-B4C7-3067B23A2F26} = {B922BF81-0D47-41E8-BDC8-37C09BFA6167}
+ {56ED2B2C-32A6-4251-A025-22CD1DC336FA} = {B922BF81-0D47-41E8-BDC8-37C09BFA6167}
+ {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07} = {56ED2B2C-32A6-4251-A025-22CD1DC336FA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6B392A9A-E58C-44EB-BA80-051A0183B5DE}
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/CommonResponseGet.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/CommonResponseGet.cs
new file mode 100644
index 0000000..01d9ee5
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/CommonResponseGet.cs
@@ -0,0 +1,47 @@
+using System.Net.Mime;
+using System.Text;
+
+using AdventureWorksDemo.MudBlazor.Models;
+
+using MudBlazor;
+
+namespace AdventureWorksDemo.MudBlazor.Common
+{
+ public interface ICommonResponseGet
+ {
+ Task> FindAllAsync(GridState state, string defaultSorting, HttpClient httpClient);
+ }
+
+ public class CommonResponseGet(IUrl Url) : ICommonResponseGet
+ {
+ public async Task> FindAllAsync(GridState state, string defaultSorting, HttpClient httpClient)
+ {
+ PageingFilter filter = PageingFilter.SetByGridState(state, defaultSorting);
+
+ var request = new HttpRequestMessage
+ {
+ Method = HttpMethod.Get,
+ RequestUri = new Uri(Url.Administration_ProductDescription),
+ Content = new StringContent(filter.ToJSON(),
+ Encoding.UTF8,
+ MediaTypeNames.Application.Json),
+ };
+
+ PagedList paging = new();
+ IEnumerable data = [];
+
+ var response = await httpClient.SendAsync(request).ConfigureAwait(false);
+ if (response.IsSuccessStatusCode)
+ {
+ data = (await response!.Content!.ReadFromJsonAsync>()) ?? [];
+ paging = PagedList.FromIEnumerable(response.Headers.GetValues("X-Pagination").SingleOrDefault());
+ }
+
+ return new GridData
+ {
+ TotalItems = paging.TotalCount,
+ Items = data,
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/Url.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/Url.cs
new file mode 100644
index 0000000..3634fd6
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/Url.cs
@@ -0,0 +1,11 @@
+namespace AdventureWorksDemo.MudBlazor.Common
+{
+ public interface IUrl
+ {
+ string Administration_ProductDescription { get; }
+ }
+ public class Url(IConfiguration configuration) : IUrl
+ {
+ public string Administration_ProductDescription => $"{configuration["Api:base"]}{configuration["Api:productdescription"]}";
+ }
+}
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor
index a8efc82..1990f28 100644
--- a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor
@@ -2,18 +2,19 @@
@using System.Text
@using System.Net.Mime
@using global::MudBlazor
-@inject IConfiguration Configuration
+@inject Common.ICommonResponseGet response
Product Description
Product Description
Modify the product descriptions.
-
@@ -21,52 +22,28 @@ Filterable="true"
-
+
-
-
-
+
+
+
+
-
-
+
+
@code {
-
- public MudDataGrid? dataGrid ;
-
-
- private async Task> ServerReload(GridState state)
- {
- PagedList paging = new();
- IEnumerable data = new List();
- PageingFilter filter = PageingFilter.SetByGridState(state, "Description");
- string url = $"{Configuration["Api:base"]}{Configuration["Api:productdescription"]}";
- var request = new HttpRequestMessage
- {
- Method= HttpMethod.Get,
- RequestUri = new Uri(url),
- Content = new StringContent(filter.ToJSON(),
- Encoding.UTF8,
- MediaTypeNames.Application.Json),
- };
+ private MudDataGrid? dataGrid ;
- var response = await httpClient.SendAsync(request).ConfigureAwait(false);
- if (response.IsSuccessStatusCode)
- {
- data = (await response!.Content!.ReadFromJsonAsync>()) ?? new ();
- paging = PagedList.FromIEnumerable(response.Headers.GetValues("X-Pagination").SingleOrDefault());
- }
- return new GridData
- {
- TotalItems = paging.TotalCount,
- Items = data,
- };
+ private async Task> ServerReload(GridState state)
+ {
+ return await response.FindAllAsync(state, "Description", httpClient);
}
private Task OnClear()
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs
index 193d1e0..37a9237 100644
--- a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs
@@ -1,3 +1,4 @@
+using AdventureWorksDemo.MudBlazor.Common;
using AdventureWorksDemo.MudBlazor.Components;
using MudBlazor.Services;
@@ -22,6 +23,9 @@ public static void Main(string[] args)
{
BaseAddress = new Uri(builder.Configuration["Api:Base"] ?? "")
});
+ builder.Services.AddSingleton(typeof(IUrl), typeof(Url));
+ builder.Services.AddScoped(typeof(ICommonResponseGet), typeof(CommonResponseGet));
+
var app = builder.Build();
// Configure the HTTP request pipeline.