+ Swapping to Development environment will display more detailed information about the error that occurred.
+
+
+ The Development environment shouldn't be enabled for deployed applications.
+ It can result in displaying sensitive information from exceptions to end users.
+ For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
+ and restarting the app.
+
+
+@code{
+ [CascadingParameter]
+ private HttpContext? HttpContext { get; set; }
+
+ private string? RequestId { get; set; }
+ private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
+
+ protected override void OnInitialized() =>
+ RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
+}
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/Home.razor b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/Home.razor
new file mode 100644
index 0000000..9992eba
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/Home.razor
@@ -0,0 +1,59 @@
+@page "/"
+@using global::MudBlazor
+
+Home
+
+Hello, world!
+Welcome to your new app, powered by MudBlazor and the .NET 8 Template!
+
+
+ You can find documentation and examples on our website here:
+
+ www.mudblazor.com
+
+
+
+
+Interactivity in this Template
+
+
+ When you opt for the "Global" Interactivity Location,
+ the render modes are defined in App.razor and consequently apply to all child components.
+ In this case, providers are globally set in the MainLayout.
+
+ On the other hand, if you choose the "Per page/component" Interactivity Location,
+ it is necessary to include the
+
+ <MudPopoverProvider />
+ <MudDialogProvider />
+ <MudSnackbarProvider />
+
+ components on every interactive page.
+
+ If a render mode is not specified for a page, it defaults to Server-Side Rendering (SSR),
+ similar to this page. While MudBlazor allows pages to be rendered in SSR,
+ please note that interactive features, such as buttons and dropdown menus, will not be functional.
+
+
+
+What's New in Blazor with the Release of .NET 8
+
+Prerendering
+
+ If you're exploring the features of .NET 8 Blazor, you might be pleasantly surprised to learn that each page is prerendered on the server, regardless of the selected render mode.
+ This means that you'll need to inject all necessary services on the server, even when opting for the wasm (WebAssembly) render mode.
+ This prerendering functionality is crucial to ensuring that WebAssembly mode feels fast and responsive, especially when it comes to initial page load times.
+ For more information on how to detect prerendering and leverage the RenderContext, you can refer to the following link:
+
+ More details
+
+
+
+
+InteractiveAuto
+
+ A discussion on how to achieve this can be found here:
+
+ More details
+
+
\ No newline at end of file
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor
new file mode 100644
index 0000000..a8efc82
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor
@@ -0,0 +1,83 @@
+@page "/productDescription"
+@using System.Text
+@using System.Net.Mime
+@using global::MudBlazor
+@inject IConfiguration Configuration
+
+Product Description
+
+Product Description
+Modify the product descriptions.
+
+
+
+
+
+ Product Description
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@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),
+ };
+
+ 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 Task OnClear()
+ {
+ return dataGrid!.ReloadServerData();
+ }
+
+ private Task OnSearch(string text)
+ {
+
+ return dataGrid!.ReloadServerData();
+ }
+
+}
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Routes.razor b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Routes.razor
new file mode 100644
index 0000000..f756e19
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Routes.razor
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/_Imports.razor b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/_Imports.razor
new file mode 100644
index 0000000..a4312bc
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/_Imports.razor
@@ -0,0 +1,14 @@
+@using System.Net.Http
+@using System.Net.Http.Json
+@using Microsoft.AspNetCore.Components.Forms
+@using Microsoft.AspNetCore.Components.Routing
+@using Microsoft.AspNetCore.Components.Web
+@inject HttpClient httpClient
+@using static Microsoft.AspNetCore.Components.Web.RenderMode
+@using Microsoft.AspNetCore.Components.Web.Virtualization
+@using Microsoft.JSInterop
+@using MudBlazor
+@using AdventureWorksDemo.MudBlazor.Components
+@using AdventureWorksDemo.MudBlazor.Models
+
+@using Microsoft.Extensions.Configuration
\ No newline at end of file
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/PagedList.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/PagedList.cs
new file mode 100644
index 0000000..9026807
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/PagedList.cs
@@ -0,0 +1,32 @@
+namespace AdventureWorksDemo.MudBlazor.Models
+{
+ public class PagedList
+ {
+ public int CurrentPage { get; set; }
+ public int PageSize { get; set; }
+ public int TotalCount { get; set; }
+ public int TotalPages { get; set; }
+
+ public static PagedList FromIEnumerable(string? value)
+ {
+ if (value == null)
+ return new PagedList();
+ var values = value!.Split(',');
+ return new PagedList()
+ {
+ CurrentPage = PagedList.ExtractValue(values, nameof(CurrentPage)),
+ PageSize = PagedList.ExtractValue(values, nameof(PageSize)),
+ TotalCount = PagedList.ExtractValue(values, nameof(TotalCount)),
+ TotalPages = PagedList.ExtractValue(values, nameof(TotalPages)),
+ }
+ ;
+ }
+
+ private static int ExtractValue(string[] values, string key)
+ {
+ string? extracted = values.SingleOrDefault(m => m.Contains(key, StringComparison.CurrentCultureIgnoreCase))?.Split(':')[1].Replace('}', ' ');
+
+ return int.Parse(extracted ?? "0");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/PageingFilter.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/PageingFilter.cs
new file mode 100644
index 0000000..f24a0ec
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/PageingFilter.cs
@@ -0,0 +1,52 @@
+using MudBlazor;
+
+namespace AdventureWorksDemo.MudBlazor.Models
+{
+ public class PageingFilter
+ {
+ public string[] Filter { get; set; } = [];
+
+ ///
+ /// PageNumber is zero based
+ ///
+ public int PageNumber { get; set; } = 1;
+
+ public int PageSize { get; set; } = 25;
+ public string[] Sorting { get; set; } = [];
+
+ public static PageingFilter SetByGridState(GridState state, string defaultSorting)
+ {
+ var filters = state.FilterDefinitions;
+ var filterArray = (from IFilterDefinition filter in filters
+ select $"{filter!.Column!.PropertyName} | {filter.Operator} | {filter.Value}").ToArray();
+
+ return new PageingFilter()
+ {
+ PageNumber = state.Page,
+ PageSize = state.PageSize,
+ Filter = filterArray,
+ Sorting = SortingArray(state.SortDefinitions, defaultSorting),
+ };
+ }
+ internal string ToJSON()
+ {
+ return System.Text.Json.JsonSerializer.Serialize(this);
+ }
+ private static string DescendingText(bool isDescending) => isDescending ? "DESC" : "ASC";
+
+ private static string[] SortingArray(ICollection>? sortDefinitions, string defaultSorting )
+ {
+ if (sortDefinitions == null || sortDefinitions.Count == 0)
+ {
+ if (string.IsNullOrEmpty(defaultSorting))
+ throw new ArgumentOutOfRangeException(nameof(defaultSorting));
+ else
+ return [defaultSorting.Trim()];
+ }
+
+ return (from m in sortDefinitions
+ select $"{m.SortBy} {DescendingText(m.Descending)}"
+ ).ToArray() ;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/ProductDescriptionModel.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/ProductDescriptionModel.cs
new file mode 100644
index 0000000..11f884a
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Models/ProductDescriptionModel.cs
@@ -0,0 +1,17 @@
+namespace AdventureWorksDemo.MudBlazor.Models
+{
+ public record ProductDescriptionModel
+ {
+ public string? Description { get; set; }
+
+ ///
+ /// Date and time the record was last updated.
+ ///
+ public DateTime ModifiedDate { get; set; }
+
+ ///
+ /// Primary key for ProductDescription records.
+ ///
+ public int ProductDescriptionId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs
new file mode 100644
index 0000000..193d1e0
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs
@@ -0,0 +1,47 @@
+using AdventureWorksDemo.MudBlazor.Components;
+
+using MudBlazor.Services;
+
+namespace AdventureWorksDemo.MudBlazor
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Add MudBlazor services
+ builder.Services.AddMudServices();
+
+ // Add services to the container.
+ builder.Services.AddRazorComponents()
+ .AddInteractiveServerComponents()
+ .Services.AddHttpClient();
+ // Add services
+ builder.Services.AddScoped(sp => new HttpClient
+ {
+ BaseAddress = new Uri(builder.Configuration["Api:Base"] ?? "")
+ });
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ if (!app.Environment.IsDevelopment())
+ {
+ app.UseExceptionHandler("/Error");
+ // The default HSTS value is 30 days. You may want to change this for production
+ // scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
+ }
+
+ app.UseHttpsRedirection();
+
+ app.UseStaticFiles();
+ app.UseAntiforgery();
+
+ app.MapRazorComponents()
+ .AddInteractiveServerRenderMode();
+
+ app.Run();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/appsettings.Development.json b/src/FrontEnd/AdventureWorksDemo.MudBlazor/appsettings.Development.json
new file mode 100644
index 0000000..b49edf4
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/appsettings.Development.json
@@ -0,0 +1,15 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "Api": {
+ "Base": "https://localhost:7277/api/",
+ "Address": "address",
+ "ProductCategory": "productcategory",
+ "ProductDescription": "productdescription"
+ },
+ "Paging": { "PageCount": 25 }
+}
\ No newline at end of file
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/appsettings.json b/src/FrontEnd/AdventureWorksDemo.MudBlazor/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/wwwroot/favicon.ico b/src/FrontEnd/AdventureWorksDemo.MudBlazor/wwwroot/favicon.ico
new file mode 100644
index 0000000..1239223
Binary files /dev/null and b/src/FrontEnd/AdventureWorksDemo.MudBlazor/wwwroot/favicon.ico differ