Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9e49791
Upgrade BlazorWasmRegex.Shared to .NET 10.0
MichaelSL Dec 3, 2025
1fa8db7
Upgrade BlazorWasmRegex.Client to .NET 10.0 and migrate to Blazored.L…
MichaelSL Dec 3, 2025
cd15d8d
Upgrade BlazorWasmRegex.Server to .NET 10.0 and migrate to minimal ho…
MichaelSL Dec 3, 2025
0fdad61
Upgrade build project to .NET 10.0 and Nuke.Common 8.1.2
MichaelSL Dec 3, 2025
88b2f28
Remove unnecessary System.Net.Http.Json package reference
MichaelSL Dec 3, 2025
a81b770
Add upgrade execution report
MichaelSL Dec 3, 2025
616bf53
Fix root component selector and remove obsolete Cloudcrate script ref…
MichaelSL Dec 3, 2025
13087d2
Fix BlazorStrap v5 script loading and async button click handler
MichaelSL Dec 3, 2025
d18588d
Add Blazor WASM Regex Tester documentation and update component refer…
MichaelSL Dec 3, 2025
5ec183b
Ensure RegexText and Tests are initialized to empty strings if local …
MichaelSL Dec 3, 2025
37869f5
Refactor build schema and add test project for RegexService with .NET…
MichaelSL Dec 3, 2025
ebecfc5
Filter out empty matches in regex results and update message display
MichaelSL Dec 3, 2025
532c07f
Add support for regex options: Ignore Case, Multiline, and Singleline
MichaelSL Dec 3, 2025
980a902
Persist regex options in local storage and initialize on load
MichaelSL Dec 3, 2025
53f8c86
Add regex timeout handling and update Regex constructor to accept tim…
MichaelSL Dec 3, 2025
b84aba8
Enhance performance by optimizing string handling in HtmlHelperServic…
MichaelSL Dec 3, 2025
8b2fc94
Add capture groups display in RegexTester with extraction logic
MichaelSL Dec 3, 2025
2ce564c
Filter out empty matches and refine split results in RegexTester and …
MichaelSL Dec 3, 2025
104e09d
Add sample regex patterns and implement sample selection in RegexTester
MichaelSL Dec 3, 2025
8c645d6
Implement replace functionality and export features in RegexTester
MichaelSL Dec 3, 2025
3e74cdb
Upgrade workflow to use .NET 10 and update runner to ubuntu-latest
MichaelSL Dec 3, 2025
35d265f
Refactor Docker build process to use GitHub Container Registry and up…
MichaelSL Dec 3, 2025
59540c9
Initial plan
Copilot Dec 3, 2025
2e4680f
Fix service worker to only unregister in development mode
Copilot Dec 3, 2025
79723ba
Add error handling to service worker registration
Copilot Dec 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Blazor WASM Regex Tester - AI Agent Instructions

## Project Overview
This is a Blazor WebAssembly application that runs a regex tester entirely in the browser. It uses the ASP.NET Core hosted model with three projects: Client (WASM), Server (host), and Shared (common code/services).

**Live Demo**: https://dotnet-regex.com/
**Key Characteristic**: All regex processing happens client-side in WebAssembly - the server only hosts static files.

## Architecture

### Project Structure
```
BlazorWasmRegex/
├── Client/ # Blazor WASM app (runs in browser)
├── Server/ # ASP.NET Core host (serves static files)
└── Shared/ # Shared interfaces and services
```

### Service Pattern
The codebase uses a **shared service pattern** where services are defined in `Shared/` and used by both Client and Server:

- **Interfaces**: Define contracts in `Shared/Interfaces/` (e.g., `IRegexService`, `IHtmlHelperService`)
- **Implementations**: Implement in `Shared/Services/` (e.g., `RegexService`, `HtmlHelperService`)
- **Registration**: Services are registered in `Client/Program.cs` using `AddTransient` for DI

Example from [Client/Program.cs](BlazorWasmRegex/Client/Program.cs):
```csharp
services.AddTransient<IRegexService, RegexService>();
services.AddTransient<IHtmlHelperService, HtmlHelperService>();
```

### Key Components
- **RegexTester.razor**: Main component handling regex testing UI and logic
- **RegexService**: Executes regex operations (matches, splits) with timing
- **HtmlHelperService**: Generates HTML-safe markup with highlighting (using `WebUtility.HtmlEncode`)

## Development Workflows

### Building & Running
```bash
# Standard build (from repo root)
dotnet build

# Run server (serves WASM app)
dotnet run --project BlazorWasmRegex/Server/BlazorWasmRegex.Server.csproj

# Using NUKE build system
./build.sh Compile # Linux/Mac
./build.cmd Compile # Windows
```

### NUKE Build System
This project uses **NUKE** for advanced build automation ([build/Build.cs](build/Build.cs)):

Key targets:
- `Compile`: Standard build
- `Publish`: Publishes to `.artifacts/publish/`
- `SetVersion`: Injects version from `Directory.build.props.template` (replaces `$ver` placeholder)
- `BuildDockerContainer` / `BuildArmDockerContainer`: Build Docker images
- `InsertCounterCode`: Injects analytics code at `<!-- Web Counter here -->` placeholder in `index.html`

**Version Management**: Versions are generated dynamically: `{Year}.{Month}.{Day}.{BuildNumber}` from `GITHUB_RUN_NUMBER` env var.

### Docker Deployment
Two Dockerfiles for multi-arch support:
- `Dockerfile`: x64 builds (uses .NET 7 Alpine images)
- `Dockerfile-Arm`: ARM builds

**Important**: `Directory.Build.props` is dynamically generated during build - never edit it directly. Modify `Directory.build.props.template` instead.

## Code Conventions

### Blazor Component Patterns
1. **State Persistence**: Uses `Blazored.LocalStorage` to persist regex and test inputs between sessions
- Keys: `REGEX_SESSION_STORAGE_KEY`, `TESTS_SESSION_STORAGE_KEY`

2. **Regex Caching**: Compiles regex once and reuses (`prevRegexText` tracking prevents recompilation)

3. **Error Handling**: Catches both `RegexParseException` (modern) and `ArgumentException` (fallback) for regex parsing

4. **HTML Safety**: Always use `WebUtility.HtmlEncode` when displaying user input in markup (see `HtmlHelperService`)

### UI Framework
- **BlazorStrap**: Bootstrap components (e.g., `<BSButton>`, `<BSTabGroup>`)
- **Open Iconic**: Icon font (e.g., `oi oi-beaker`, `oi oi-terminal`)

### Target Framework
Currently targeting **net10.0** (.NET 10) across all projects - check project files when adding dependencies.

## Integration Points

### Service Worker (PWA)
The app is a Progressive Web App with offline support:
- `service-worker.js`: Development service worker
- `service-worker.published.js`: Production version (NUKE build appends timestamp for cache busting)

### External Dependencies
- **BlazorStrap** (v5.2.0): Bootstrap UI components
- **Blazored.LocalStorage** (v4.5.0): Browser storage API

## Common Tasks

### Adding a New Service
1. Define interface in `Shared/Interfaces/I{ServiceName}.cs`
2. Implement in `Shared/Services/{ServiceName}.cs`
3. Register in `Client/Program.cs` ConfigureServices method
4. Inject via `@inject` directive in Razor components

### Modifying Regex Logic
Edit [RegexService.cs](BlazorWasmRegex/Shared/Services/RegexService.cs) - methods return tuples including timing data for performance display.

### UI Changes
Main UI is in [RegexTester.razor](BlazorWasmRegex/Client/Shared/RegexTester.razor) - uses three tabs: Matches, Split list, and Table view.

## Testing
Currently **no automated tests** exist (see `Build.cs` Test target).

**Planned**: Implement automated tests in a new `tests/` directory following the solution structure. When adding tests, consider:
- Unit tests for `RegexService` and `HtmlHelperService`
- Component tests for `RegexTester.razor`
- Integration tests for the full regex workflow

## Future Development
- **Testing Infrastructure**: Add comprehensive test coverage (unit, component, and integration tests)
- **UI/UX Enhancements**: Build a more robust regex tester interface with improved usability and features

## Local Development
This is a **test/demo application** intended for local development. The build system includes Docker and CI/CD features, but primary development is done locally using `dotnet build` and `dotnet run`.
89 changes: 89 additions & 0 deletions .github/upgrades/execution_log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# .NET 10.0 Upgrade Report

## Project target framework modifications

| Project name | Old Target Framework | New Target Framework | Commits |
|:--------------------------------------|:--------------------:|:--------------------:|-----------------|
| BlazorWasmRegex.Shared.csproj | net7.0 | net10.0 | 9e49791 |
| BlazorWasmRegex.Client.csproj | net7.0 | net10.0 | 1fa8db7, 88b2f28|
| BlazorWasmRegex.Server.csproj | net7.0 | net10.0 | cd15d8d |
| _build.csproj | net7.0 | net10.0 | 0fdad61 |

## NuGet Packages

| Package Name | Old Version | New Version | Commit ID |
|:------------------------------------------------------|:-----------:|:-----------:|-----------|
| Blazored.LocalStorage | - | 4.5.0 | 1fa8db7 |
| BlazorStrap | 1.5.1 | 5.2.100 | 1fa8db7 |
| Cloudcrate.AspNetCore.Blazor.Browser.Storage | 3.0.0 | (removed) | 1fa8db7 |
| Microsoft.AspNetCore.Components.WebAssembly | 7.0.0 | 10.0.0 | 1fa8db7 |
| Microsoft.AspNetCore.Components.WebAssembly.DevServer | 7.0.0 | 10.0.0 | 1fa8db7 |
| Microsoft.AspNetCore.Components.WebAssembly.Server | 7.0.0 | 10.0.0 | cd15d8d |
| Microsoft.VisualStudio.Azure.Containers.Tools.Targets | 1.17.0 | 1.21.0 | cd15d8d |
| Nuke.Common | 6.2.1 | 8.1.2 | 0fdad61 |
| System.Net.Http.Json | 7.0.0 | (removed) | 88b2f28 |

## All commits

| Commit ID | Description |
|:----------|:---------------------------------------------------------------|
| 9e49791 | Upgrade BlazorWasmRegex.Shared to .NET 10.0 |
| 1fa8db7 | Upgrade BlazorWasmRegex.Client to .NET 10.0 and migrate to Blazored.LocalStorage |
| cd15d8d | Upgrade BlazorWasmRegex.Server to .NET 10.0 and migrate to minimal hosting model |
| 0fdad61 | Upgrade build project to .NET 10.0 and Nuke.Common 8.1.2 |
| 88b2f28 | Remove unnecessary System.Net.Http.Json package reference |

## Project feature upgrades

### BlazorWasmRegex.Client

Here is what changed for the project during upgrade:

- **Storage API Migration**: Replaced deprecated `Cloudcrate.AspNetCore.Blazor.Browser.Storage` with `Blazored.LocalStorage`
- Updated `SessionStorage` to `ILocalStorageService` in RegexTester.razor
- Changed synchronous `SetItem`/`GetItemAsync` calls to async `SetItemAsync`/`GetItemAsync<T>`
- Updated method signatures to support async/await pattern

- **BlazorStrap v5 Upgrade**: Updated from BlazorStrap 1.5.1 to 5.2.100
- Replaced `AddBootstrapCss()` with `AddBlazorStrap()` in service configuration
- Removed `IBootstrapCss` dependency from MainLayout.razor

- **Root Component Registration**: Updated to .NET 10.0 syntax
- Changed from `builder.RootComponents.Add<App>("app")` to `builder.RootComponents.Add<App>("#app")`

### BlazorWasmRegex.Server

Here is what changed for this project during upgrade:

- **Minimal Hosting Model Migration**: Converted from Startup.cs pattern to minimal hosting
- Consolidated all configuration from Startup.cs into Program.cs
- Removed Startup.cs file completely
- Updated to use top-level statements and WebApplication builder pattern
- Migrated middleware configuration to use `app.Map*` methods instead of `endpoints.Map*`

### build (_build.csproj)

Here is what changed for this project during upgrade:

- **Nuke.Common v8 Compatibility**: Updated to support breaking changes
- Removed obsolete `[CheckBuildProjectConfigurations]` attribute
- Build warnings indicate deprecated methods (DeleteDirectory, EnsureCleanDirectory) that can be updated to new extension methods in future

## Summary

The upgrade to .NET 10.0 was completed successfully for all four projects in the solution:

✅ **BlazorWasmRegex.Shared** - Straightforward framework upgrade
✅ **BlazorWasmRegex.Client** - Framework upgrade + package migrations + API updates
✅ **BlazorWasmRegex.Server** - Framework upgrade + minimal hosting migration
✅ **build** - Framework upgrade + Nuke.Common v8 compatibility

All projects build successfully with only minor warnings about BlazorStrap version resolution (5.2.100 resolved instead of 5.2.0) and some Razor component naming warnings which are cosmetic.

## Next steps

- Consider testing the application thoroughly to ensure all runtime functionality works as expected
- The BlazorStrap component warnings can be addressed by adding explicit component registrations if needed
- Review and test local storage functionality since the API was changed from Cloudcrate to Blazored
- Consider updating the deprecated Nuke file system methods to their new extension method equivalents
- Test the Docker build process since the Dockerfile references were maintained but not tested during upgrade
78 changes: 78 additions & 0 deletions .github/upgrades/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# .NET 10.0 Upgrade Plan

## Execution Steps

Execute steps below sequentially one by one in the order they are listed.

1. Validate that a .NET 10.0 SDK required for this upgrade is installed on the machine and if not, help to get it installed.
2. Upgrade BlazorWasmRegex/Shared/BlazorWasmRegex.Shared.csproj
3. Upgrade BlazorWasmRegex/Client/BlazorWasmRegex.Client.csproj
4. Upgrade BlazorWasmRegex/Server/BlazorWasmRegex.Server.csproj
5. Upgrade build/_build.csproj

## Settings

This section contains settings and data used by execution steps.

### Aggregate NuGet packages modifications across all projects

NuGet packages used across all selected projects or their dependencies that need version update in projects that reference them.

| Package Name | Current Version | New Version | Description |
|:----------------------------------------------------------|:---------------:|:-----------:|:----------------------------------------------|
| BlazorStrap | 1.5.1 | 5.2.0 | Recommended for .NET 10.0 |
| Blazored.LocalStorage | | 4.5.0 | Replacement for Cloudcrate.AspNetCore.Blazor.Browser.Storage |
| Cloudcrate.AspNetCore.Blazor.Browser.Storage | 3.0.0 | | Deprecated - replace with Blazored.LocalStorage |
| Microsoft.AspNetCore.Components.WebAssembly | 7.0.0 | 10.0.0 | Recommended for .NET 10.0 |
| Microsoft.AspNetCore.Components.WebAssembly.DevServer | 7.0.0 | 10.0.0 | Recommended for .NET 10.0 |
| Microsoft.AspNetCore.Components.WebAssembly.Server | 7.0.0 | 10.0.0 | Recommended for .NET 10.0 |
| Microsoft.VisualStudio.Azure.Containers.Tools.Targets | 1.17.0 | 1.21.0 | Recommended for .NET 10.0 |
| Nuke.Common | 6.2.1 | 8.1.2 | Recommended for .NET 10.0 |
| System.Net.Http.Json | 7.0.0 | 10.0.0 | Recommended for .NET 10.0 |

### Project upgrade details

This section contains details about each project upgrade and modifications that need to be done in the project.

#### BlazorWasmRegex.Shared.csproj modifications

Project properties changes:
- Target framework should be changed from `net7.0` to `net10.0`

#### BlazorWasmRegex.Client.csproj modifications

Project properties changes:
- Target framework should be changed from `net7.0` to `net10.0`

NuGet packages changes:
- BlazorStrap should be updated from `1.5.1` to `5.2.0` (*recommended for .NET 10.0*)
- Cloudcrate.AspNetCore.Blazor.Browser.Storage should be removed (*deprecated - replace with Blazored.LocalStorage*)
- Blazored.LocalStorage should be added with version `4.5.0` (*replacement for deprecated package*)
- Microsoft.AspNetCore.Components.WebAssembly should be updated from `7.0.0` to `10.0.0` (*recommended for .NET 10.0*)
- Microsoft.AspNetCore.Components.WebAssembly.DevServer should be updated from `7.0.0` to `10.0.0` (*recommended for .NET 10.0*)
- System.Net.Http.Json should be updated from `7.0.0` to `10.0.0` (*recommended for .NET 10.0*)

Other changes:
- Update Program.cs to use new Blazored.LocalStorage API instead of Cloudcrate storage
- Update root component registration syntax for .NET 10.0

#### BlazorWasmRegex.Server.csproj modifications

Project properties changes:
- Target framework should be changed from `net7.0` to `net10.0`

NuGet packages changes:
- Microsoft.AspNetCore.Components.WebAssembly.Server should be updated from `7.0.0` to `10.0.0` (*recommended for .NET 10.0*)
- Microsoft.VisualStudio.Azure.Containers.Tools.Targets should be updated from `1.17.0` to `1.21.0` (*recommended for .NET 10.0*)

Other changes:
- Migrate from Startup.cs pattern to minimal hosting model (Program.cs only)
- Update to .NET 10.0 hosting patterns

#### _build.csproj modifications

Project properties changes:
- Target framework should be changed from `net7.0` to `net10.0`

NuGet packages changes:
- Nuke.Common should be updated from `6.2.1` to `8.1.2` (*recommended for .NET 10.0*)
20 changes: 13 additions & 7 deletions .github/workflows/create-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,28 @@ jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: [self-hosted, Linux]
runs-on: [ ubuntu-latest ]

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup .NET 7
uses: actions/setup-dotnet@v2
uses: actions/checkout@v4
- name: Setup .NET 10
uses: actions/setup-dotnet@v4
with:
dotnet-version: 7.0.x
dotnet-version: 10.0.x
- name: Set build script eXecutable
id: builscriptexec
run: chmod +x ./build.sh
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build ARM container
id: armcontainer
run: ./build.sh -Target PushArmDockerContainer -DockerPrivateRegistry "${{ secrets.PRIVATE_DOCKER_REGISTRY }}" -DockerLogin "${{ secrets.PRIVATE_DOCKER_REGISTRY_LOGIN }}" -DockerPassword "${{ secrets.PRIVATE_DOCKER_REGISTRY_PASSWORD }}"
run: ./build.sh -Target PushArmDockerContainer -GitHubOwner "${{ github.repository_owner }}" -GitHubToken "${{ secrets.GITHUB_TOKEN }}"
- name: Build x64 container
id: x64container
run: ./build.sh -Target PushDockerContainer -DockerPrivateRegistry "${{ secrets.PRIVATE_DOCKER_REGISTRY }}" -DockerLogin "${{ secrets.PRIVATE_DOCKER_REGISTRY_LOGIN }}" -DockerPassword "${{ secrets.PRIVATE_DOCKER_REGISTRY_PASSWORD }}"
run: ./build.sh -Target PushDockerContainer -GitHubOwner "${{ github.repository_owner }}" -GitHubToken "${{ secrets.GITHUB_TOKEN }}"
Loading