Browse Source

Merge branch 'dev' into net10.0

pull/23609/head
maliming 5 months ago
parent
commit
f7ec6dc131
  1. 18
      Directory.Packages.props
  2. 2
      docs/en/Community-Articles/2025-09-02-training-campaign/post.md
  3. 173
      docs/en/Community-Articles/2025-09-10-NET10-What-You-Need-To-Know/Post.md
  4. BIN
      docs/en/Community-Articles/2025-09-10-NET10-What-You-Need-To-Know/cover.png
  5. BIN
      docs/en/Community-Articles/2025-09-10-NET10-What-You-Need-To-Know/image-1.png
  6. BIN
      docs/en/Community-Articles/2025-09-10-NET10-What-You-Need-To-Know/image-2.png
  7. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/BenchmarkDotnet.png
  8. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/Disruptor.png
  9. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/MemoryPack.png
  10. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/MessagePack.png
  11. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/Polly.png
  12. 161
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/Post.md
  13. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/cliwrap.png
  14. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/cover.png
  15. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/wolverine-logo.png
  16. BIN
      docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/wolverine.png
  17. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_1.png
  18. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_2.png
  19. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_3.png
  20. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_4.png
  21. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_5.png
  22. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_6.png
  23. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_7.png
  24. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_8.png
  25. BIN
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_9.png
  26. 282
      docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/post.md
  27. 28
      docs/en/framework/fundamentals/localization.md
  28. 183
      docs/en/release-info/migration-guides/AutoMapper-To-Mapperly.md
  29. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs
  30. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularSourceCodeAdder.cs
  31. 12
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs
  32. 14
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs
  33. 72
      framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs
  34. 7
      framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationFile.cs
  35. 54
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ObjectToInferredTypesConverter_Tests.cs
  36. 25
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs
  37. 24
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json
  38. 9
      latest-versions.json
  39. 74
      modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs

18
Directory.Packages.props

@ -114,10 +114,10 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.12.0" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.12.0" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.12.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.12.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.14.0" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.14.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.14.0" />
<PackageVersion Include="Minio" Version="6.0.4" />
<PackageVersion Include="MongoDB.Driver" Version="3.5.0" />
<PackageVersion Include="NEST" Version="7.17.5" />
@ -129,11 +129,11 @@
<PackageVersion Include="NUglify" Version="1.21.15" />
<PackageVersion Include="Nullable" Version="1.3.1" />
<PackageVersion Include="Octokit" Version="14.0.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="7.0.0" />
<PackageVersion Include="OpenIddict.Core" Version="7.0.0" />
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="7.0.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="7.0.0" />
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="7.0.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="7.1.0" />
<PackageVersion Include="OpenIddict.Core" Version="7.1.0" />
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="7.1.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="7.1.0" />
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="7.1.0" />
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="9.23.80" />
<PackageVersion Include="Polly" Version="8.5.2" />
<PackageVersion Include="Polly.Extensions.Http" Version="3.0.0" />

2
docs/en/Community-Articles/2025-09-02-training-campaign/post.md

@ -25,5 +25,5 @@ Simply visit our training page, select your preferred package, add your note if
Invest in your skills and advance your career with ABP.IO training. This offer won’t last long, so grab your spot now\!
### 🔗[Sign up for training now and start building with ABP](https://abp.io/trainings?utm_source=referral&utm_medium=website&utm_campaign=training_abpblogpost)\!
### 🔗[Pick your package and send your training request now!](https://abp.io/trainings?utm_source=referral&utm_medium=website&utm_campaign=training_abpblogpost)

173
docs/en/Community-Articles/2025-09-10-NET10-What-You-Need-To-Know/Post.md

@ -0,0 +1,173 @@
# .NET 10: What You Need to Know (LTS Release, Coming November 2025)
The next version of .NET is .NET 10 and it is coming with **Long-Term Support (LTS)**, scheduled for **November 2025**.
On **September 9, 2025**, Microsoft released **.NET 10 Release Candidate 1 (RC1)**, which supports go-live usage and is compatible with [Visual Studio 2026 Insider](https://visualstudio.microsoft.com/insiders/) and [Visual Studio Code Insider](https://code.visualstudio.com/insiders/) via the [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) extension.
------
## .NET 10 Runtime Enhancements
- **JIT Speed-ups**: Enhanced struct argument handling—members now go directly into registers, reducing memory load/store operations.
- **Advanced Loop Optimization**: New graph-based loop inversion improves precision and boosts further optimizations.
- **Array Interface De-virtualization**: Critical for performance, now array-based enumerations inline and skip virtual calls including de-abstraction of array enumeration and small-array stack allocation.
- **General JIT Improvements**: Better code layout and branch reduction support overall efficiency.
------
## Language & Library Upgrades
### C# 14 Enhancements
- Field-backed properties: easier custom getters/setters.
- `nameof` for unbound generics like `List<>`.
- Implicit conversions for `Span<T>` and `ReadOnlySpan<T>`.
- Lambda parameter modifiers (`ref`, `in`, `out`).
- Partial constructors/events.
- `extension` blocks for static extension members.
- Null-conditional assignment (`?.=`) and custom compound/increment operators.
### F# & Visual Basic Enhancements
- F# improvements via `<LangVersion>preview</LangVersion>`, updated `FSharp.Core`, and compiler fixes.
- VB compiler supports `unmanaged` generics and respects `OverloadResolutionPriorityAttribute` for performance and overload clarity.
## .NET Libraries & SDK
### Libraries:
- Better ZipArchive performance (lazy entry loading).
- JSON improvements, including `JsonSourceGenerationOptions` and reference-handling tweaks.
- Enhanced `OrderedDictionary`, ISOWeek date APIs, PEM data and certificate handling, `CompareOptions.NumericOrdering`
### SDK & CLI:
- No major new SDK features in RC1—you should expect stability fixes rather than additions.
- Earlier previews brought JSON support improvements (e.g., `PipeReader` for JSON, WebSocketStream, ML-DSA crypto, AES KeyWrap), TLS 1.3 for macOS
------
## ASP.NET Core & Blazor
### Blazor & Web App Security:
Enhanced OIDC and Microsoft Entra ID integration, including encrypted token caching and Key Vault use.
### UI Enhancements:
- `QuickGrid` gains `RowClass` for conditional styling.
- Scripts now served as static assets with compression and fingerprinting.
- NavigationManager no longer scrolls to top for same-page updates.
### API Improvements:
Full support for OpenAPI 3.1 (JSON Schema draft 2020-12), and metrics for authentication/authorization events (e.g., sign-ins, logins) .
------
## .NET MAUI
Updates include multiple file selection, image compression, WebView request interception, and support for Android API 35/36.
## EF Core
LINQ enhancements, performance boosts, better Azure Cosmos DB support, and more flexible named query filters.
## Breaking Changes in .NET 10
### ASP.NET Core - Breaking Changes in .NET 10:
.NET 10 Preview 7 brings **several deprecations + behavior changes**, while **RC1 removes the old WebHost model**.
- **[Cookie login redirects disabled](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/cookie-authentication-api-endpoints)** → Redirects no longer occur for API endpoints; APIs now return `401`/`403`. *(Behavioral change)*
- **[WithOpenApi deprecated](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/withopenapi-deprecated)** → Extension method removed; use updated OpenAPI generator features. *(Source incompatible)*
- **[Exception diagnostics suppressed](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/exception-handler-diagnostics-suppressed)** → When `TryHandleAsync` returns true, exception details aren’t logged. *(Behavioral change)*
- **[IActionContextAccessor obsolete](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/iactioncontextaccessor-obsolete)** → Marked obsolete; may break code depending on it. *(Source/behavioral change)*
- **[IncludeOpenAPIAnalyzers deprecated](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/openapi-analyzers-deprecated)** → Property and MVC API analyzers removed. *(Source incompatible)*
- **[IPNetwork & KnownNetworks obsolete](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/ipnetwork-knownnetworks-obsolete)** → Old networking APIs removed in favor of new ones. *(Source incompatible)*
- **[ApiDescription.Client package deprecated](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/apidescription-client-deprecated)** → No longer maintained; migrate to other tools. *(Source incompatible)*
- **[Razor run-time compilation obsolete](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/razor-runtime-compilation-obsolete)** → Disabled at runtime; precompilation required. *(Source incompatible)*
- **[WebHostBuilder, IWebHost, WebHost obsolete](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/webhostbuilder-deprecated)** → Legacy hosting model deprecated; use `WebApplicationBuilder`. *(Source incompatible, RC1)*
### EF Core - Breaking Changes in .NET 10:
You can find the complete list at [Microsoft EF Core 10 Breaking Changes page](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-10.0/breaking-changes). Here's the brief summary:
#### EF Core - SQL Server
- **JSON column type by default (Azure SQL / compat level ≥170).** Primitive collections and owned types mapped to JSON now use SQL Server’s native `json` type instead of `nvarchar(max)`. A migration may alter existing columns. Mitigate by setting compat level <170 or explicitly forcing `nvarchar(max)`.
- **`ExecuteUpdateAsync` signature change.** Column setters now take a regular `Func<…>` (not an expression). Dynamic expression-tree code won’t compile; replace with imperative setters inside the lambda.
#### Microsoft.Data.Sqlite
- **`GetDateTimeOffset` (no offset) assumes UTC.** Previously assumed local time. You can temporarily revert via `AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", true)`.
- **Writing `DateTimeOffset` to REAL stores UTC.** Conversion now happens before writing; revertable with the same switch.
- **`GetDateTime` (with offset) returns UTC `DateTime` (`DateTimeKind.Utc`).** Was `Local` before. Same temporary switch if needed.
#### Who’s most affected
- Apps on **Azure SQL / SQL Server 2025** using JSON mapping.
- Codebases building **expression trees** for bulk updates.
- Apps using **SQLite** with date/time parsing or REAL timestamp storage.
#### Quick mitigations
- Set SQL Server compatibility <170 or force column type.
- Rewrite `ExecuteUpdateAsync` callers to use the new delegate form.
- For SQLite, update handling to UTC or use the temporary AppContext switch while transitioning.
### Containers - Breaking Changes in .NET 10:
Default .NET images now use [Ubuntu](https://learn.microsoft.com/en-us/dotnet/core/compatibility/containers/10.0/default-images-use-ubuntu).
### Core Libraries - Breaking Changes in .NET 10:
[ActivitySource](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/10.0/activity-sampling) behavior tweaks; [generic math](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/10.0/generic-math) shift behavior aligned; W3C trace context is [default](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/10.0/default-trace-context-propagator); [DriveInfo](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/10.0/driveinfo-driveformat-linux) reports Linux FS types; InlineArray size rules tightened; [System.Linq.AsyncEnumerable](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/10.0/asyncenumerable) included in core libs...
### Cryptography - Breaking Changes in .NET 10:
[Stricter X500](https://learn.microsoft.com/en-us/dotnet/core/compatibility/cryptography/10.0/x500distinguishedname-validation) name validation; [OpenSSL](https://learn.microsoft.com/en-us/dotnet/core/compatibility/cryptography/10.0/openssl-macos-unsupported) primitives unsupported on macOS; [some key members](https://learn.microsoft.com/en-us/dotnet/core/compatibility/cryptography/10.0/mldsa-slhdsa-secretkey-to-privatekey) nullable/renamed; env var [rename to](https://learn.microsoft.com/en-us/dotnet/core/compatibility/cryptography/10.0/version-override) `DOTNET_OPENSSL_VERSION_OVERRIDE`.
### Extensions - Breaking Changes in .NET 10:
[Config preserves](https://learn.microsoft.com/en-us/dotnet/core/compatibility/extensions/10.0/configuration-null-values-preserved) nulls; [logging](https://learn.microsoft.com/en-us/dotnet/core/compatibility/extensions/10.0/console-json-logging-duplicate-messages)/[package](https://learn.microsoft.com/en-us/dotnet/core/compatibility/extensions/10.0/provideraliasattribute-moved-assembly)/trim annotations changes; some [trim-unsafe](https://learn.microsoft.com/en-us/dotnet/core/compatibility/extensions/10.0/dynamically-accessed-members-configuration) code annotations removed.
### Globalization & Interop - Breaking Changes in .NET 10:
[ICU](https://learn.microsoft.com/en-us/dotnet/core/compatibility/globalization/10.0/version-override) env var renamed; single-file apps stop probing executable dir for native libs; [DllImport](https://learn.microsoft.com/en-us/dotnet/core/compatibility/interop/10.0/search-assembly-directory) search path tightened.
Networking:
[HTTP/3 disabled ](https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/10.0/http3-disabled-with-publishtrimmed) by default when trimming; [default cert revocation](https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/10.0/ssl-certificate-revocation-check-default) check now Online; [browser clients](https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/10.0/default-http-streaming) stream responses by default; [URI length limits](https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/10.0/uri-length-limits-removed) removed.
### SDK & MSBuild/NuGet - Breaking Changes in .NET 10:
`dotnet --interactive` [defaults to true](https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/dotnet-cli-interactive); tool packages are [RID-specific](https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/dotnet-tool-pack-publish); [workload](https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/default-workload-config) sets default; `dotnet new sln` uses [SLNX](https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/dotnet-new-sln-slnx-default); restore audits transitives; [local tool](https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/dotnet-tool-install-local-manifest) install creates manifest by default; `project.json` [not supported](https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/dotnet-restore-project-json-unsupported); stricter NuGet [validation](https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/nuget-packageid-validation)/[errors](https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/10.0/http-warnings-to-errors).
WinForms/WPF:
Multiple [API obsoletions](https://learn.microsoft.com/en-us/dotnet/core/compatibility/windows-forms/10.0/obsolete-apis)/parameter [renames](https://learn.microsoft.com/en-us/dotnet/core/compatibility/windows-forms/10.0/insertadjacentelement-orientation); [rendering](https://learn.microsoft.com/en-us/dotnet/core/compatibility/windows-forms/10.0/statusstrip-renderer)/behavior tweaks; stricter XAML rules (e.g., [disallow empty row](https://learn.microsoft.com/en-us/dotnet/core/compatibility/wpf/10.0/empty-grid-definitions)/column definitions or incorrect usage of [DynamicResource](https://learn.microsoft.com/en-us/dotnet/core/compatibility/wpf/10.0/dynamicresource-crash) will crash).
------
## Support Policy for .NET 10
As you can see from the picture below, **.NET 10 has long term support** therefore it will be maintained for 3 years **until November 2028**.
[![.NET 10 Support Policy](image-2.png)](https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core)
## Download .NET10
Click 👉 https://dotnet.microsoft.com/en-us/download/dotnet/10.0 to download the latest release candidate (currently RC.1).
[![Download .NET 10](image-1.png)](https://dotnet.microsoft.com/en-us/download/dotnet/10.0)
Also to use the latest features, download/update your Visual Studio to the latest 👉 https://visualstudio.microsoft.com/downloads/

BIN
docs/en/Community-Articles/2025-09-10-NET10-What-You-Need-To-Know/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 KiB

BIN
docs/en/Community-Articles/2025-09-10-NET10-What-You-Need-To-Know/image-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/en/Community-Articles/2025-09-10-NET10-What-You-Need-To-Know/image-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/BenchmarkDotnet.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 KiB

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/Disruptor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/MemoryPack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/MessagePack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/Polly.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

161
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/Post.md

@ -0,0 +1,161 @@
# High-Performance .NET Libraries You Didn’t Know You Needed
Whether you’re building enterprise apps, microservices, or SaaS platforms, using the right libraries can help you ship faster and scale effortlessly.
Here are some **high-performance .NET libraries** you might not know but definitely should.
## 1. BenchmarkDotNet – Measure before you optimize
![BenchmarkDotnet](BenchmarkDotnet.png)
BenchmarkDotNet makes it simple to **benchmark .NET code with precision**.
- Easy setup with `[Benchmark]` attributes
- Generates detailed performance reports
- Works with .NET Core, .NET Framework, and Mono
Perfect for spotting bottlenecks in APIs, background services, or CPU-bound operations.
- **NuGet** (40M downloads) 🔗 https://www.nuget.org/packages/BenchmarkDotNet
- **GitHub** (11k stars) 🔗 https://github.com/dotnet/BenchmarkDotNet
------
## 2. MessagePack – Fastest JSON serializer
Need speed beyond System.Text.Json or Newtonsoft.Json ? MessagePack is the fastest serializer for C# (.NET, .NET Core, Unity, Xamarin). MessagePack has a compact binary size and a full set of general purpose expressive data types. Ideal for high-traffic APIs, IoT data processing, and microservices.
![MessagePack Benchmark](MessagePack.png)
- **NuGet** (204M downloads) 🔗 https://www.nuget.org/packages/messagepack
- **GitHub** (6.4K stars) 🔗 https://github.com/MessagePack-CSharp/MessagePack-CSharp
------
## 3. Polly – Resilience at scale
![Polly](Polly.png)
In distributed systems, failures are inevitable. **Polly** provides a fluent way to add **retry, circuit-breaker, and fallback** strategies.
- Handle transient faults gracefully
- Improve uptime and user experience
- Works seamlessly with HttpClient and gRPC
A must-have for cloud-native .NET applications.
- **NuGet** (1B downloads) 🔗 https://www.nuget.org/packages/polly/
- **GitHub** (14K stars) 🔗 https://github.com/App-vNext/Polly
------
## 4. MemoryPack – Zero-cost binary serialization
If you need **blazing-fast serialization** for in-memory caching or network transport, **MemoryPack** is a game-changer.
- Zero-copy, zero-alloc serialization
- Perfect for high-performance caching or game servers
- Strongly typed and version-tolerant
![MemoryPack](MemoryPack.png)
Great for real-time multiplayer games, chat apps, or financial systems.
- **NuGet** (5.3M downloads) 🔗 https://www.nuget.org/packages/MemoryPack
- **GitHub** (4K stars) 🔗 https://github.com/Cysharp/MemoryPack
------
## 5. WolverineFx – Ultra-low latency messaging
![wolverine](wolverine-logo.png)
MediatR was one of the best mediator library but now it's a paid library. Wolverine is a toolset for command execution and message handling within .NET applications. The killer feature of Wolverine is its very efficient command execution pipeline that can be used as:
- An [inline "mediator" pipeline](https://wolverinefx.net/tutorials/mediator.html) for executing commands
- A [local message bus](https://wolverinefx.net/guide/messaging/transports/local.html) for in-application communication
- A full-fledged [asynchronous messaging framework](https://wolverinefx.net/guide/messaging/introduction.html) for robust communication and interaction between services when used in conjunction with low level messaging infrastructure tools like RabbitMQ
- With the [WolverineFx.Http](https://wolverinefx.net/guide/http/) library, Wolverine's execution pipeline can be used directly as an alternative ASP.Net Core Endpoint provider
*Below image is from [codecrash.net](https://www.codecrash.net/2024/02/06/Mediatr-versus-Wolverine-performance.html)*
![WolverineFx](wolverine.png)
WolverineFx is great for cleanly separating business logic from controllers while unifying in-process mediator patterns with powerful distributed messaging in a single, high-performance .NET library.
- **NuGet** (1.5M downloads) 🔗 https://www.nuget.org/packages/WolverineFx
- **GitHub** (1.7K stars) 🔗 https://github.com/JasperFx/wolverine
## 6. Disruptor-net – Next generation free .NET mediator
The Disruptor is a high performance inter-thread message passing framework. A lock-free ring buffer for ultra-low latency messaging.
features are:
- Zero memory allocation after initial setup (the events are pre-allocated).
- Push-based consumers.
- Optionally lock-free.
- Configurable wait strategies.
![Disruptor](Disruptor.png)
- **NuGet** (1.2M downloads) 🔗 https://www.nuget.org/packages/Disruptor/
- **GitHub** (1.3K stars) 🔗 https://github.com/disruptor-net/Disruptor-net
## 7. CliWrap - Running command-line processes
![CLIWrap](C:\Users\alper\Desktop\high-perf-dotnet-libs\cliwrap.png)
CliWrap makes it easy to **run and manage external CLI processes in .NET**.
- Fluent, task-based API for starting commands
- Streams standard input/output and error in real time
- Supports cancellation, timeouts, and piping between processes
Ideal for automation, build tools, and integrating external executables.
- **NuGet** (14.1M downloads) 🔗 https://www.nuget.org/packages/CliWrap
- **GitHub** (4.7K stars) 🔗 https://github.com/Tyrrrz/CliWrap
---
## Hidden Libs from the Community
### Sylvan.Csv & **Sep**
- **Sylvan.Csv**: Up to *10× faster* and *100× less memory allocations* than `CsvHelper`, making CSV processing lightning-fast. ([Reddit](https://www.reddit.com/r/csharp/comments/191rwgt/extremely_highperformance_libraries_for_common/?utm_source=chatgpt.com))
- **Sep**: Even faster than Sylvan, but trades off some flexibility. Great when performance matters more than API richness. ([Reddit](https://www.reddit.com/r/csharp/comments/191rwgt/extremely_highperformance_libraries_for_common/?utm_source=chatgpt.com))
### String Parsing: **csFastFloat**
- Parses `float` and `double` around *8–9× faster* than `.Parse` methods—perfect for high-volume parsing tasks. ([Reddit](https://www.reddit.com/r/csharp/comments/191rwgt/extremely_highperformance_libraries_for_common/?utm_source=chatgpt.com))
### CySharp’s Suite: MemoryPack, MasterMemory, SimdLinq
- **MemoryPack**: One of the fastest serializers available, with low allocations and high throughput. Ideal for Web APIs or microservices. ([Reddit](https://www.reddit.com/r/csharp/comments/191rwgt/extremely_highperformance_libraries_for_common/?utm_source=chatgpt.com))
- **MasterMemory**: Designed for databases or config storage. Claims *4,700× faster than SQLite* with zero-allocations per query. ([Reddit](https://www.reddit.com/r/csharp/comments/191rwgt/extremely_highperformance_libraries_for_common/?utm_source=chatgpt.com))
- **SimdLinq**: SIMD-accelerated LINQ operations supporting a broader set of methods than .NET's built-in SIMD. Works when slight floating-point differences are acceptable. ([Reddit](https://www.reddit.com/r/csharp/comments/191rwgt/extremely_highperformance_libraries_for_common/?utm_source=chatgpt.com))
### Jil – JSON Deserializer
- Ultra-fast JSON (de)serializer with low memory overhead, used in high-scale systems. ([Performance is a Feature!](https://www.mattwarren.org/2014/09/05/stack-overflow-performance-lessons-part-2/?utm_source=chatgpt.com))
### StackExchange.NetGain – WebSocket Efficiency
- High-performance WebSocket server library designed for low-latency IO scenarios. (Now mostly replaced by Kestrel's built-in support, but worth knowing.) ([GitHub](https://github.com/StackExchange/NetGain?utm_source=chatgpt.com))
### Math Libraries: Math.NET Numerics & ILNumerics
- **Math.NET Numerics**: Core numerical methods and matrix math, similar to BLAS/LAPACK. ([Wikipedia](https://en.wikipedia.org/wiki/Math.NET_Numerics?utm_source=chatgpt.com))
- **ILNumerics**: Efficient numerical arrays with parallelized processing, loop unrolling, cache optimizations. Great for scientific computing. ([Wikipedia](https://en.wikipedia.org/wiki/ILNumerics?utm_source=chatgpt.com))

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/cliwrap.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/wolverine-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

BIN
docs/en/Community-Articles/2025-09-11-High-Perf-DotNet-Libs/wolverine.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/images/img_9.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

282
docs/en/Community-Articles/2025-09-11-Web-Design-Basics-for-Graphic-Designers-Who-Dont-Code/post.md

@ -0,0 +1,282 @@
# Web Design Basics for Graphic Designers Who Don't Code
## Introduction
As a **designer**, I have been working on **logos**, **posters**, and **social media announcement** **visuals** for years. However, when it comes to the web, I used to hold back saying “I **don’t know how to code**.” We have all thought about this at some point and unfortunately, we still think about it from time to time.
🚀 **Good news**: We can learn **web design** without writing code and design **user-friendly**, **aesthetic, and functional web interfaces** using basic knowledge.
In this article, we will talk about the **basics of web design**, its **differences from graphic design**, and whether it is possible to do **web design without knowing how to code**.
## Differences Between Graphic Design & Web Design
![](images/img_2.png)
### What is Graphic Design?
Graphic design is creating **visual content** that conveys a message to a **specific audience**. Graphic designers use various **visual elements** such as **color**, **typography**, **imagery**, and **layout** to communicate a message effectively. They work on a wide range of projects, including **logos**, **websites**, **packaging**, **advertisements, and branding**.
### What is Web Design?
Web design is the process of creating a website that can be viewed on computers or mobile devices. Like graphic design, web design also involves creating **graphics**, **typography**, **and visuals**, but they use the **internet** as the communication channel.
### Graphic Design
* Graphic Design is concerned with **visuals** and **appearance**.
* Graphic design focuses on visually conveying specific messages or ideas through **typography**, **visuals**, **colors**, and i**llustrations**.
* Graphic design focuses on how objects **look**.
* Graphic designers **do not need coding knowledge**.
* Graphic design is **static**.
### Web Design
* Web design is user experience–focused.
* Web design aims to create **functional** and **user-friendly** **websites** that provide the **best experience** for users.
* Web design considers **search engine optimization** when creating websites.
* Web designers need to have **knowledge of HTML**, **CSS**, and other web development languages to create **functional and responsive designs**.
* Web design is **dynamic**.
## Fundamental Principles of Web Design (Applicable Without Coding)
Companies and **brands** from almost every sector request the **creation of their own websites**. This way, they gain the opportunity to introduce their **services**, **prices**, and themselves to their **target audiences**. However, for this to have the desired effect, the website must be **designed properly**. What are the **fundamental principles** to pay attention to when designing a website? Now, it’s time to answer this question by introducing the basics. Here are the **indispensable principles in web design**.
### 1\) User-Centered Designs:
Users always value **ease and practicality** when receiving a service. For this reason, it is important for websites to be designed in a user-centered way. **Easy to find menus**, **fast usage**, and the **easy to locate any information** are very important. With **user centered design**, it is possible to create websites that are **easy to use** and also **satisfy users**.
### 2\) Responsive Designs:
It is very important for the website and its design to be **usable on every digital platform**. Therefore, the designed sites must have a **responsive design**. This means easy access to the site on a **phone**, **tablet**, or **computer**. This also ensures that users continue to prefer the site.
### 3\) Visual Hierarchy:
The page must have **visuals related to itself**, and **product content** should be matched with the **correct visuals**. It is also very important for visual elements to be placed according to their order of importance. On web pages, content compatible with visuals must be provided with **sufficient and accurate information**.
### 4\) Color and Typography Selection:
Color and typography selection is very important for handling visuals, colors, and text in a certain **harmony**. For the site to **attract attention** or for the relevant pages to achieve the expected interaction, the use of color and the chosen font style and font color must be harmonious. A design that is both **easy to read** and **eye catching** without causing any disturbance should be preferred.
### 5\) Content and Layout Structure:
One of the most desired features on web pages is **content organization**. Content that is **unrelated to the pages, creates confusion while reading**, or **lacks simplicity**, such as overly frequent paragraphs, incorrect fonts, and similar factors, causes web pages to have less impact. **Content structure** also includes **placing related topics sequentially** and **adding them to the menu**. For example, on a website created for shoes, if shoe types are grouped separately, users find it easier. Options like high heels, sandals, and sneakers help users find what they are looking for more easily, which in turn ensures positive site feedback.
### 6\) Speed Optimization:
As with every type of service, speed is very important for services provided through web pages. Easy navigation between pages, error-free performance, and ease of use are very important for users. No one wants to shop or use a service on a website that takes a long time to load, because everyone prefers websites to save time.
### 7\) Consistency:
For a service to be preferred, it must first be reliable. This is directly related to the information, visuals, and everything on the website. The information in the content, visuals, and content details must be consistent and should not raise any questions in visitors’ minds. Otherwise, negative feedback can later affect customer preferences and damage the brand image.
## Is It Possible to Do Web Design Without Coding?
In the past, it was not possible to create a website without at least some basic coding knowledge. However, today, almost anyone can build a website. Even if you have not written a **single line of code**.
The biggest helpers for those who want to do **web development without coding** are **No-Code** and **Low-Code** platforms. These tools help users **design websites** without dealing with **technical details**.
Systems like **Wix**, **Webflow**, **Shopify**, and **WordPress** are very common in this area.
![](images/img_3.png)
The web development process on these platforms is carried out through practical methods such as **drag-and-drop**, selecting **ready-made templates**, and filling out forms.
### **No Code**
As the name suggests, it allows you to create websites, mobile applications, automations, and workflows **without writing a single line of code**.
* **How Does It Work**? They usually have a visual editor. You create the skeleton of your application by dragging and dropping ready “building blocks” such as buttons, forms, and visuals onto your canvas. Then, you determine what these elements will do (for example, “go to this page when this button is clicked”) by selecting options from the menus.
* **Who Uses It**? It is perfect for entrepreneurs, marketers, product managers, designers, and anyone who wants to quickly test an idea.
* **Examples**: Platforms like Webflow, Bubble, Adalo, and Glide allow you to create a wide range of products, from complex web applications to mobile apps.
### **Low Code**
Low-Code systems require a bit more **technical knowledge** but still **do not require learning full-scale programming**.
* **How Does It Work**? You handle 80% of the work with drag-and-drop, and for the remaining 20% that requires customization, you add small code snippets.
* **Who Uses It**? It is generally preferred by IT departments of corporate companies and technical teams that want to develop more complex, scalable applications.
* **Examples**: Platforms like OutSystems and Mendix are used to build large, integrated systems that manage a company’s internal processes.
## What Should the Web Design Process be Like?
![](images/img_4.png)
**Web design** is a passionate field but can be **overwhelming** at times. When starting out, coming up with a plan on how to tackle your website or a web app idea often feels daunting: Where should you begin?Web designers often think about the **web design process** with a focus on **technical matters** such as wireframes, code, and content management. But great
design isn’t about how you integrate the social media buttons or even slick visuals. **Great design** is actually about having **a website creation process** that aligns with an **overarching strategy.**
Doing all the thinking beforehand ensures that you don’t forget anything crucial. It also frees up headspace for doing the actual work, avoids overwhelm, improves efficiency, and allows you to build better websites on repeat.
But how do you achieve that harmonious synthesis of elements? Through a **holistic web design** process that takes both **form and function** into account.
We have already covered the fundamentals, now, I'll share the steps to an **effective web design process.**
Let's get started.
### 1\) Goal Identification
In this **initial stage**, the designer needs to identify the end goal of the website design, usually in close collaboration with the client or other stakeholders. Questions to explore and answer in this stage of the design and website development process include:
* Who is the site for?
* What do they hope to find or do there?
* Is the main purpose of this website to inform, to sell (e-commerce, for everyone?), or to entertain?
* Does the website need to clearly convey the **brand's core message**, or is it part of a broader **brand strategy** with its own unique focus?
* If there are any, which **competitor sites** exist, and how should this site be **inspired by them** / how should it differ from them?
To have clear answers to above questions will lead to the **successful execution** of the project.
### What Purpose Will the Website Serve?
Whatever the project you’re taking on, you always want each and every initiative you take to achieve the goals you’ve set for it. **Goal setting is critical** because it will be key in making decisions throughout the project by asking yourself the right questions and **prioritizing tasks and efforts**.
As basic as it may seem, following the **SMART framework** is always a great idea when setting your goals, to **ensure effectiveness:**
**S \- SPECIFIC**
Your goal is direct, detailed, and meaningful.
**M \- MEASURABLE**
Your goal is quantifiable to track progress or success.
**A \- ATTAINABLE**
Your goal is realistic and you have the tools and/or resources to attain it.
**R \- RELEVANT**
Your goal aligns with your company mission.
**T \- TIME-BASED**
Your goal has a deadline.
### 2\) Scope Definition
This is easier said than done when starting out, so it is best to approach it with caution : Everyone has once been guilty of saying a project “will be done by next week” before realizing they dramatically **underestimated** how hard it would be.
Nevertheless, **setting** a timeline will help a lot with **accountability**, both internal and external, and will help **break down the project in distinct stages**.
You don’t have to reinvent anything from scratch, as a lot of tools such as Airtable’s timeline view will help you put the timeline together.
![](images/img_5.png)
Source: [Airtable](https://blog.airtable.com/introducing-airtables-new-timeline-view/)
### 3\) Sitemap and Wireframe Creation
The site map forms the foundation of a well-designed website. It gives web designers a clear idea of the **information architecture** of the website and explains the **relationships** between various **pages and content elements**.
![](images/img_6.png)
Building a web site without a site map is like building a house without a plan. And it rarely ends well.
Time to start building the first iteration of your project\! To put it shortly, **wireframes** serve as a blueprint, a visual guide representing the skeletal framework of a website or application. It will be a raw version of your project, a great way to get your **initial idea down** in its first “physical” form.
![](images/img_7.png)
Source: [Afolayan Daniel](https://medium.com/fbdevclagos/4-reasons-why-wire-frame-is-important-during-website-or-mobile-app-development-46fabdf47190)
While it won’t be functional yet, it’ll be a major web design step to share with your team, potential leads or even investors, and will highlight issues that you might not have thought about previously. Wireframes are a great opportunity to move fast, once they’re ready, you’ll be able to:
* Gather early feedback;
* Run UX testing groups;
* Iterate on your timeline if necessary;
* Get concept validation.
There are different ways to create wireframes. You can of course sketch them out on paper to start with, but creating a digital version will eventually be much more practical to share them.
#### Tools for sitemapping and wireframing;
* Pen/pencil and paper.
* Balsamiq.
* Moqups.
* Sketch.
* Axure.
* Webflow.
* Slickplan.
* Writemaps.
* Mindnode.
* Figma.
* Sketch.
### 4\) Content Creation
A website should offer more than just a simple design and attractive graphics. An effective content strategy is essential to capture users’ interest and to make the site stand out in search engines.
![](images/img_8.png)
When it comes to content, search engine optimization is only
half of the battle.
There are two main goals that you need to focus on while creating content.
#### **Goal 1 Content encourages engagement and action:**
First of all, content drives readers to take action and encourages them to perform the actions necessary to achieve a site's goals. This is influenced both by the content itself (writing) and by the way it is presented (typography and structural elements).
Boring, lifeless, and lengthy writing rarely holds visitors' attention for long enough. Short, fluent, and engaging content captures them and makes them click through to other pages. Even if your pages need a lot of content (which they often do), properly "breaking it up" into short paragraphs supported by visuals can help create a light and engaging feel.
#### **Goal 2 Search Engine Optimization**:
Content also increases a site's visibility in the eyes of search engines. The practice of creating and developing content to achieve a good ranking in search results is called search engine optimization or SEO.
Identifying your keywords and key phrases correctly is very important for the success of any website.
### 5\) Visual Elements
![](images/img_9.png)
Style Tile: a free style tile / moodboard template built by Mat Vogels.
It is time to create the **visual style** of the site. This part of the design process is usually shaped by **existing brand elements, color choices**, and **logos** specified by the client. However, it is also the stage of the web design process where a **good web designer can truly shine**.
**Visuals play a more important** **role** in web design than ever before. High quality visuals not only give a website a professional look and feel, but also convey a message, are mobile friendly, and help build trust.
**Visual design is a way of communicating** with the web site users to make the site as **appealing to them** as possible. When done right, it can determine the site’s being one of the major successes amongst competitors. On the other hand, any mistake might put it in risk of becoming just another ordinary web site.
**Tools for visual elements**:
* (Sketch, Illustrator, Photoshop, Figma, vb.)
* Visual Style Guides.
### 6\) Development & Platforms
**Front-End Development**: The parts that users interact with (HTML, CSS, JavaScript).
**Back-End Developmen**t: Database and server-side processes (PHP, Python, Node.js).
**No-Code Platforms**: Publishing on platforms like Webflow, Bubble, Adalo, Glide.
### 7\) Testing
When your site has all the visuals and content, you are ready to test.
Once the **first iteration** of your website/web app is ready, it’s time for some **testing** to make sure it **runs smoothly**.
A website should undergo a detailed testing process before going live.
Items to check during the testing process:
* Mobile Compatibility.
* Functionality across different browsers.
* Functionality of forms and buttons.
Alongside these steps, setting up website uptime monitoring is essential to ensure the site remains functional after launch, providing immediate alerts if any downtime occurs. Ultimately, while testing is an important part of the web design process, it’s not worth losing sleep over. **Done is always better than perfect** and when in doubt, keep this quote in mind.
*“If you are not embarrassed by the first version of your product, you've launched too late.” \- Reid Hoffman, founder of LinkedIn*
### 8\) Website Launch
Now it’s time for everyone’s favorite part of the website design process: When everything has been thoroughly tested and you’re happy with the site, you can start.
Don’t expect this to go perfectly. There may still be some elements that need fixing. Web design is a fluid and ongoing process that requires constant maintenance.
Web design and design in general is about finding the right balance between form and function. You need to use the right fonts, colors, and design motifs. But the way users navigate and experience your site is just as important.
## Conclusion
Previously, when we wanted to turn our designs into reality, the barrier of learning and using a programming language tool stood in our way. This barrier has now been removed thanks to **No-Code tools**. With these tools, even without coding knowledge, there is now a way to bring your designs to life.
## Resources
* Bulut, B. (2025, July 20). *Kod yazmayı bilmeden yazılımcı olmak nasıl mümkün oldu?* Webtekno. [https://www.webtekno.com/kod-bilmeden-yazilimci-olmak-nasil-mumkun-oldu-h159799.html](https://www.webtekno.com/kod-bilmeden-yazilimci-olmak-nasil-mumkun-oldu-h159799.html)
* Ectasarim. (2024, Kasım 10). *Web tasarım ilkeleri nelerdir? Önemli hususlar*. [https://www.ectasarim.com/web-tasarim-ilkeleri/](https://www.ectasarim.com/web-tasarim-ilkeleri/?utm_source=chatgpt.com)
* Meazey, M. (2020, February 12). *The web design process in 7 simple steps*. *Webflow Blog*. [https://webflow.com/blog/the-web-design-process-in-7-simple-steps](https://webflow.com/blog/the-web-design-process-in-7-simple-steps)
* University of California Office of the President. (2016). *How to write SMART goals: A how-to guide.* University of California. [https://www.ucop.edu/local-human-resources/\_files/performance-appraisal/How+to+write+SMART+Goals+v2.pdf](https://www.ucop.edu/local-human-resources/_files/performance-appraisal/How+to+write+SMART+Goals+v2.pdf)

28
docs/en/framework/fundamentals/localization.md

@ -91,6 +91,34 @@ A JSON localization file content is shown below:
> ABP will ignore (skip) the JSON file if the `culture` section is missing.
You can also use nesting or array in localization files, like this:
````json
{
"culture": "en",
"texts": {
"HelloWorld": "Hello World!",
"Hello": {
"World": "Hello World!"
},
"Hi":[
"Bye": "Bye World!"
"Hello": "Hello World!"
]
}
}
````
Then you can use it like this:
> The double underscore (`__`) is used to separate the parent key from the child key.
````csharp
var str = L["Hello__World"]; // Hello World!
var str2 = L["Hi__0"]; // Bye World!
var str3 = L["Hi__1"]; // Hello World!
````
### Default Resource
`AbpLocalizationOptions.DefaultResourceType` can be set to a resource type, so it is used when the localization resource was not specified:

183
docs/en/release-info/migration-guides/AutoMapper-To-Mapperly.md

@ -56,7 +56,7 @@ public class ExampleAutoMapper : Profile
And the Mapperly mapping class:
```csharp
[Mapper]
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
[MapExtraProperties]
public partial class IdentityUserToIdentityUserDtoMapper : MapperBase<IdentityUser, IdentityUserDto>
{
@ -71,7 +71,7 @@ public partial class IdentityUserToIdentityUserDtoMapper : MapperBase<IdentityUs
public override partial void Map(IdentityUser source, IdentityUserDto destination);
}
[Mapper]
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class IdentityUserClaimToIdentityUserClaimDtoMapper : MapperBase<IdentityUserClaim, IdentityUserClaimDto>
{
public override partial IdentityUserClaimDto Map(IdentityUserClaim source);
@ -79,7 +79,7 @@ public partial class IdentityUserClaimToIdentityUserClaimDtoMapper : MapperBase<
public override partial void Map(IdentityUserClaim source, IdentityUserClaimDto destination);
}
[Mapper]
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
[MapExtraProperties]
public partial class OrganizationUnitToOrganizationUnitDtoMapper : MapperBase<OrganizationUnit, OrganizationUnitDto>
{
@ -87,7 +87,7 @@ public partial class OrganizationUnitToOrganizationUnitDtoMapper : MapperBase<Or
public override partial void Map(OrganizationUnit source, OrganizationUnitDto destination);
}
[Mapper]
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class OrganizationUnitRoleToOrganizationUnitRoleDtoMapper : TwoWayMapperBase<OrganizationUnitRole, OrganizationUnitRoleDto>
{
public override partial OrganizationUnitRoleDto Map(OrganizationUnitRole source);
@ -97,7 +97,7 @@ public partial class OrganizationUnitRoleToOrganizationUnitRoleDtoMapper : TwoWa
public override partial void ReverseMap(OrganizationUnitRoleDto destination, OrganizationUnitRole source);
}
[Mapper]
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
[MapExtraProperties]
public partial class OrganizationUnitToOrganizationUnitWithDetailsDtoMapper : MapperBase<OrganizationUnit, OrganizationUnitWithDetailsDto>
{
@ -110,7 +110,7 @@ public partial class OrganizationUnitToOrganizationUnitWithDetailsDtoMapper : Ma
public override partial void Map(OrganizationUnit source, OrganizationUnitWithDetailsDto destination);
}
[Mapper]
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class IdentityRoleToOrganizationUnitRoleDtoMapper : MapperBase<IdentityRole, OrganizationUnitRoleDto>
{
[MapProperty(nameof(IdentityRole.Id), nameof(OrganizationUnitRoleDto.RoleId))]
@ -120,7 +120,7 @@ public partial class IdentityRoleToOrganizationUnitRoleDtoMapper : MapperBase<Id
public override partial void Map(IdentityRole source, OrganizationUnitRoleDto destination);
}
[Mapper]
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class IdentityUserToIdentityUserExportDtoMapper : MapperBase<IdentityUser, IdentityUserExportDto>
{
[MapperIgnoreTarget(nameof(IdentityUserExportDto.Roles))]
@ -143,7 +143,7 @@ public partial class IdentityUserToIdentityUserExportDtoMapper : MapperBase<Iden
To use Mapperly, you'll need to create a dedicated mapping class for each source and destination types.
* Use the `[Mapper]` attribute to designate the class as a Mapperly mapper.
* Use the `[Mapper]` attribute to designate the class as a Mapperly mapper. The `RequiredMappingStrategy` is set to `Target` by default.
* Replace AutoMapper's `Ignore()` method with the `[MapperIgnoreTarget]` attribute.
* Replace the `MapExtraProperties()` method with the `[MapExtraProperties]` attribute.
* Use the `TwoWayMapperBase` class as an alternative to AutoMapper’s `ReverseMap()` functionality.
@ -151,11 +151,12 @@ To use Mapperly, you'll need to create a dedicated mapping class for each source
### Dependency Injection in Mapper Class
All Mapperly mapping classes automatically registered in the the [dependency injection (DI)](../../framework/fundamentals/dependency-injection.md) container. To use a service within a Mapper class, simply add it to the constructor, Mapperly will inject it automatically.
All Mapperly mapping classes automatically registered in the [dependency injection (DI)](../../framework/fundamentals/dependency-injection.md) container. To use a service within a Mapper class, simply add it to the constructor; Mapperly will inject it automatically.
**Example:**
```csharp
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class IdentityUserToIdentityUserDtoMapper : MapperBase<IdentityUser, IdentityUserDto>
{
public IdentityUserToIdentityUserDtoMapper(MyService myService)
@ -173,6 +174,170 @@ public partial class IdentityUserToIdentityUserDtoMapper : MapperBase<IdentityUs
}
```
## AI Prompt for Migrating AutoMapper to Mapperly
If you have AI tools like Cursor, you can use the following prompt to migrate your AutoMapper mappings to Mapperly automatically:
> AI may generate some code that is not correct. Please check the code carefully.
```
Please help me migrate AutoMapper Profile classes to Mapperly. I have AutoMapper Profile files in my current workspace/context that need to be converted.
**Conversion Requirements:**
1. **Convert AutoMapper Profile to Mapperly Mappers**: Transform each `CreateMap` into a separate Mapperly mapper class
2. **Rename the file**: Change from `XXXAutoMapperProfile.cs` to `XXXMappers.cs`
3. **Use proper Mapperly attributes**:
- `[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]` for each mapper class
- `[MapExtraProperties]` for classes that need extra properties mapping
- `[MapperIgnoreTarget]` for ignored properties
- `[MapProperty]` for custom property mappings
4. **Inherit from appropriate base classes**:
- `MapperBase<TSource, TDestination>` for one-way mapping
- `TwoWayMapperBase<TSource, TDestination>` for reverse mapping
5. **Handle complex mappings**: Use `AfterMap` method for complex transformations
**Note:** The code below contains two parts - both are reference examples for you to understand the conversion pattern:
1. **AutoMapper Profile example** - shows the original AutoMapper code structure
2. **Mapperly Mappers example** - shows the expected converted Mapperly code structure
Please convert the actual AutoMapper Profile files that exist in your current context/workspace, following the same conversion pattern as shown in these examples.
**Reference Examples:**
**1. AutoMapper Profile (original code):**
using System;
using AutoMapper;
using System.Linq;
using Volo.Abp.AutoMapper;
namespace Volo.Abp.Identity;
public class ExampleAutoMapperProfile : Profile
{
public ExampleAutoMapperProfile()
{
CreateMap<IdentityUser, IdentityUserDto>()
.MapExtraProperties()
.Ignore(x => x.IsLockedOut)
.Ignore(x => x.SupportTwoFactor)
.Ignore(x => x.RoleNames);
CreateMap<IdentityUserClaim, IdentityUserClaimDto>();
CreateMap<OrganizationUnit, OrganizationUnitDto>()
.MapExtraProperties();
CreateMap<OrganizationUnitRole, OrganizationUnitRoleDto>()
.ReverseMap();
CreateMap<IdentityRole, OrganizationUnitRoleDto>()
.ForMember(dest => dest.RoleId, src => src.MapFrom(r => r.Id));
CreateMap<IdentityUser, IdentityUserExportDto>()
.ForMember(dest => dest.Active, src => src.MapFrom(r => r.IsActive ? "Yes" : "No"))
.ForMember(dest => dest.EmailConfirmed, src => src.MapFrom(r => r.EmailConfirmed ? "Yes" : "No"))
.ForMember(dest => dest.TwoFactorEnabled, src => src.MapFrom(r => r.TwoFactorEnabled ? "Yes" : "No"))
.ForMember(dest => dest.AccountLookout, src => src.MapFrom(r => r.LockoutEnd != null && r.LockoutEnd > DateTime.UtcNow ? "Yes" : "No"))
.Ignore(x => x.Roles);
}
}
---
**2. Mapperly Mappers (converted code):**
using System;
using System.Linq;
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;
namespace Volo.Abp.Identity;
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
[MapExtraProperties]
public partial class IdentityUserToIdentityUserDtoMapper : MapperBase<IdentityUser, IdentityUserDto>
{
[MapperIgnoreTarget(nameof(IdentityUserDto.IsLockedOut))]
[MapperIgnoreTarget(nameof(IdentityUserDto.SupportTwoFactor))]
[MapperIgnoreTarget(nameof(IdentityUserDto.RoleNames))]
public override partial IdentityUserDto Map(IdentityUser source);
[MapperIgnoreTarget(nameof(IdentityUserDto.IsLockedOut))]
[MapperIgnoreTarget(nameof(IdentityUserDto.SupportTwoFactor))]
[MapperIgnoreTarget(nameof(IdentityUserDto.RoleNames))]
public override partial void Map(IdentityUser source, IdentityUserDto destination);
}
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class IdentityUserClaimToIdentityUserClaimDtoMapper : MapperBase<IdentityUserClaim, IdentityUserClaimDto>
{
public override partial IdentityUserClaimDto Map(IdentityUserClaim source);
public override partial void Map(IdentityUserClaim source, IdentityUserClaimDto destination);
}
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
[MapExtraProperties]
public partial class OrganizationUnitToOrganizationUnitDtoMapper : MapperBase<OrganizationUnit, OrganizationUnitDto>
{
public override partial OrganizationUnitDto Map(OrganizationUnit source);
public override partial void Map(OrganizationUnit source, OrganizationUnitDto destination);
}
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class OrganizationUnitRoleToOrganizationUnitRoleDtoMapper : TwoWayMapperBase<OrganizationUnitRole, OrganizationUnitRoleDto>
{
public override partial OrganizationUnitRoleDto Map(OrganizationUnitRole source);
public override partial void Map(OrganizationUnitRole source, OrganizationUnitRoleDto destination);
public override partial OrganizationUnitRole ReverseMap(OrganizationUnitRoleDto destination);
public override partial void ReverseMap(OrganizationUnitRoleDto destination, OrganizationUnitRole source);
}
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
[MapExtraProperties]
public partial class OrganizationUnitToOrganizationUnitWithDetailsDtoMapper : MapperBase<OrganizationUnit, OrganizationUnitWithDetailsDto>
{
[MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.Roles))]
[MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.UserCount))]
public override partial OrganizationUnitWithDetailsDto Map(OrganizationUnit source);
[MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.Roles))]
[MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.UserCount))]
public override partial void Map(OrganizationUnit source, OrganizationUnitWithDetailsDto destination);
}
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class IdentityRoleToOrganizationUnitRoleDtoMapper : MapperBase<IdentityRole, OrganizationUnitRoleDto>
{
[MapProperty(nameof(IdentityRole.Id), nameof(OrganizationUnitRoleDto.RoleId))]
public override partial OrganizationUnitRoleDto Map(IdentityRole source);
[MapProperty(nameof(IdentityRole.Id), nameof(OrganizationUnitRoleDto.RoleId))]
public override partial void Map(IdentityRole source, OrganizationUnitRoleDto destination);
}
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class IdentityUserToIdentityUserExportDtoMapper : MapperBase<IdentityUser, IdentityUserExportDto>
{
[MapperIgnoreTarget(nameof(IdentityUserExportDto.Roles))]
public override partial IdentityUserExportDto Map(IdentityUser source);
[MapperIgnoreTarget(nameof(IdentityUserExportDto.Roles))]
public override partial void Map(IdentityUser source, IdentityUserExportDto destination);
public override void AfterMap(IdentityUser source, IdentityUserExportDto destination)
{
destination.Active = source.IsActive ? "Yes" : "No";
destination.EmailConfirmed = source.EmailConfirmed ? "Yes" : "No";
destination.TwoFactorEnabled = source.TwoFactorEnabled ? "Yes" : "No";
destination.AccountLookout = source.LockoutEnd != null && source.LockoutEnd > DateTime.UtcNow ? "Yes" : "No";
}
}
```
## Mapperly Documentation
Please refer to the [Mapperly documentation](https://mapperly.riok.app/docs/intro/) for more details.

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs

@ -69,6 +69,7 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency
var newProTemplate = !string.IsNullOrEmpty(template) && template == ModuleProTemplate.TemplateName;
var withSourceCode = newTemplate || newProTemplate || commandLineArgs.Options.ContainsKey(Options.SourceCode.Long);
var addSourceCodeToSolutionFile = withSourceCode && commandLineArgs.Options.ContainsKey("add-to-solution-file");
var skipOpeningDocumentation = commandLineArgs.Options.ContainsKey(Options.SkipOpeningDocumentation.Long);
var skipDbMigrations = newTemplate || newProTemplate || commandLineArgs.Options.ContainsKey(Options.DbMigrations.Skip);
var solutionFile = GetSolutionFile(commandLineArgs);
@ -98,7 +99,8 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency
withSourceCode,
addSourceCodeToSolutionFile,
newTemplate,
newProTemplate
newProTemplate,
skipOpeningDocumentation
);
_lastAddedModuleInfo = new AddModuleInfoOutput
@ -223,5 +225,10 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency
public const string Short = "t";
public const string Long = "template";
}
public class SkipOpeningDocumentation
{
public const string Long = "skip-opening-documentation";
}
}
}

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularSourceCodeAdder.cs

@ -14,11 +14,11 @@ namespace Volo.Abp.Cli.ProjectModification;
public class AngularSourceCodeAdder : ITransientDependency
{
public ILogger<SolutionModuleAdder> Logger { get; set; }
public ILogger<AngularSourceCodeAdder> Logger { get; set; }
public AngularSourceCodeAdder()
{
Logger = NullLogger<SolutionModuleAdder>.Instance;
Logger = NullLogger<AngularSourceCodeAdder>.Instance;
}
public async Task AddFromModuleAsync(string solutionFilePath, string angularPath)

12
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

@ -98,7 +98,8 @@ public class SolutionModuleAdder : ITransientDependency
bool withSourceCode = false,
bool addSourceCodeToSolutionFile = false,
bool newTemplate = false,
bool newProTemplate = false)
bool newProTemplate = false,
bool skipOpeningDocumentation = false)
{
Check.NotNull(solutionFile, nameof(solutionFile));
Check.NotNull(moduleName, nameof(moduleName));
@ -159,10 +160,13 @@ public class SolutionModuleAdder : ITransientDependency
await SetLeptonXAbpVersionsAsync(solutionFile, Path.Combine(modulesFolderInSolution, module.Name));
}
var documentationLink = module.GetFirstDocumentationLinkOrNull();
if (documentationLink != null)
if (!skipOpeningDocumentation)
{
CmdHelper.Open(documentationLink);
var documentationLink = module.GetFirstDocumentationLinkOrNull();
if (documentationLink != null)
{
CmdHelper.Open(documentationLink);
}
}
return module;

14
framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs

@ -26,6 +26,16 @@ public class ObjectToInferredTypesConverter : JsonConverter<object>
public override void Write(
Utf8JsonWriter writer,
object objectToWrite,
JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options);
JsonSerializerOptions options)
{
var runtimeType = objectToWrite.GetType();
if (runtimeType == typeof(object))
{
writer.WriteStartObject();
writer.WriteEndObject();
return;
}
JsonSerializer.Serialize(writer, objectToWrite, runtimeType, options);
}
}

72
framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using Microsoft.Extensions.Localization;
@ -47,12 +48,11 @@ public static class JsonLocalizationDictionaryBuilder
{
throw new AbpException("Can not parse json string. " + ex.Message);
}
if (jsonFile == null)
{
return null;
}
var cultureCode = jsonFile.Culture;
if (string.IsNullOrEmpty(cultureCode))
{
@ -61,18 +61,17 @@ public static class JsonLocalizationDictionaryBuilder
var dictionary = new Dictionary<string, LocalizedString>();
var dublicateNames = new List<string>();
foreach (var item in jsonFile.Texts)
foreach (var item in FlattenTexts(jsonFile.Texts))
{
if (string.IsNullOrEmpty(item.Key))
{
throw new AbpException("The key is empty in given json string.");
}
if (dictionary.GetOrDefault(item.Key) != null)
{
dublicateNames.Add(item.Key);
}
dictionary[item.Key] = new LocalizedString(item.Key, item.Value.NormalizeLineEndings());
}
@ -85,4 +84,67 @@ public static class JsonLocalizationDictionaryBuilder
return new StaticLocalizationDictionary(cultureCode, dictionary);
}
private static Dictionary<string, string> FlattenTexts(Dictionary<string, object> texts, string prefix = "")
{
var result = new Dictionary<string, string>();
foreach (var text in texts)
{
var currentKey = string.IsNullOrEmpty(prefix) ? text.Key : $"{prefix}__{text.Key}";
switch (text.Value)
{
case JsonElement jsonElement:
foreach (var item in FlattenJsonElement(jsonElement, currentKey))
{
result[item.Key] = item.Value;
}
break;
case string str:
result[currentKey] = str;
break;
case null:
result[currentKey] = "";
break;
default:
result[currentKey] = text.Value.ToString() ?? "";
break;
}
}
return result;
}
private static IEnumerable<KeyValuePair<string, string>> FlattenJsonElement(JsonElement element, string prefix)
{
switch (element.ValueKind)
{
case JsonValueKind.String:
yield return new KeyValuePair<string, string>(prefix, element.GetString() ?? "");
break;
case JsonValueKind.Object:
foreach (var prop in element.EnumerateObject())
{
var newKey = $"{prefix}__{prop.Name}";
foreach (var item in FlattenJsonElement(prop.Value, newKey))
{
yield return item;
}
}
break;
case JsonValueKind.Array:
var i = 0;
foreach (var prop in element.EnumerateArray())
{
var newKey = $"{prefix}__{i}";
foreach (var item in FlattenJsonElement(prop, newKey))
{
yield return item;
}
i++;
}
break;
default:
yield return new KeyValuePair<string, string>(prefix, element.ToString());
break;
}
}
}

7
framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationFile.cs

@ -9,10 +9,5 @@ public class JsonLocalizationFile
/// </summary>
public string Culture { get; set; } = default!;
public Dictionary<string, string> Texts { get; set; }
public JsonLocalizationFile()
{
Texts = new Dictionary<string, string>();
}
public Dictionary<string, object> Texts { get; set; } = [];
}

54
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ObjectToInferredTypesConverter_Tests.cs

@ -0,0 +1,54 @@
using System.Text.Json;
using Shouldly;
using Xunit;
namespace Volo.Abp.Json;
public class ObjectToInferredTypesConverter_Tests : AbpJsonSystemTextJsonTestBase
{
private readonly IJsonSerializer _jsonSerializer;
public ObjectToInferredTypesConverter_Tests()
{
_jsonSerializer = GetRequiredService<IJsonSerializer>();
}
[Fact]
public void Test()
{
var objString = _jsonSerializer.Serialize(new object());
objString.ShouldBe("{}");
var obj = _jsonSerializer.Deserialize<object>(objString);
obj.ShouldBeOfType<JsonElement>();
var booleanString = _jsonSerializer.Serialize(true);
booleanString.ShouldBe("true");
var boolean = _jsonSerializer.Deserialize<bool>(booleanString);
boolean.ShouldBe(true);
var booleanString2 = _jsonSerializer.Serialize(false);
booleanString2.ShouldBe("false");
var boolean2 = _jsonSerializer.Deserialize<bool>(booleanString2);
boolean2.ShouldBe(false);
var numberString = _jsonSerializer.Serialize(1);
numberString.ShouldBe("1");
var number = _jsonSerializer.Deserialize<long>(numberString);
number.ShouldBe(1);
var numberString2 = _jsonSerializer.Serialize(1.1);
numberString2.ShouldBe("1.1");
var number2 = _jsonSerializer.Deserialize<double>(numberString2);
number2.ShouldBe(1.1);
var dateString = _jsonSerializer.Serialize(System.DateTime.Parse("2024-01-01"));
dateString.ShouldBe("\"2024-01-01T00:00:00\"");
var date = _jsonSerializer.Deserialize<System.DateTime>(dateString);
date.ShouldBe(System.DateTime.Parse("2024-01-01"));
var textString = _jsonSerializer.Serialize("text");
textString.ShouldBe("\"text\"");
var text = _jsonSerializer.Deserialize<string>(textString);
text.ShouldBe("text");
}
}

25
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs

@ -196,7 +196,7 @@ public class AbpLocalization_Tests : AbpIntegratedTest<AbpLocalizationTestModule
{
_localizer["CarPlural"].Value.ShouldBe("汽车");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hans-CN")))
{
_localizer["Car"].Value.ShouldBe("汽车");
@ -214,7 +214,7 @@ public class AbpLocalization_Tests : AbpIntegratedTest<AbpLocalizationTestModule
{
_localizer["CarPlural"].Value.ShouldBe("汽車");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-TW")))
{
_localizer["Car"].Value.ShouldBe("汽車");
@ -223,7 +223,7 @@ public class AbpLocalization_Tests : AbpIntegratedTest<AbpLocalizationTestModule
{
_localizer["CarPlural"].Value.ShouldBe("汽車");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hant-TW")))
{
_localizer["Car"].Value.ShouldBe("汽車");
@ -375,4 +375,21 @@ public class AbpLocalization_Tests : AbpIntegratedTest<AbpLocalizationTestModule
var externalLocalizer = _localizerFactory.CreateByResourceName(TestExternalLocalizationStore.TestExternalResourceNames.ExternalResource1);
externalLocalizer["Car"].Value.ShouldBe("Car");
}
}
[Fact]
public void Should_Get_Nested_Translations()
{
using (CultureHelper.Use("en"))
{
_localizer["MyNestedTranslation__SomeKey"].Value.ShouldBe("Some nested value");
_localizer["MyNestedTranslation__SomeOtherKey"].Value.ShouldBe("Some other nested value");
_localizer["MyNestedTranslation__DeeplyNested__DeepKey"].Value.ShouldBe("A deeply nested value");
_localizer["MyNestedTranslation__DeeplyNestedArray__0"].Value.ShouldBe("First value in array");
_localizer["MyNestedTranslation__DeeplyNestedArray__1"].Value.ShouldBe("Second value in array");
_localizer["MyNestedTranslation__DeeplyNestedArray__2__InnerDeepKey"].Value.ShouldBe("Inner deeply nested value");
_localizer["MyNestedTranslation__DeeplyNestedArray__3__InnerDeepArray__0"].Value.ShouldBe("First inner deep array value");
_localizer["MyNestedTranslation__DeeplyNestedArray__3__InnerDeepArray__1"].Value.ShouldBe("Second inner deep array value");
}
}
}

24
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json

@ -1,6 +1,26 @@
{
"culture": "en",
"texts": {
"SeeYou": "See you"
"SeeYou": "See you",
"MyNestedTranslation": {
"SomeKey": "Some nested value",
"SomeOtherKey": "Some other nested value",
"DeeplyNested": {
"DeepKey": "A deeply nested value"
},
"DeeplyNestedArray": [
"First value in array",
"Second value in array",
{
"InnerDeepKey": "Inner deeply nested value"
},
{
"InnerDeepArray": [
"First inner deep array value",
"Second inner deep array value"
]
}
]
}
}
}
}

9
latest-versions.json

@ -1,4 +1,13 @@
[
{
"version": "9.3.3",
"releaseDate": "",
"type": "stable",
"message": "",
"leptonx": {
"version": "4.3.3"
}
},
{
"version": "9.3.2",
"releaseDate": "",

74
modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs

@ -31,11 +31,8 @@ public partial class PermissionManagementModal
protected string _selectedTabName;
protected int _grantedPermissionCount = 0;
protected int _notGrantedPermissionCount = 0;
protected bool _selectAllDisabled;
protected string _permissionGroupSearchText;
protected bool GrantAll { get; set; }
@ -62,8 +59,8 @@ public partial class PermissionManagementModal
_groups = _allGroups.ToList();
NormalizePermissionGroup();
GrantAll = _notGrantedPermissionCount == 0;
GrantAll = _groups.SelectMany(x => x.Permissions).All(p => p.IsGranted);
await InvokeAsync(_modal.Show);
}
@ -76,17 +73,14 @@ public partial class PermissionManagementModal
protected virtual async Task GrantAllAsync(bool grantAll)
{
GrantAll = grantAll;
if (_allGroups == null)
{
return;
}
_grantedPermissionCount = 0;
_notGrantedPermissionCount = 0;
await OnPermissionGroupSearchTextChangedAsync(string.Empty);
foreach (var permission in _allGroups.SelectMany(x => x.Permissions))
{
if (IsDisabledPermission(permission))
@ -95,49 +89,28 @@ public partial class PermissionManagementModal
}
permission.IsGranted = grantAll;
if (grantAll)
{
_grantedPermissionCount++;
}
else
{
_notGrantedPermissionCount++;
}
}
await InvokeAsync(StateHasChanged);
}
protected virtual void NormalizePermissionGroup(bool checkDisabledPermissions = true)
{
_selectAllDisabled = _groups.All(IsPermissionGroupDisabled);
_grantedPermissionCount = 0;
_notGrantedPermissionCount = 0;
if (checkDisabledPermissions)
{
_disabledPermissions.Clear();
}
foreach (var permission in _groups.SelectMany(x => x.Permissions))
{
if (checkDisabledPermissions && permission.IsGranted && permission.GrantedProviders.All(x => x.ProviderName != _providerName))
{
_disabledPermissions.Add(permission);
continue;
}
if (permission.IsGranted)
{
_grantedPermissionCount++;
}
else
{
_notGrantedPermissionCount++;
}
}
foreach (var group in _groups)
{
SetPermissionDepths(group.Permissions, null, 0);
@ -210,7 +183,7 @@ public partial class PermissionManagementModal
return _permissionDepths.GetValueOrDefault(name, 0);
}
protected virtual void GroupGrantAllChanged(bool value, PermissionGroupDto permissionGroup)
protected virtual async Task GroupGrantAllChanged(bool value, PermissionGroupDto permissionGroup)
{
foreach (var permission in permissionGroup.Permissions)
{
@ -219,9 +192,12 @@ public partial class PermissionManagementModal
SetPermissionGrant(permission, value);
}
}
GrantAll = _groups.SelectMany(x => x.Permissions).All(p => p.IsGranted);
await InvokeAsync(StateHasChanged);
}
protected virtual void PermissionChanged(bool value, PermissionGroupDto permissionGroup, PermissionGrantInfoDto permission)
protected virtual async Task PermissionChanged(bool value, PermissionGroupDto permissionGroup, PermissionGrantInfoDto permission)
{
SetPermissionGrant(permission, value);
@ -238,6 +214,9 @@ public partial class PermissionManagementModal
SetPermissionGrant(childPermission, false);
}
}
GrantAll = _groups.SelectMany(x => x.Permissions).All(p => p.IsGranted);
await InvokeAsync(StateHasChanged);
}
private void SetParentPermissionGrant(PermissionGroupDto permissionGroup, PermissionGrantInfoDto permission)
@ -261,17 +240,6 @@ public partial class PermissionManagementModal
return;
}
if (value)
{
_grantedPermissionCount++;
_notGrantedPermissionCount--;
}
else
{
_grantedPermissionCount--;
_notGrantedPermissionCount++;
}
permission.IsGranted = value;
}
@ -338,22 +306,22 @@ public partial class PermissionManagementModal
return permissions.All(x => x.IsGranted) && grantedProviders.Any(p => p.ProviderName != _providerName);
}
protected virtual async Task OnPermissionGroupSearchTextChangedAsync(string value)
{
if (value == _permissionGroupSearchText)
{
return;
}
_permissionGroupSearchText = value;
_groups = _permissionGroupSearchText.IsNullOrWhiteSpace() ? _allGroups.ToList() : _allGroups.Where(x => x.DisplayName.Contains(_permissionGroupSearchText, StringComparison.OrdinalIgnoreCase) || x.Permissions.Any(permission => permission.DisplayName.Contains(_permissionGroupSearchText, StringComparison.OrdinalIgnoreCase))).ToList();
NormalizePermissionGroup(false);
await InvokeAsync(StateHasChanged);
}
protected virtual Task OnSelectedTabChangedAsync(string name)
{
_selectedTabName = name;

Loading…
Cancel
Save