diff --git a/DeepDrftPublic.Client/Pages/TracksView.razor.cs b/DeepDrftPublic.Client/Pages/TracksView.razor.cs index 59357b2..b6701ff 100644 --- a/DeepDrftPublic.Client/Pages/TracksView.razor.cs +++ b/DeepDrftPublic.Client/Pages/TracksView.razor.cs @@ -38,7 +38,7 @@ public partial class TracksView : ComponentBase private async Task SetPage(int newPage) { - var result = await ViewModel.TrackClient.GetPage(newPage, ViewModel.PageSize, ViewModel.SortBy, ViewModel.IsDescending); + var result = await ViewModel.TrackData.GetPage(newPage, ViewModel.PageSize, ViewModel.SortBy, ViewModel.IsDescending); if (result is { Success: true, Value: PagedResult pageResult }) { diff --git a/DeepDrftPublic.Client/Services/ITrackDataService.cs b/DeepDrftPublic.Client/Services/ITrackDataService.cs new file mode 100644 index 0000000..9c715e4 --- /dev/null +++ b/DeepDrftPublic.Client/Services/ITrackDataService.cs @@ -0,0 +1,25 @@ +using DeepDrftModels.Entities; +using Models.Common; +using NetBlocks.Models; + +namespace DeepDrftPublic.Client.Services; + +/// +/// Track metadata fetch abstraction with two render-mode-specific implementations: +/// +/// - Server prerender pass: TrackDirectDataService in the DeepDrftPublic host +/// resolves in-process (EF Core / SQL) and +/// avoids a loopback HTTP hop. +/// - WASM interactive pass: TrackClientDataService in this assembly delegates +/// to over HTTP. +/// +/// Components inject this single seam so they do not branch on render mode. +/// +public interface ITrackDataService +{ + Task>> GetPage( + int pageNumber, + int pageSize, + string? sortColumn = null, + bool sortDescending = false); +} diff --git a/DeepDrftPublic.Client/Services/TrackClientDataService.cs b/DeepDrftPublic.Client/Services/TrackClientDataService.cs new file mode 100644 index 0000000..70e1fa2 --- /dev/null +++ b/DeepDrftPublic.Client/Services/TrackClientDataService.cs @@ -0,0 +1,28 @@ +using DeepDrftModels.Entities; +using DeepDrftPublic.Client.Clients; +using Models.Common; +using NetBlocks.Models; + +namespace DeepDrftPublic.Client.Services; + +/// +/// WASM-side that delegates to +/// (HTTP to the DeepDrft.API backend). Used on the WASM interactive render pass; +/// the server prerender pass swaps in a direct, in-process implementation. +/// +public class TrackClientDataService : ITrackDataService +{ + private readonly TrackClient _trackClient; + + public TrackClientDataService(TrackClient trackClient) + { + _trackClient = trackClient; + } + + public Task>> GetPage( + int pageNumber, + int pageSize, + string? sortColumn = null, + bool sortDescending = false) + => _trackClient.GetPage(pageNumber, pageSize, sortColumn, sortDescending); +} diff --git a/DeepDrftPublic.Client/Startup.cs b/DeepDrftPublic.Client/Startup.cs index cf8fbe6..0858ad7 100644 --- a/DeepDrftPublic.Client/Startup.cs +++ b/DeepDrftPublic.Client/Startup.cs @@ -14,8 +14,11 @@ public static class Startup services.AddScoped(); services.AddScoped(); - // Track Client + // Track Client. The HTTP-backed ITrackDataService registration here is the WASM + // default; the server host overrides it with an in-process implementation after + // this method runs, so SSR prerender skips the loopback hop. services.AddScoped(); + services.AddScoped(); services.AddScoped(); } diff --git a/DeepDrftPublic.Client/ViewModels/TracksViewModel.cs b/DeepDrftPublic.Client/ViewModels/TracksViewModel.cs index 32b0c6c..a68b46e 100644 --- a/DeepDrftPublic.Client/ViewModels/TracksViewModel.cs +++ b/DeepDrftPublic.Client/ViewModels/TracksViewModel.cs @@ -1,14 +1,13 @@ -using DeepDrftModels.Entities; -using DeepDrftPublic.Client.Clients; +using DeepDrftModels.Entities; +using DeepDrftPublic.Client.Services; using Models.Common; namespace DeepDrftPublic.Client.ViewModels; public class TracksViewModel { - public TrackClient TrackClient { get; } + public ITrackDataService TrackData { get; } - // private int _pageNumber = 1; public int PageNumber { get; set; } = 1; public int PageSize @@ -26,9 +25,9 @@ public class TracksViewModel public string SortBy { get; set; } = string.Empty; public bool IsDescending { get; set; } = false; public PagedResult? Page { get; set; } = null; - - public TracksViewModel(TrackClient trackClient) + + public TracksViewModel(ITrackDataService trackData) { - TrackClient = trackClient; + TrackData = trackData; } -} \ No newline at end of file +} diff --git a/DeepDrftPublic/Services/TrackDirectDataService.cs b/DeepDrftPublic/Services/TrackDirectDataService.cs new file mode 100644 index 0000000..e97107e --- /dev/null +++ b/DeepDrftPublic/Services/TrackDirectDataService.cs @@ -0,0 +1,33 @@ +using DeepDrftData; +using DeepDrftModels.Entities; +using DeepDrftPublic.Client.Services; +using Models.Common; +using NetBlocks.Models; + +namespace DeepDrftPublic.Services; + +/// +/// Server-side that calls +/// in-process (EF Core / SQL). Replaces the loopback HTTP hop during SSR prerender: +/// the WASM interactive pass still uses +/// over HTTP, but on the server we already have the domain service in DI. +/// +public class TrackDirectDataService : ITrackDataService +{ + private readonly ITrackService _trackService; + + public TrackDirectDataService(ITrackService trackService) + { + _trackService = trackService; + } + + public async Task>> GetPage( + int pageNumber, + int pageSize, + string? sortColumn = null, + bool sortDescending = false) + { + var result = await _trackService.GetPaged(pageNumber, pageSize, sortColumn, sortDescending); + return ApiResult>.From(result); + } +} diff --git a/DeepDrftPublic/Startup.cs b/DeepDrftPublic/Startup.cs index 703e62f..61ca8cf 100644 --- a/DeepDrftPublic/Startup.cs +++ b/DeepDrftPublic/Startup.cs @@ -1,6 +1,7 @@ using DeepDrftData; using DeepDrftData.Data; using DeepDrftData.Repositories; +using DeepDrftPublic.Client.Services; using DeepDrftPublic.Services; // DarkModeService namespace (within this host project) using Microsoft.EntityFrameworkCore; @@ -28,6 +29,11 @@ public static class Startup .AddScoped() .AddScoped() .AddScoped(sp => sp.GetRequiredService()); + + // Override the WASM HTTP-backed ITrackDataService (registered earlier by + // DeepDrftPublic.Client.Startup.ConfigureDomainServices) with an in-process + // adapter for SSR prerender. Last registration wins for single-resolution. + builder.Services.AddScoped(); } public static string GetKestrelUrl(this WebApplicationBuilder builder)