diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 4a649ba..34d84e9 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,7 +2,7 @@ ## Project Overview -SharedCode is a multi-project .NET 9 solution that provides reusable utility libraries +SharedCode is a multi-project .NET solution that provides reusable utility libraries published as individual NuGet packages. Each project corresponds to one NuGet package: | Project | NuGet Package | Purpose | @@ -34,7 +34,9 @@ dotnet test --logger GitHubActions --verbosity normal SharedCode.sln ### Language & Framework -- **Target framework**: `net9.0` +- **Target frameworks**: + - Primary/current: `.NET 10` (`net10.0`) + - Compatibility targets: `.NET 9` (`net9.0`), `.NET 8` (`net8.0`), and `.NET Standard 2.0/2.1` where applicable - **Language version**: `preview` (latest C# features enabled) - **Nullable reference types**: enabled (`enable`) - **Implicit usings**: enabled diff --git a/.github/prompts/create-module.prompt.md b/.github/prompts/create-module.prompt.md index 9f2257e..c6a3fa4 100644 --- a/.github/prompts/create-module.prompt.md +++ b/.github/prompts/create-module.prompt.md @@ -27,7 +27,7 @@ belong here. A library of [short description] shared for free use to help with common scenarios. shared code, c#, [relevant tags] SharedCode. - net9.0 + net9.0;net10.0 diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index e09e401..e4841f4 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -19,7 +19,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 9.0.x + dotnet-version: 10.0.x - name: Run tests run: dotnet test --logger GitHubActions SharedCode.sln diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eaa20aa..d005744 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,9 +17,9 @@ jobs: - uses: actions/checkout@v3 - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 9.0.x + dotnet-version: 10.0.x - name: Run Tests run: dotnet test --logger GitHubActions --verbosity normal SharedCode.sln @@ -34,9 +34,9 @@ jobs: - uses: actions/checkout@v3 - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 9.0.x + dotnet-version: 10.0.x - name: Bump version and push tag id: tag_version @@ -73,9 +73,9 @@ jobs: name: PackedLib - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 9.0.x + dotnet-version: 10.0.x - name: Push Package to GitHub run: dotnet nuget push --api-key ${{secrets.GITHUB_TOKEN}} --source "https://nuget.pkg.github.com/improvgroup/index.json" *.nupkg @@ -93,9 +93,9 @@ jobs: name: PackedLib - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 9.0.x + dotnet-version: 10.0.x - name: Push Package to NuGet run: dotnet nuget push --api-key ${{secrets.NUGET_API_KEY}} --source "https://api.nuget.org/v3/index.json" *.nupkg diff --git a/Directory.Build.props b/Directory.Build.props index 4541e31..00a7305 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,7 +24,7 @@ true preview en-US - $(NoWarn);CA1014 + $(NoWarn);CA1014;NU1510 enable share.png MIT @@ -100,6 +100,12 @@ + + + + + false + diff --git a/README.md b/README.md index ad0869e..7f2860d 100644 --- a/README.md +++ b/README.md @@ -42,19 +42,20 @@ in only what you need. | Package | NuGet | Target Frameworks | Description | |---|---|---|---| -| `SharedCode.Core` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Core.svg)](https://www.nuget.org/packages/SharedCode.Core) | `netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0` | Core utilities: extensions, specifications, domain primitives, security, threading, reactive | -| `SharedCode.Data` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Data.svg)](https://www.nuget.org/packages/SharedCode.Data) | `netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0` | Framework-agnostic data access abstractions: repository pattern, paging, query results | -| `SharedCode.Data.CosmosDb` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Data.CosmosDb.svg)](https://www.nuget.org/packages/SharedCode.Data.CosmosDb) | `net8.0`, `net9.0` | Azure Cosmos DB integration and helpers | -| `SharedCode.Data.EntityFramework` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Data.EntityFramework.svg)](https://www.nuget.org/packages/SharedCode.Data.EntityFramework) | `net8.0`, `net9.0` | Entity Framework Core integration: auditable contexts, EF repository, specifications | -| `SharedCode.DependencyInjection` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.DependencyInjection.svg)](https://www.nuget.org/packages/SharedCode.DependencyInjection) | `netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0` | DI assembly scanning and auto-registration via `IDependencyRegister` | -| `SharedCode.MediatR` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.MediatR.svg)](https://www.nuget.org/packages/SharedCode.MediatR) | `net8.0`, `net9.0` | MediatR command/query abstractions and pipeline helpers | -| `SharedCode.Web` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Web.svg)](https://www.nuget.org/packages/SharedCode.Web) | `net9.0` | ASP.NET Core helpers: base controller, resilient HTTP client setup, health checks | -| `SharedCode.Windows.WPF` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Windows.WPF.svg)](https://www.nuget.org/packages/SharedCode.Windows.WPF) | `net9.0-windows10.0.22621.0` | WPF helpers: `BindableBase`, value converters, attached properties, MVVM mediator | +| `SharedCode.Core` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Core.svg)](https://www.nuget.org/packages/SharedCode.Core) | `netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0`, `net10.0` | Core utilities: extensions, specifications, domain primitives, security, threading, reactive | +| `SharedCode.Data` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Data.svg)](https://www.nuget.org/packages/SharedCode.Data) | `netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0`, `net10.0` | Framework-agnostic data access abstractions: repository pattern, paging, query results | +| `SharedCode.Data.CosmosDb` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Data.CosmosDb.svg)](https://www.nuget.org/packages/SharedCode.Data.CosmosDb) | `net8.0`, `net9.0`, `net10.0` | Azure Cosmos DB integration and helpers | +| `SharedCode.Data.EntityFramework` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Data.EntityFramework.svg)](https://www.nuget.org/packages/SharedCode.Data.EntityFramework) | `net8.0`, `net9.0`, `net10.0` | Entity Framework Core integration: auditable contexts, EF repository, specifications | +| `SharedCode.DependencyInjection` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.DependencyInjection.svg)](https://www.nuget.org/packages/SharedCode.DependencyInjection) | `netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0`, `net10.0` | DI assembly scanning and auto-registration via `IDependencyRegister` | +| `SharedCode.MediatR` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.MediatR.svg)](https://www.nuget.org/packages/SharedCode.MediatR) | `net8.0`, `net9.0`, `net10.0` | MediatR command/query abstractions and pipeline helpers | +| `SharedCode.Web` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Web.svg)](https://www.nuget.org/packages/SharedCode.Web) | `net9.0`, `net10.0` | ASP.NET Core helpers: base controller, resilient HTTP client setup, health checks | +| `SharedCode.Windows.WPF` | [![NuGet](https://img.shields.io/nuget/v/SharedCode.Windows.WPF.svg)](https://www.nuget.org/packages/SharedCode.Windows.WPF) | `net9.0-windows10.0.22621.0`, `net10.0-windows10.0.22621.0` | WPF helpers: `BindableBase`, value converters, attached properties, MVVM mediator | --- ## Requirements +- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) (for `net10.0` targets) - [.NET 9 SDK](https://dotnet.microsoft.com/download/dotnet/9.0) (for `net9.0` targets) - [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) (for `net8.0` targets) - .NET Standard 2.0 / 2.1 targets are compatible with .NET Framework 4.6.1+ and .NET Core 2.0+ @@ -100,7 +101,7 @@ Install-Package SharedCode.Windows.WPF [![NuGet](https://img.shields.io/nuget/v/SharedCode.Core.svg)](https://www.nuget.org/packages/SharedCode.Core) Core utilities and domain primitives that are shared across all other packages. Targets -`netstandard2.0`, `netstandard2.1`, `net8.0`, and `net9.0`. +`netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0`, and `net10.0`. **Highlights** @@ -137,7 +138,7 @@ public sealed class ActiveUsersSpec : Specification [![NuGet](https://img.shields.io/nuget/v/SharedCode.Data.svg)](https://www.nuget.org/packages/SharedCode.Data) Framework-agnostic data access abstractions. Targets `netstandard2.0`, `netstandard2.1`, -`net8.0`, and `net9.0`. +`net8.0`, `net9.0`, and `net10.0`. **Highlights** @@ -170,7 +171,7 @@ public class UserService Azure Cosmos DB integration built on top of the official [Microsoft.Azure.Cosmos](https://www.nuget.org/packages/Microsoft.Azure.Cosmos) SDK. -Targets `net8.0` and `net9.0`. +Targets `net8.0`, `net9.0`, and `net10.0`. **Highlights** @@ -183,7 +184,7 @@ Targets `net8.0` and `net9.0`. [![NuGet](https://img.shields.io/nuget/v/SharedCode.Data.EntityFramework.svg)](https://www.nuget.org/packages/SharedCode.Data.EntityFramework) -Entity Framework Core integration. Targets `net8.0` and `net9.0`. +Entity Framework Core integration. Targets `net8.0`, `net9.0`, and `net10.0`. **Highlights** @@ -213,7 +214,7 @@ services.AddDbContext(options => [![NuGet](https://img.shields.io/nuget/v/SharedCode.DependencyInjection.svg)](https://www.nuget.org/packages/SharedCode.DependencyInjection) Assembly scanning and automatic service registration. Targets `netstandard2.0`, -`netstandard2.1`, `net8.0`, and `net9.0`. +`netstandard2.1`, `net8.0`, `net9.0`, and `net10.0`. **Highlights** @@ -241,8 +242,8 @@ public class MyServiceRegistrar : IDependencyRegister [![NuGet](https://img.shields.io/nuget/v/SharedCode.MediatR.svg)](https://www.nuget.org/packages/SharedCode.MediatR) -[MediatR](https://github.com/jbogard/MediatR) pipeline abstractions. Targets `net8.0` and -`net9.0`. +[MediatR](https://github.com/jbogard/MediatR) pipeline abstractions. Targets `net8.0`, +`net9.0`, and `net10.0`. **Highlights** @@ -277,7 +278,7 @@ services.AddSharedCodeMediatR(typeof(Program).Assembly); [![NuGet](https://img.shields.io/nuget/v/SharedCode.Web.svg)](https://www.nuget.org/packages/SharedCode.Web) -ASP.NET Core helpers. Targets `net9.0`. +ASP.NET Core helpers. Targets `net9.0` and `net10.0`. **Highlights** @@ -303,7 +304,7 @@ public class UsersController : BaseController [![NuGet](https://img.shields.io/nuget/v/SharedCode.Windows.WPF.svg)](https://www.nuget.org/packages/SharedCode.Windows.WPF) -WPF helpers targeting `net9.0-windows10.0.22621.0`. +WPF helpers targeting `net9.0-windows10.0.22621.0` and `net10.0-windows10.0.22621.0`. **Highlights** @@ -334,8 +335,9 @@ dotnet build SharedCode.sln dotnet test SharedCode.sln ``` -The solution targets **.NET 9** for the library projects. The WPF project additionally requires -Windows 10 SDK version 10.0.19041.0 or later. +The solution targets **.NET 8, .NET 9, and .NET 10** for library projects (plus .NET Standard +2.0/2.1 compatibility for selected packages). The WPF project additionally requires Windows 10 SDK +version 10.0.19041.0 or later. --- diff --git a/SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs b/SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs index 840425a..b508ce1 100644 --- a/SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs +++ b/SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs @@ -6,6 +6,7 @@ namespace SharedCode.Tests.Calendar; using SharedCode.Calendar; using System.Diagnostics.CodeAnalysis; +using System.Globalization; /// /// The date time extensions tests class @@ -26,6 +27,16 @@ public class DateTimeExtensionsTests /// private DateTime originalDateTime; + /// + /// The original culture before test execution. + /// + private CultureInfo? originalCulture; + + /// + /// The original UI culture before test execution. + /// + private CultureInfo? originalUiCulture; + [TestMethod] [DataRow(5, 2022, 12, 11, 2022, 12, 19)] [DataRow(3, 2022, 12, 10, 2022, 12, 15)] @@ -61,7 +72,7 @@ public void AddWorkdays_SkipsWeekends() public void Can_Get_Full_Long_Date_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.FullLongDateTime); - Assert.AreEqual("Sunday, March 11, 1984 2:30:58 AM", result); + Assert.AreEqual("Sunday, March 11, 1984 2:30:58 AM", NormalizeWhitespace(result)); } /// @@ -71,7 +82,7 @@ public void Can_Get_Full_Long_Date_Time_String() public void Can_Get_Full_Short_Date_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.FullShortDateTime); - Assert.AreEqual("Sunday, March 11, 1984 2:30 AM", result); + Assert.AreEqual("Sunday, March 11, 1984 2:30 AM", NormalizeWhitespace(result)); } /// @@ -81,7 +92,7 @@ public void Can_Get_Full_Short_Date_Time_String() public void Can_Get_General_Long_Date_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.GeneralLongDateTime); - Assert.AreEqual("3/11/1984 2:30:58 AM", result); + Assert.AreEqual("3/11/1984 2:30:58 AM", NormalizeWhitespace(result)); } /// @@ -91,7 +102,7 @@ public void Can_Get_General_Long_Date_Time_String() public void Can_Get_General_Short_Date_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.GeneralShortDateTime); - Assert.AreEqual("3/11/1984 2:30 AM", result); + Assert.AreEqual("3/11/1984 2:30 AM", NormalizeWhitespace(result)); } /// @@ -111,7 +122,7 @@ public void Can_Get_Long_Date_String() public void Can_Get_Long_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.LongTime); - Assert.AreEqual("2:30:58 AM", result); + Assert.AreEqual("2:30:58 AM", NormalizeWhitespace(result)); } /// @@ -171,7 +182,7 @@ public void Can_Get_Short_Date_String() public void Can_Get_Short_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.ShortTime); - Assert.AreEqual("2:30 AM", result); + Assert.AreEqual("2:30 AM", NormalizeWhitespace(result)); } /// @@ -219,7 +230,14 @@ public void Can_Get_Year_Month_Upper_Case_String() /// Initializes the test case. /// [TestInitialize] - public void InitTestCase() => this.originalDateTime = new DateTime(Year, Month, Day, Hour, Minute, Second); + public void InitTestCase() + { + this.originalCulture = CultureInfo.CurrentCulture; + this.originalUiCulture = CultureInfo.CurrentUICulture; + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US"); + CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en-US"); + this.originalDateTime = new DateTime(Year, Month, Day, Hour, Minute, Second); + } /// /// Teardowns the test case. @@ -232,5 +250,17 @@ public void TeardownTestCase() { GC.SuppressFinalize(this.originalDateTime); } + + if (this.originalCulture is not null) + { + CultureInfo.CurrentCulture = this.originalCulture; + } + + if (this.originalUiCulture is not null) + { + CultureInfo.CurrentUICulture = this.originalUiCulture; + } } + + private static string NormalizeWhitespace(string value) => value.Replace('\u202F', ' '); } diff --git a/SharedCode.Core.Tests/Core.Tests.csproj b/SharedCode.Core.Tests/Core.Tests.csproj index 3857501..4e86630 100644 --- a/SharedCode.Core.Tests/Core.Tests.csproj +++ b/SharedCode.Core.Tests/Core.Tests.csproj @@ -6,7 +6,7 @@ false false SharedCode.Tests - net9.0 + net9.0;net10.0 diff --git a/SharedCode.Core/Core.csproj b/SharedCode.Core/Core.csproj index 8ef53d6..02cee0c 100644 --- a/SharedCode.Core/Core.csproj +++ b/SharedCode.Core/Core.csproj @@ -3,7 +3,7 @@ SharedCode.Core latest SharedCode - netstandard2.0;netstandard2.1;net8.0;net9.0 + netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0 diff --git a/SharedCode.Data.CosmosDb/Data.CosmosDb.csproj b/SharedCode.Data.CosmosDb/Data.CosmosDb.csproj index 014b462..954c4a8 100644 --- a/SharedCode.Data.CosmosDb/Data.CosmosDb.csproj +++ b/SharedCode.Data.CosmosDb/Data.CosmosDb.csproj @@ -2,7 +2,7 @@ SharedCode.Data.CosmosDb SharedCode.Data.CosmosDb - net8.0;net9.0 + net8.0;net9.0;net10.0 diff --git a/SharedCode.Data.EntityFramework/Data.EntityFramework.csproj b/SharedCode.Data.EntityFramework/Data.EntityFramework.csproj index 8232b2d..1ccfff4 100644 --- a/SharedCode.Data.EntityFramework/Data.EntityFramework.csproj +++ b/SharedCode.Data.EntityFramework/Data.EntityFramework.csproj @@ -2,7 +2,7 @@ SharedCode.Data.EntityFramework SharedCode.Data.EntityFramework - net8.0;net9.0 + net8.0;net9.0;net10.0 diff --git a/SharedCode.Data.Tests/Data.Tests.csproj b/SharedCode.Data.Tests/Data.Tests.csproj index d99805b..d0ceece 100644 --- a/SharedCode.Data.Tests/Data.Tests.csproj +++ b/SharedCode.Data.Tests/Data.Tests.csproj @@ -6,7 +6,7 @@ false false SharedCode.Data.Tests - net9.0 + net9.0;net10.0 diff --git a/SharedCode.Data/Data.csproj b/SharedCode.Data/Data.csproj index 648f5fa..1b8cb35 100644 --- a/SharedCode.Data/Data.csproj +++ b/SharedCode.Data/Data.csproj @@ -3,7 +3,7 @@ SharedCode.Data latest SharedCode.Data - netstandard2.0;netstandard2.1;net8.0;net9.0 + netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0 diff --git a/SharedCode.DependencyInjection/DependencyInjection.csproj b/SharedCode.DependencyInjection/DependencyInjection.csproj index f1442ca..8b9553d 100644 --- a/SharedCode.DependencyInjection/DependencyInjection.csproj +++ b/SharedCode.DependencyInjection/DependencyInjection.csproj @@ -4,7 +4,7 @@ latest shared code, c#, utilities, dependency injection SharedCode.DependencyInjection - netstandard2.0;netstandard2.1;net8.0;net9.0 + netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0 diff --git a/SharedCode.MediatR/MediatR.csproj b/SharedCode.MediatR/MediatR.csproj index 02ced03..27bc25e 100644 --- a/SharedCode.MediatR/MediatR.csproj +++ b/SharedCode.MediatR/MediatR.csproj @@ -2,7 +2,7 @@ SharedCode.MediatR SharedCode.MediatR - net8.0;net9.0 + net8.0;net9.0;net10.0 diff --git a/SharedCode.Web/Web.csproj b/SharedCode.Web/Web.csproj index e79b7f5..9787a96 100644 --- a/SharedCode.Web/Web.csproj +++ b/SharedCode.Web/Web.csproj @@ -4,7 +4,7 @@ Library true SharedCode.Web - net9.0 + net9.0;net10.0 diff --git a/SharedCode.Windows.WPF/Windows.WPF.csproj b/SharedCode.Windows.WPF/Windows.WPF.csproj index 2648712..c8a2b67 100644 --- a/SharedCode.Windows.WPF/Windows.WPF.csproj +++ b/SharedCode.Windows.WPF/Windows.WPF.csproj @@ -5,7 +5,7 @@ shared code, c#, utilities, Windows, WPF SharedCode.Windows.WPF 10.0.19041.0 - net9.0-windows10.0.22621.0 + net9.0-windows10.0.22621.0;net10.0-windows10.0.22621.0 true