Enhanced test coverage for the `InvokeAsync` method in the
`RecActions` client by adding three new test cases:
1. `InvokeAsync_returns_BatchRecActionViewResponse_on_success`:
- Verifies successful invocation with valid data.
- Includes checks for `TotalActionCount` and `ActionExceptionCount`.
2. `InvokeAsync_with_batchId_string_returns_BatchRecActionViewResponse`:
- Tests invocation with a `batchId` string argument.
- Handles scenarios where test data is unavailable.
3. `InvokeAsync_with_batchId_string_and_unknown_profile_throws_ReCApiException`:
- Confirms that an unknown profile ID throws a `ReCApiException`.
- Validates exception details like HTTP method and request URI.
These changes improve test robustness by covering success, edge,
and error scenarios for the `InvokeAsync` method.
Introduce the `BatchRecActionViewResponse` class to represent the
result of batch RecAction invocations, including total actions
processed and exceptions encountered.
Update `InvokeAsync` methods in `RecActionApi` to return a
`BatchRecActionViewResponse` instead of `void`. Modify the
implementation to deserialize API responses into this new class.
Add XML documentation for the updated return type and use
conditional compilation to handle nullable reference types
for .NET Framework and other target frameworks.
Refactored `BatchRecActionViewResponse` from a mutable class to an immutable record type with a constructor for `TotalActionCount` and a new `ActionExceptionCount` property. Moved the record to its own file under the `ReC.Application.Common.Dto` namespace.
Updated `InvokeBatchRecActionViewsCommand` and `InvokeRecActionViewsCommandHandler` to use the new record type. Removed `SuccessCount` and `FailureCount` properties, replacing them with `ActionExceptionCount`.
Performed minor cleanup, including removing the old class definition and updating namespaces.
- Remove unnecessary try-catch block in ShouldRead_Invalid_RecActionView test
- Code now directly awaits the query execution without exception handling
- Improves test readability and clarity
- Introduce BatchRecActionViewResponse to track execution metrics
- Add SuccessCount and FailureCount properties to monitor execution results
- Change InvokeBatchRecActionViewsCommand to return response data
- Update RecActionController to return Ok with response instead of Accepted
- Improve error handling to distinguish RecActionException from unexpected errors
- Consolidate exception handling logic for ErrorAction.Continue scenarios
- Replace NLog packages with Serilog.AspNetCore and related dependencies
- Add Serilog.UI with SQLite provider for log visualization
- Implement environment-based logging configuration:
* Development: Console output with simplified template
* Production: File-based logging with separate files per level
- Add SQLite sink for persistent log storage and web UI access
- Configure rolling file policies with configurable retention
- Update appsettings.Logging.json to use Serilog configuration format
- Enable Serilog self-diagnostics for troubleshooting
Refactored query handlers (`ReadProfileViewQueryHandler`,
`ReadRecActionViewQueryHandler`, and `ReadResultViewQueryHandler`)
to return empty results instead of throwing `NotFoundException`
when no data is found. Simplified the logic by removing null
or empty result checks and directly returning mapped results.
Updated corresponding test cases to align with the new behavior:
- Removed `try-catch` blocks for `NotFoundException`.
- Adjusted assertions to handle empty results.
- Removed the test case for `ReadRecActionViewQuery` that
expected `NotFoundException`.
This change reflects a design shift to let the calling code
handle empty results instead of relying on exceptions.
The `<DesktopBuildPackageLocation>` property in the `IISProfile.pubxml` file was updated to use the `PreRelease` folder instead of the `API` folder. This change reflects a new deployment strategy for pre-release builds.
Add an informational note to clarify the usage of the callback-based variant of `StaticBuildConfiguration`. Highlight that it is marked as `[Obsolete]` with the message: "Use a local service collection instead of the static provider."
Emphasize that while the `StaticBuildConfiguration` variant is recommended within the static path, the static path itself remains a convenience API. Reference Chapter 6 for additional context.
Modified the `ReC.sln` solution file to update the build
configuration for the project with GUID
`{DA3A6BDD-8045-478F-860B-D1F0EB97F02B}`:
- Changed `Debug|Any CPU` configuration from `Debug|Any CPU`
to `Release|Any CPU` for both `ActiveCfg` and `Build.0`.
- `Release|Any CPU` configuration remains unchanged.
No changes were made to other projects or configurations.
Updated `<PackageTags>` to better describe the package as a client library. Incremented `<Version>` to 2.0.0-beta, reflecting a major update. Synchronized `<AssemblyVersion>` and `<FileVersion>` to 2.0.0.0 for consistency with the new version.
Enhanced `RecActionApiTests` and `ResultApiTests` to handle flexible server responses, including `null` or `JsonElement` payloads, ensuring calls do not throw exceptions. Updated exception handling to allow undefined server behavior for unfiltered `GET` requests with no data.
Replaced hardcoded `FakeProfileId` with `TryResolveProfileIdAsync`, a dynamic method to resolve profile IDs from configuration or server queries. Added this method to `RecClientTestBase`.
Refactored `UpdateAsync_with_unknown_id` test to support idempotent behavior, passing on successful updates or verifying exceptions.
Included `System.Linq` and `System.Threading.Tasks` namespaces to support new functionality.
Introduced the `TryResolveProfileIdAsync` method in the `RecApplicationTestBase` class to resolve a usable profile ID for tests. The method prioritizes a configured `FakeProfileId` and falls back to querying the database for the first available profile. Added necessary namespaces (`System.Linq`, `System.Threading.Tasks`, and `MediatR`) to support LINQ, async operations, and the `ISender` interface. Implemented dependency injection for querying profiles and added error handling to ensure robustness.
Updated `ResultProcedureTests` to use `UpdateResultDto` for better structure and clarity in the `UpdateResultProcedure_runs_via_mediator` test. Adjusted the `StatusId` value to `0` for consistency.
Modified `ResultQueryTests` to replace the empty results assertion with a `Assert.Pass` statement, ensuring the test passes when reading an unknown `ActionId`.
Added handling for BadRequestException in RecActionProcedureTests
to ensure data-related errors are gracefully handled. Updated
UpdateActionProcedure_runs_via_mediator to use UpdateActionDto
for better type safety. Refactored ReadRecActionViewQuery_returns_actions_for_profile
to dynamically resolve profile IDs, improving test reliability
and providing clearer feedback when test data is missing.
Refactored `ProfileProcedureTests` to use `UpdateProfileDto` for the `Data` property in `UpdateProfileCommand`, improving code clarity.
Updated `ProfileQueryTests` to replace `FakeProfileId` retrieval with `TryResolveProfileIdAsync` and added a conditional check to ignore the test if no valid profile ID is available, enhancing test robustness and flexibility.
Refactored the `ExecuteUpdateProcedure_runs_with_changedWho`
test method to use the `UpdateProfileDto` class for the `Data`
property of the `UpdateProfileCommand`, improving encapsulation
and structure. Added the necessary `using` directive for
`ReC.Application.Common.Procedures.UpdateProcedure.Dto` to
support this change.
Updated EndpointProcedureTests to use UpdateEndpointDto for the
Data property in UpdateEndpointCommand. Added a new using
directive for ReC.Application.Common.Procedures.UpdateProcedure.Dto
to include the required class.
Refactored the `UpdateEndpointParamsCommand` to use the newly
introduced `UpdateEndpointParamsDto` class for encapsulating
the `Data` property. Added a `using` directive for the
`ReC.Application.Common.Procedures.UpdateProcedure.Dto`
namespace to support this change.
Updated the `UpdateEndpointAuthProcedure_runs_via_mediator` test to use the `UpdateEndpointAuthDto` class for the `Data` property of the `UpdateEndpointAuthCommand`, improving clarity and aligning with the use of a dedicated DTO.
Added the necessary `using` directive for `ReC.Application.Common.Procedures.UpdateProcedure.Dto` to ensure the `UpdateEndpointAuthDto` class is accessible in the test file.
Introduced `StaticReCClientTests` to validate the behavior of
the `ReCClient` static client, ensuring deterministic and
non-parallel execution due to process-wide state mutation.
Added tests to cover various scenarios:
- Null configuration callback throws `ArgumentNullException`.
- Missing `BaseAddress` or `ConfigureClient` throws.
- Conflicting `BaseAddress` and `ConfigureClient` throws.
- Successful static client build and resolution via `Create`.
- Subsequent `BuildStaticClient` calls throw exceptions.
Included helper types for `ConfigureServices` validation and
used `#pragma` directives to suppress warnings for obsolete
members. Ensured test order with `[Order]` attributes.
Added a new `DependencyInjectionTests` class to validate the
dependency injection setup for the `ReCClient` class.
- Added tests to ensure `ReCClient` can be resolved when registered
with a base URL or custom HTTP client configuration.
- Verified default options are registered when no callback is
supplied and that options callbacks are applied correctly.
- Added tests to validate behavior when `LogSuccessfulRequests`
is enabled, including scenarios with and without a registered
logger.
- Included necessary `using` directives for DI, logging, options,
HTTP client, and the `ReC.Client` namespace.
Moved static provider logic to a new partial class `ReCClient.Static.cs` to support legacy scenarios (e.g., .NET Framework) without requiring an external `IServiceProvider`.
Introduced new static methods for building and resolving a static `IServiceProvider`:
- `BuildStaticClient(Action<StaticBuildConfiguration>)`
- Overloads for simpler configuration with `apiUri` or `HttpClient`.
Marked static methods as `[Obsolete]` to discourage use in modern DI-based applications.
Refactored `ReCClient` to focus solely on instance-level functionality, improving code organization and maintainability. Added documentation to clarify the intended use of static methods.
Updated `ReCClientOptions` to include a warning about the `LogSuccessfulRequests` option throwing an `InvalidOperationException` if no `ILogger` is registered via DI. Added validation and thread-safety to `BuildStaticClient` using `Lazy<IServiceProvider>`.
Introduced `StaticBuildConfiguration` for callback-based configuration and detailed its properties. Clarified usage patterns, added VB.NET and C# examples, and documented validation rules.
Marked older `BuildStaticClient` overloads as `[Obsolete]` while retaining functionality. Expanded context on static client use cases and synchronous wrappers. Improved documentation clarity and consistency.
Introduced a new `BuildStaticClient(Action<StaticBuildConfiguration>)` method for flexible and detailed static `IServiceProvider` configuration. Added the `StaticBuildConfiguration` class to encapsulate optional settings like `BaseAddress`, `ConfigureClient`, `Logger`, and more.
Refactored existing `BuildStaticClient` overloads to use the new method, ensuring consistency and reducing duplication. Added support for optional `ILogger` instances and improved validation to enforce proper configuration.
Marked existing `BuildStaticClient` methods as obsolete, recommending the new method. Enhanced thread-safety using `Interlocked.CompareExchange`. Updated XML documentation and added conditional compilation for `NETFRAMEWORK` compatibility.
These changes improve maintainability, usability, and alignment with modern .NET practices.
Refactor static IServiceProvider initialization to use a thread-safe Lazy<IServiceProvider>, ensuring lazy creation and improved efficiency. Replace `Services` and `Provider` fields with `_staticConfigure` delegate for dynamic service collection configuration.
Update `BuildStaticClient` methods to use `Interlocked.CompareExchange` for safe initialization of `_staticConfigure`. Modify `Create` method to retrieve the provider via `LazyProvider`.
Mark `BuildStaticClient` and `Create` methods as obsolete, encouraging the use of local service collections. Adjust exception messages and documentation to reflect these changes.
Added a validation in the `ReCClient` constructor to ensure that
an `ILogger` instance is provided when the `LogSuccessfulRequests`
option in `ReCClientOptions` is enabled. Throws an
`InvalidOperationException` with a detailed message if no logger
is injected. The message includes guidance on resolving the issue
by either registering a logging provider or disabling the option.
Expand documentation on `[Obsolete]` static APIs and sync wrappers,
emphasizing their maintained status and appropriate use cases.
- Added detailed examples for `BuildStaticClient` and `Create`
in VB.NET and C#, including configuration options.
- Updated `TaskSyncExtensions.Sync` section with warnings about
potential deadlocks and recommendations for `async/await`.
- Introduced "6.3 Mid-Term Recommendation" to guide migration
to DI and async patterns.
- Highlighted scenarios where static APIs and sync wrappers
remain appropriate, such as legacy .NET Framework projects
or quick-start use cases.
- Clarified that `[Obsolete]` is a reminder, not a breaking change.
The solution file (ReC.sln) was updated to include the new
documentation file `docs\ReC.Client.xwiki` under the "Solution
Items" section. This change ensures the file is part of the
solution for better organization and accessibility.
Updated `RecActions.InvokeAsync(...).Sync()` to align with migration guidelines, marking `Sync()` as `[Obsolete]` and recommending `async/await` for asynchronous patterns.
Enhanced `BuildStaticClient` methods to include an optional `configureOptions` parameter for flexible `ReCClientOptions` configuration. Added conditional compilation for nullable reference type compatibility across .NET Framework and modern .NET versions.
Updated `Services.AddRecClient` calls to support `configureOptions`. Retained `[Obsolete]` on static helpers to encourage dependency injection (`services.AddRecClient(...)`) for new code.
Revised migration notes to emphasize deprecation of synchronous methods, static helpers, and the importance of adopting modern async and DI patterns. Clarified changes to `GetAsync` methods, error handling with `ReCApiException`, and deserialization behavior.
Comprehensively updated the documentation for the ReC.Client
library to improve usability and align with modern .NET
development practices. Key changes include:
- Added an introduction to the library, its purpose, and
supported frameworks (.NET 8 and .NET Framework 4.6.2).
- Documented core features like DI support, typed APIs,
consistent error handling, and flexible GET methods.
- Provided installation and setup instructions with examples
in VB.NET and C#.
- Explained usage patterns for GET endpoints (typed and
dynamic), CRUD operations, and invoking RecActions.
- Highlighted error handling via ReCApiException with examples.
- Added a section on testing with in-process API testing
recommendations.
- Marked static APIs and synchronous helpers as [Obsolete],
explaining limitations and providing migration tips.
- Provided migration guidance for recent API changes, such as
`GetAsync<T>` returning deserialized values and unified
error handling.
- Addressed FAQs about new patterns and deprecated methods.
These updates aim to modernize the library, promote best
practices, and simplify adoption for developers.
Renamed `GetDynamicAsync` to `GetAsync` across `ProfileApi.cs`,
`RecActionApi.cs`, and `ResultApi.cs` to improve consistency
and align with naming conventions for asynchronous methods.
Updated XML documentation to clarify that the non-generic
`GetAsync` overload returns a dynamically deserialized payload,
typically a `System.Text.Json.JsonElement`. Highlighted its
relation to the generic `GetAsync<T>` method.
Adjusted method signatures for both `NETFRAMEWORK` and
non-`NETFRAMEWORK` code paths. Updated test files
(`ProfileApiTests.cs`, `RecActionApiTests.cs`, and
`ResultApiTests.cs`) to reflect the renaming, including
test method names and assertions.
These changes enhance code readability, maintainability,
and consistency.
The `TaskSyncExtensions` class and its methods (`Sync` and
`Sync<TResult>`) have been marked as `[System.Obsolete]`. These
methods are no longer recommended due to the risk of deadlocks
and unexpected behavior caused by synchronous blocking.
Developers are advised to use `async/await` patterns instead.
The warning messages indicate that these methods will be
removed in a future release.
Updated all test methods to use asynchronous programming with
`async` and `await`, replacing synchronous calls with
`.GetAwaiter().GetResult()`. This improves readability and
aligns with modern C# practices.
Renamed test methods to reflect their asynchronous nature and
better describe their behavior. Updated exception handling to
validate HTTP methods and request URIs while maintaining
original assertions.
Applied changes consistently across multiple test classes,
including `CommonApiTests`, `EndpointAuthApiTests`,
`EndpointParamsApiTests`, `EndpointsApiTests`,
`ProfileApiTests`, `RecActionApiTests`, and `ResultApiTests`.
Added a new test class `EndpointsApiTests` to validate the `Endpoints` API functionality in the `ReC.Client`.
Tests include:
- Dependency injection resolution for the `Endpoints` API.
- Behavior of `CreateAsync` with minimal payload.
- Behavior of `UpdateAsync` with an unknown ID.
- Validation of `DeleteAsync` sending payload as query string.
Introduced necessary `using` directives and utilized the `CreateScopedClient` helper method for resource management.
Added `EndpointParamsApiTests` to validate the `EndpointParams`
API functionality. Introduced tests for dependency injection
resolution, `CreateAsync`, `UpdateAsync`, and `DeleteAsync`
methods to ensure proper behavior, including exception handling
and HTTP method verification. Utilized scoped clients for
resource management and introduced payload DTOs for API
operations.
Added the `EndpointAuthApiTests` class to test the `EndpointAuth` API.
Tests include:
- Dependency injection resolution (`ReCClient_endpoint_auth_api_is_resolvable_through_dependency_injection`).
- `CreateAsync` behavior with minimal payload.
- `UpdateAsync` behavior with an unknown ID.
- `DeleteAsync` behavior, ensuring payload is sent as a query string.
Introduced necessary `using` directives and utilized the `CreateScopedClient` helper method for scoped client creation. Added exception handling to validate API method behavior and ensure proper assertions on exceptions.
Introduced the `CommonApiTests` class to validate the behavior of the `ReCClient`'s `Common` API.
- Added `using` directives for namespaces related to procedures and commands to support the new tests.
- Verified dependency injection resolution for `ReCClient` and its `Common` API.
- Added tests for `CreateAsync`, `UpdateAsync`, and `DeleteAsync` methods to ensure proper handling of payloads and expected behavior:
- `CreateAsync_with_invalid_action_payload_throws_or_completes`: Tests invalid payload handling for `CreateAsync`.
- `UpdateAsync_with_body_payload_throws_or_completes`: Tests payload handling for `UpdateAsync`.
- `DeleteAsync_sends_payload_as_query_string`: Verifies query string construction for `DeleteAsync`.
Introduced a new `ProfileApiTests` class to test the `Profiles` API in the `ReC.Client`. Added test methods to verify API behavior, including dependency injection resolution, handling of unknown IDs, dynamic payload retrieval, update operations, and query string validation for delete operations.
Key changes:
- Added `ReCClient_profiles_api_is_resolvable_through_dependency_injection` test.
- Added `GetAsync_with_unknown_id_throws_not_found` test.
- Added `GetDynamicAsync_with_unknown_id_throws_not_found` test.
- Added `GetDynamicAsync_without_filters_returns_dynamic_payload_or_throws_not_found` test.
- Added `UpdateAsync_with_unknown_id_throws_or_completes` test.
- Added `DeleteAsync_sends_payload_as_query_string` test.
Included necessary `using` directives, scoped client creation, and exception handling to ensure robust test coverage for the `Profiles` API.
Introduced the `ResultApiTests` class to validate the behavior of the `Results` API client. Added test cases to ensure proper dependency injection, handle various API operations (`GetAsync`, `GetDynamicAsync`, `CreateAsync`, `UpdateAsync`, `DeleteAsync`), and verify expected outcomes such as exceptions, payload handling, and dynamic responses. Included necessary `using` directives to support the new tests.
Added a `using` directive for `System.Text.Json` to support JSON
operations. Introduced two new test methods:
`GetDynamicAsync_without_filters_returns_dynamic_payload_or_throws_not_found`
to validate the behavior of `GetDynamicAsync` without filters, and
`GetDynamicAsync_with_unknown_profile_throws_not_found` to ensure
proper handling of unknown profile IDs.
Added `GetDynamicAsync` methods to `ProfileApi`, `RecActionApi`,
and `ResultApi` to enable dynamic payload deserialization.
These methods support optional parameters for filtering and
are conditionally compiled for `NETFRAMEWORK` and other
frameworks, with nullable reference type support where
applicable. Internally, they reuse the existing `GetAsync<object>`
method for data retrieval.
Introduced a new test class `RecActionApiTests` to validate the behavior of the `RecActions` API client.
- Added tests for `GetAsync`, `CreateAsync`, `UpdateAsync`, `DeleteAsync`, and `InvokeAsync` methods to ensure proper handling of valid and invalid inputs.
- Verified dependency injection resolution for `RecClient` and `RecActions`.
- Included assertions for HTTP status codes, request methods, and query parameters.
- Handled edge cases such as missing test data with `Assert.Pass` or `Assert.Ignore`.
- Utilized scoped clients for test isolation and resource management.
These changes improve test coverage and ensure the reliability of the `RecActions` API client.
Introduce `RecClientTestBase` to streamline integration tests for `ReCClient`.
This abstract class uses `WebApplicationFactory` to create a test server
for `ReC.API` and configures a `ServiceProvider` with necessary services.
It includes helper methods for creating scoped `ReCClient` instances and
ensures proper resource cleanup via `IDisposable`.
Update `ReC.Tests.csproj` to include:
- `Microsoft.AspNetCore.Mvc.Testing` package for integration testing.
- Project references to `ReC.API` and `ReC.Client` for testing purposes.
These changes establish a reusable and maintainable testing infrastructure.
Updated the `try-catch` block in `Program.cs` to rethrow exceptions after logging them, ensuring proper error propagation. Added a `public partial class Program` declaration to enable splitting the `Program` class across multiple files. Adjusted closing braces to align with the new structure.
Updated GetAsync methods in ProfileApi, RecActionApi, and
ResultApi to return deserialized objects of type <T> instead
of raw HttpResponseMessage, improving usability.
Added conditional compilation (#if NETFRAMEWORK) to handle
nullable return types (T?) for non-NET Framework targets,
ensuring compatibility across .NET versions.
Replaced direct Http.GetAsync calls with using blocks for
proper disposal of HTTP responses. Introduced response
handling and deserialization via ReCClientHelpers to
streamline processing and logging.
Updated XML documentation to reflect the new behavior and
removed redundant parameters.
Enhanced `HandleResponseAsync` to return response body as a string and log successful responses. Introduced `JsonOptions` for consistent JSON serialization/deserialization. Added a generic `Deserialize<T>` method for deserializing JSON responses. Updated method signatures to support nullable reference types.
Updated `DeleteAsync` in `BaseCrudApi.cs` to serialize payloads into query strings to align with API expectations.
Added `UpdateAsync` to `CommonApi.cs` for payload-based updates, overriding inherited CRUD helpers to match the API's behavior.
Enhanced `GetAsync` in `ProfileApi.cs` to support optional profile filtering and default `includeActions` to `true`.
Refactored `InvokeAsync` in `RecActionApi.cs` to use `long` for `profileId`, support nullable `references`, and handle batches of RecActions.
Extended `GetAsync` in `ResultApi.cs` with new optional filters (`batchId`, `includeAction`, `includeProfile`, `lastBatch`) and updated query-building logic.
Enhanced ReCClientHelpers.cs with a new utility method:
- Added `BuildQueryFromObject<T>` to serialize objects into query strings.
- Skips `null` properties and escapes names/values for safety.
- Added `System.Collections` and `System.Reflection` namespaces to support reflection and collection operations.
This improves HTTP request handling by enabling dynamic query string generation from object payloads.