Compare commits

..

107 Commits

Author SHA1 Message Date
e96773f3c4 Remove DbModelConfigurationException and related logic
Removed the DbModelConfigurationException class and all its usages from DbModelOptions and EntityOptions. Indexers in these classes no longer throw this exception when configuration is missing. Updated the project file to include the Common\Options\DbModel\ folder.
2026-03-26 10:34:24 +01:00
06e92b588f Remove DbModel configuration and related JSON file
Removed all references to DbModel configuration from Program.cs and RecApplicationTestBase.cs. Deleted appsettings.DbModel.json, eliminating custom entity and column mapping definitions. The application no longer loads or uses DbModel configuration from JSON.
2026-03-26 10:34:05 +01:00
b922cbbb30 Remove ConfigureDbModel from dependency injection setup
Eliminated all references to ConfigureDbModel in DependencyInjection.cs, including related imports, configuration methods, and required service tracking. Dependency injection configuration is otherwise unchanged.
2026-03-26 10:32:24 +01:00
6c56375e3e Refactor RecDbContext to remove dynamic view mapping
Removed dependency on DbModelOptions and IOptions. Entity-to-view mappings are now hardcoded in OnModelCreating with fixed view names and schema. Property-to-column mappings now use EF Core conventions. Simplifies configuration and maintenance, but reduces flexibility for schema changes. Entity relationships remain explicitly configured.
2026-03-26 10:31:48 +01:00
fa9aa23f32 Add EF Core data annotations to view models
Added [Key], [Column], and [Table] attributes to ProfileView, RecActionView, and ResultView classes to explicitly map properties to database columns and views. Expanded model properties for clearer schema alignment and improved maintainability with Entity Framework Core.
2026-03-26 10:30:00 +01:00
b86d0c0f99 Add [Column] mapping attributes to query result classes
Added [Column] attributes to properties in BodyQueryResult, HeaderQueryResult, and InsertObjectResult to explicitly map them to their respective database columns. Also included necessary using directives for DataAnnotations.Schema to support these mappings. This enhances ORM compatibility and ensures correct property-to-column mapping.
2026-03-26 10:28:52 +01:00
b0d89ceba4 Remove properties from RecActionOptions class
Removed AddedWho and UseHttp1ForNtlm properties from RecActionOptions, leaving the class empty. This change cleans up unused configuration options.
2026-03-25 16:13:32 +01:00
11ebfdd21e Refactor DbModelOptions to use indexers for lookups
Replaced GetEntity and GetColumn extension methods with indexers
on DbModelOptions and EntityOptions. Updated all usages to use
the new indexer syntax, improving code clarity and error handling
for missing entity or column configurations.
2026-03-25 16:10:50 +01:00
1467acc4a1 Refactor DbModel options to use generic entity mapping
Replaces strongly-typed view options classes with a generic EntityOptions class and a dictionary-based configuration for entity-to-view and property-to-column mappings. Updates appsettings.DbModel.json to match the new structure. Refactors RecDbContext to use extension methods for mapping configuration. Removes obsolete options classes and simplifies exception handling for missing mappings. This change improves flexibility and maintainability of database view configuration.
2026-03-25 15:25:29 +01:00
e761fbd1ca Add DbModel config to Rec services setup
Added options.ConfigureDbModel to the AddRecServices configuration, enabling Rec services to use settings from the "DbModel" section of the app configuration for enhanced database model customization.
2026-03-25 13:30:12 +01:00
2e83d4a24a Make RecDbContext model mapping fully configurable
Refactored RecDbContext to use DbModelOptions injected via IOptions, replacing hardcoded view and column names with configuration-driven mappings. This enables dynamic control of entity-to-database mapping through appsettings.json, improving flexibility and maintainability.
2026-03-25 13:29:29 +01:00
37ba85d681 Add support for configuring DbModelOptions via DI
Introduce ConfigureDbModel methods to DependencyInjection for setting up DbModelOptions from code or configuration. Update required services tracking and add usage in Program.cs to enable structured DbModelOptions injection.
2026-03-25 13:26:54 +01:00
a46cd08122 Refactor DbModel options to use explicit, typed classes
Replaced the old generic, dictionary-based entity configuration system with a new, strongly-typed options structure under ReC.Application.Common.Options.DbModel. Introduced specific options classes for each major database view and result type, each with clear property mappings and defaults. Added a ViewOptions class for view/schema info. Removed all legacy entity mapping infrastructure, resulting in a more maintainable and type-safe configuration approach.
2026-03-25 12:53:10 +01:00
3d46901af5 Add DbModel view mappings to appsettings.DbModel.json
Added a new "DbModel" section to appsettings.DbModel.json, defining property-to-column mappings for RecActionView, ProfileView, ResultView, HeaderQueryResult, BodyQueryResult, and InsertObjectResult. This centralizes and standardizes database view and query result configurations.
2026-03-25 12:44:12 +01:00
90e8adbd36 Update behavior namespaces to InvokeAction for clarity
Renamed namespaces in PreprocessingBehavior and PostprocessingBehavior from .Action to .InvokeAction, and updated related using directives in DependencyInjection.cs. Added a folder entry for Common\Behaviors\Action\ in the project file for organization.
2026-03-25 11:43:30 +01:00
aef59def7f Add ResultType to InsertResultCommand in all handlers
Added the Type property (ResultType) to every InsertResultCommand sent in PostprocessingBehavior, PreprocessingBehavior, and InvokeRecActionViewCommand. This ensures each result now includes its context (Post, Pre, or Main), both in normal and exception flows.
2026-03-25 11:17:38 +01:00
d7783b6e81 Make InsertObjectProcedure properties nullable, require ResultType
Updated InsertObjectProcedure to make related command properties nullable and removed default initializations. Updated handler to use null-conditional access for these properties. Changed InsertResultCommand.Type to required and updated tests accordingly. Improves null safety and clarifies required fields.
2026-03-25 11:17:21 +01:00
4126f984e4 Expand and refactor OutResDto for richer data support
Refactored OutResDto to include additional properties such as Action, Profile, Status, and Type, and made several fields nullable. This enhances flexibility and allows for more comprehensive and optional data representation in API responses.
2026-03-25 11:06:07 +01:00
0e2328c287 Add support for Result.Info, Error, and Type in insert proc
Extended InsertObjectProcedureHandler to include Result.Info, Result.Error, and Result.Type in both the SQL parameter list and the command string. This ensures these fields are correctly passed to and handled by the stored procedure.
2026-03-25 11:02:56 +01:00
e04e054151 Add optional ResultType to InsertResultCommand
Added a nullable Type property of ResultType to InsertResultCommand for enhanced result categorization. Also included the required using directive for ReC.Domain.Constants.
2026-03-25 11:02:35 +01:00
6082a637fe Add mapping for result type fields in RecDbContext
Added entity property mappings for RESULT_TYPE_ID (Type) and RESULT_TYPE (TypeName) columns in RecDbContext to support storing and retrieving result type information.
2026-03-25 11:00:12 +01:00
93669a6358 Add Type and TypeName to ResultView model
Imported ResultType and added Type (ResultType?) and TypeName (string?) properties to ResultView to support representing result types alongside status information.
2026-03-25 10:59:33 +01:00
fecd9219b4 Add ResultType enum to ReC.Domain.Constants
Introduced a new ResultType enum with values Pre, Main, and Post to represent different result stages. Pre is explicitly set to 1.
2026-03-25 10:58:45 +01:00
bd07b4482c Remove CS0618 warning suppression for ExceptionHandlingMiddleware
Removed #pragma directives that suppressed CS0618 (obsolete API usage) warnings around app.UseMiddleware<ExceptionHandlingMiddleware>(). Obsolete warnings for this middleware will now be shown during compilation.
2026-03-25 10:28:49 +01:00
520aec427b Remove obsolete attribute and add exception using directive
Removed [Obsolete] from ExceptionHandlingMiddleware, indicating it is no longer deprecated. Added using directive for ReC.Application.Common.Exceptions to support updated exception handling.
2026-03-25 10:27:41 +01:00
26b7a82451 Handle RecActionException in middleware with 422 response
Added specific handling for RecActionException in the exception middleware. Now logs a warning with ActionId and ProfileId, returns a 422 Unprocessable Entity status, and provides detailed error information in the response.
2026-03-25 10:26:24 +01:00
08c0d29d84 Improve error handling and logging in batch rec actions
Add ILogger support to InvokeRecActionViewsCommandHandler for enhanced error and warning logging. Log and continue on handled exceptions when appropriate, and rethrow for critical errors. Clean up and reorder using directives. This increases robustness and traceability during batch rec action processing.
2026-03-25 10:25:52 +01:00
405b5f3ab1 Add ActionId and ProfileId properties to RecActionException
Expose ActionId and ProfileId as public properties in the
RecActionException class, allowing external access to these
values from exception instances. Refactored the constructor
to use a block body.
2026-03-25 10:17:24 +01:00
32af65d30c Remove InvokeBatchRecActionViewsCommand extension method
Deleted the InvokeBatchRecActionViewsCommandExtensions class and its InvokeBatchRecActionView extension method for ISender. The command record and handler remain unchanged.
2026-03-25 10:07:15 +01:00
30ccf05c57 Use RecActionException for contextual error handling
Replaced generic exception with RecActionException in PostprocessingBehavior when ErrorAction is Stop, providing ActionId and ProfileId for better error context. Added necessary using statements for the new exception and related namespaces.
2026-03-25 09:58:02 +01:00
a14d5ff112 Improve error handling with RecActionException
Wrap exceptions in PreprocessingBehavior with RecActionException, including ActionId and ProfileId for better context and debugging. This enhances error reporting when ErrorAction is set to Stop.
2026-03-25 09:57:46 +01:00
fec125b0d5 Improve exception context in action error handling
Updated InvokeRecActionViewCommandHandler to throw a RecActionException with action Id and ProfileId when an error occurs and ErrorAction is set to Stop. This change enhances error traceability by providing more contextual information in exceptions.
2026-03-25 09:56:58 +01:00
82ae4c5957 Add RecActionException custom exception class
Introduced RecActionException in ReC.Application.Common.Exceptions to encapsulate errors related to rec actions, including actionId, optional profileId, and inner exception details in the error message.
2026-03-25 09:55:52 +01:00
894b7bb070 Improve error handling and resource cleanup in action handler
Refactored InvokeRecActionViewCommandHandler to enhance error handling by logging exceptions and conditionally rethrowing based on ErrorAction. Simplified NTLM HttpClient/handler management for proper disposal. Improved code structure and formatting for clarity.
2026-03-24 17:02:06 +01:00
a707cce6e4 Refactor error handling in Pre/Postprocessing behaviors
Refactored PreprocessingBehavior and PostprocessingBehavior to send InsertResultCommand with only relevant info or error fields. Now throws exceptions when ErrorAction is Stop, allowing upstream error handling and preventing unnecessary or misleading result data. Improves consistency and clarity in error processing.
2026-03-24 16:19:00 +01:00
2ca85a2372 Refactor action behaviors to use Unit instead of bool
Refactored PreprocessingBehavior and PostprocessingBehavior for InvokeRecActionViewCommand to use MediatR's Unit as the response type instead of bool. Updated method signatures, return values, and DI registration accordingly to align with MediatR conventions for commands without return values.
2026-03-24 16:01:24 +01:00
dbe09cd07b Refactor error handling in RecActionView invocation
Switch to exception-based error handling for invoking RecActionView actions, removing boolean return values and related checks. Update command and handler signatures to use void return type. Clean up unused using directives. This improves clarity and robustness of error management during batch processing.
2026-03-24 16:00:47 +01:00
690dcea7a8 Add PostprocessingBehavior to MediatR pipeline
Registered PostprocessingBehavior for InvokeRecActionViewCommand (with bool result) in the MediatR pipeline via DependencyInjection. This ensures both preprocessing and postprocessing behaviors are executed for this command.
2026-03-24 14:41:41 +01:00
fdae4d26be Add PostprocessingBehavior for action result logging
Introduced PostprocessingBehavior as an IPipelineBehavior for InvokeRecActionViewCommand. This behavior handles post-processing by executing optional queries, serializing results, and logging outcomes via InsertResultCommand. It also manages error handling based on the action's ErrorAction setting, ensuring consistent result tracking after command execution.
2026-03-24 14:40:52 +01:00
2883cf9be4 Add PreprocessingBehavior for InvokeRecActionViewCommand
Register PreprocessingBehavior in the MediatR pipeline specifically for InvokeRecActionViewCommand. Update using directives to reflect the shift from Procedures to Commands and from Common.Behaviors to Common.Behaviors.Action.
2026-03-24 14:15:01 +01:00
9410c5dc0d Refactor PreprocessingBehavior to log results and errors
Refactored PreprocessingBehavior to serialize and log the results and errors of preprocessing SQL queries using InsertResultCommand. Now records both successful and failed executions, while preserving the stop-on-error behavior. Cleaned up and updated using directives.
2026-03-24 14:01:45 +01:00
35e99d9f2a Change ExecuteDynamicSqlAsync to return object list
The ExecuteDynamicSqlAsync method now returns an IEnumerable of
dictionaries representing query result rows, instead of a JSON
string. This allows consumers to work directly with the data
in its native .NET object form.
2026-03-24 13:26:10 +01:00
5fd65e52a3 Pass CancellationToken to ExecuteDynamicSqlAsync
Updated PreprocessingBehavior to include the CancellationToken when calling ExecuteDynamicSqlAsync, enabling query execution to be cancelled if the operation is aborted.
2026-03-24 13:21:40 +01:00
2508a8b986 Add CancellationToken to ExecuteDynamicSqlAsync method
The ExecuteDynamicSqlAsync extension for IRecDbContext now accepts an optional CancellationToken, which is passed to all async database operations to support cancellation. Also added a TODO to move this method to Common.Infrastructure in the future.
2026-03-24 13:21:05 +01:00
daff1477be Refactor PUT endpoints to use id in route and DTO in body
Refactored update (PUT) endpoints in multiple controllers to accept the record id as a route parameter and the update data as a DTO in the request body. Updated method signatures, XML documentation, and imports to align with RESTful conventions and improve API clarity. Controller methods now construct command objects using the id and DTO before sending to MediatR.
2026-03-24 12:07:50 +01:00
dcfa47c68d Update DELETE endpoints to use [FromQuery] parameters
Refactored all relevant controller DELETE actions to accept command/procedure parameters from the query string ([FromQuery]) instead of the request body ([FromBody]). Updated XML documentation and method signatures to reflect this change, including renaming parameters from "procedure" to "command" where appropriate. Also removed the unused IConfiguration dependency from EndpointAuthController.
2026-03-24 11:57:53 +01:00
e691faf620 Rename Result*Procedure to Result*Command for consistency
Refactor all Result-related procedure records, handlers, and usages to use the *Command suffix instead of *Procedure. Update controller actions, handler interfaces, tests, and InsertObjectProcedure accordingly. No functional changes; improves naming consistency across the codebase.
2026-03-24 11:40:28 +01:00
cac33c46df Rename *ActionProcedure classes to *ActionCommand
Renamed InsertActionProcedure, UpdateActionProcedure, and DeleteActionProcedure to their respective *ActionCommand counterparts to align with CQRS conventions. Updated all controller actions, handlers, tests, and related usages accordingly. No changes to business logic or method signatures.
2026-03-24 11:39:55 +01:00
de503cac5b Rename Profile*Procedure types to Profile*Command for clarity
Renamed InsertProfileProcedure, UpdateProfileProcedure, and DeleteProfileProcedure (and their handlers) to use the "Command" suffix for consistency. Updated all usages in controllers, handlers, and tests. No logic changes; only type names were updated for improved clarity.
2026-03-24 11:39:04 +01:00
4999beda3b Refactor endpoint Procedures to Commands for CQRS alignment
Renamed Insert/Update/DeleteEndpointProcedure classes to their
respective Command counterparts to follow CQRS conventions.
Updated controller actions, handlers, InsertObjectProcedure,
and related unit tests to use the new Command types.
No functional changes were made; this is a naming refactor.
2026-03-24 11:38:22 +01:00
5df36d94e0 Rename EndpointParams procedures to commands for CQRS clarity
Renamed Insert/Update/DeleteEndpointParamsProcedure classes and
handlers to use the "Command" suffix (e.g., InsertEndpointParamsCommand)
for consistency with CQRS conventions. Updated all controller actions,
handlers, and tests to use the new command names. This improves
clarity and aligns naming with standard command patterns.
2026-03-24 11:37:30 +01:00
d3d24a0fb6 Refactor: Rename UpdateEndpointAuthProcedure to Command
Renamed UpdateEndpointAuthProcedure to UpdateEndpointAuthCommand across the codebase for improved naming consistency. Updated controller, handler, and tests to use the new command name, aligning with CQRS conventions for state-modifying operations.
2026-03-24 11:36:49 +01:00
a6b0cbaf9d Rename InsertEndpointAuthProcedure to InsertEndpointAuthCommand
Refactored all usages of InsertEndpointAuthProcedure to InsertEndpointAuthCommand, including method signatures, handler interfaces, and test cases, to better align with CQRS naming conventions for write operations.
2026-03-24 11:35:58 +01:00
0162d059da Refactor: Rename DeleteEndpointAuthProcedure to Command
Renamed DeleteEndpointAuthProcedure to DeleteEndpointAuthCommand across the codebase, including controller, handler, and tests, to improve naming consistency and align with CQRS conventions for write operations.
2026-03-24 11:31:33 +01:00
302fee4908 Refactor tests to send commands directly to mediator
Refactored test code to remove ToObjectProcedure usage and send command objects directly to the mediator. Updated update procedure tests to use Data and Id properties. Replaced custom Execute*Procedure methods with sender.Send. Cleaned up unused usings. These changes improve consistency and reflect updates to command structures.
2026-03-24 11:29:15 +01:00
3e10176d98 Add PreprocessingBehavior for action command pipeline
Introduced PreprocessingBehavior implementing MediatR's IPipelineBehavior for InvokeRecActionViewCommand. This behavior executes a preprocessing SQL query if specified, and halts processing if an error occurs and ErrorAction is set to Stop. Added necessary using directives for dependencies.
2026-03-24 11:14:11 +01:00
4f0f99e0f8 Refactor InsertResultProcedure execution method
Replaced sender.ExecuteInsertProcedure with sender.Send for executing InsertResultProcedure. Removed the _options.AddedWho parameter, passing only the procedure object and cancellation token. The construction of InsertResultProcedure remains unchanged.
2026-03-24 11:11:36 +01:00
8fb4b4005c Refactor UpdateObjectProcedure to use DTO properties
Replaced *Procedure properties in UpdateObjectProcedure with corresponding DTO types (e.g., UpdateActionDto, UpdateEndpointDto, etc.) and added the necessary DTO namespace import. This decouples the record from procedure logic, improving separation of concerns and data transfer handling.
2026-03-24 11:11:12 +01:00
b3bb7144ef Refactor IUpdateProcedure to generic with Id and Data props
Changed IUpdateProcedure to a generic interface IUpdateProcedure<T>, adding Id (long) and Data (T) properties for improved type safety and flexibility in update procedures. The interface continues to inherit from IRequest<int>.
2026-03-24 11:10:47 +01:00
eff6350d77 Refactor update procedures to use DTO-based pattern
Refactored Update*Procedure records to encapsulate update data in dedicated DTOs (e.g., UpdateActionDto, UpdateEndpointDto) via a generic Data property. Updated interfaces to be generic and modified handlers to pass only the DTO to UpdateObjectProcedure. This improves maintainability, reduces duplication, and standardizes update logic across entities.
2026-03-24 11:09:46 +01:00
114b5de71d Add Update DTOs for partial entity updates in Procedures
Introduced six new DTO record classes under ReC.Application.Common.Procedures.UpdateProcedure.Dto to support partial (nullable) updates for Action, Endpoint, EndpointAuth, EndpointParams, Profile, and Result entities. These DTOs enable PATCH-like update operations by allowing selective property updates. No existing code was modified.
2026-03-24 11:08:37 +01:00
f786192786 Refactor ResultController to use mediator.Send for commands
Standardize command handling by replacing custom mediator methods
with mediator.Send in ResultController. Update PUT endpoint to
remove id route parameter and rely on payload for identification.
2026-03-24 11:07:42 +01:00
50741bfdd3 Refactor RecActionController to use MediatR Send only
Simplified controller by removing IConfiguration dependency and unused usings. Refactored all endpoints to use MediatR's Send method with command objects, eliminating custom mediator extension methods and route parameters like id. This streamlines command handling and reduces dependencies.
2026-03-24 11:06:20 +01:00
561eafe48c Refactor ProfileController to use MediatR Send method
Replaces custom Execute*Procedure methods with MediatR's Send for insert, update, and delete operations. Removes obsolete using directives. Updates the PUT endpoint to accept the profile ID in the request body instead of the route.
2026-03-24 11:04:41 +01:00
84358ced96 Refactor EndpointsController to use standard MediatR pattern
Removed IConfiguration dependency and replaced custom mediator
extension methods with standard mediator.Send calls for endpoint
commands. Simplified method signatures and removed unused usings.
Updated PUT endpoint to accept UpdateEndpointProcedure directly.
2026-03-24 11:03:28 +01:00
d2e97a2fef Refactor EndpointParamsController to use MediatR.Send
Removed IConfiguration dependency and custom MediatR extension methods from EndpointParamsController. All command handling now uses mediator.Send directly, and route/config parameters have been eliminated from endpoints. Cleaned up unused usings and streamlined controller logic.
2026-03-24 11:02:58 +01:00
d505c8415e Refactor EndpointAuthController to use MediatR Send
Replaced custom procedure execution methods with MediatR's Send method in EndpointAuthController. Removed obsolete using directives and updated the PUT endpoint to no longer require an id route parameter, expecting the id in the payload instead. This streamlines the controller and aligns it with standard MediatR practices.
2026-03-24 10:58:43 +01:00
a590ffd2dc Refactor InsertProfileProcedure to use MediatR handler
Refactored InsertProfileProcedure by removing the ToObjectProcedure method and introducing InsertProfileProcedureHandler, which implements IRequestHandler and delegates insert logic via MediatR's ISender. Updated using directives to include MediatR. This aligns profile insertion with the MediatR request/response pattern.
2026-03-24 10:14:58 +01:00
94da75ce37 Add MediatR handler for DeleteProfileProcedure command
Introduce DeleteProfileProcedureHandler using MediatR's IRequestHandler to process DeleteProfileProcedure requests. The handler sends a DeleteObjectProcedure via ISender, replacing the previous ToObjectProcedure method. Also, add necessary using directives and refactor logic to centralize command handling.
2026-03-24 10:14:10 +01:00
9c1ffd7df8 Refactor UpdateEndpointProcedure and add handler
Refactored UpdateEndpointProcedure to implement IUpdateProcedure directly and removed the ToObjectProcedure method. Introduced UpdateEndpointProcedureHandler using MediatR's ISender for command handling, aligning with MediatR patterns and enabling dependency injection.
2026-03-24 10:13:35 +01:00
e31d034266 Refactor InsertEndpointProcedure; add MediatR handler
Refactored InsertEndpointProcedure to remove the ToObjectProcedure method, making it a simple data record. Introduced InsertEndpointProcedureHandler using MediatR's IRequestHandler to handle insert commands asynchronously. Added necessary MediatR using directives.
2026-03-24 10:13:12 +01:00
649d7eff8c Refactor DeleteEndpointProcedure to use MediatR handler
Replaces the ToObjectProcedure method with a dedicated
DeleteEndpointProcedureHandler implementing IRequestHandler.
The handler uses MediatR's ISender to send DeleteObjectProcedure,
improving separation of concerns and aligning with MediatR
request/response patterns.
2026-03-24 10:12:35 +01:00
401d67de4c Refactor UpdateEndpointParamsProcedure to MediatR pattern
Refactored UpdateEndpointParamsProcedure to include all relevant properties and removed the ToObjectProcedure method. Introduced UpdateEndpointParamsProcedureHandler using MediatR's IRequestHandler, delegating update logic via ISender. This improves code structure and maintainability.
2026-03-24 10:11:55 +01:00
ed94415a33 Refactor InsertEndpointParamsProcedure with MediatR handler
Remove ToObjectProcedure method from InsertEndpointParamsProcedure and introduce InsertEndpointParamsProcedureHandler using MediatR's IRequestHandler. This decouples conversion and command logic, aligning with MediatR patterns and improving separation of concerns.
2026-03-24 10:10:14 +01:00
04513a3d08 Refactor endpoint params delete to use MediatR handler
Replaces ToObjectProcedure with DeleteEndpointParamsProcedureHandler using MediatR's request/handler pattern. Improves separation of concerns by delegating deletion logic to the handler and updates imports and namespace accordingly.
2026-03-24 10:09:37 +01:00
d390c3f7b6 Remove DeleteObjectProcedureExtensions and its methods
Deleted the DeleteObjectProcedureExtensions static class and its ExecuteDeleteProcedure extension methods from DeleteObjectProcedure.cs. These methods previously provided convenience for executing delete procedures via ISender. The core DeleteObjectProcedure record and its handler remain unchanged.
2026-03-24 10:08:45 +01:00
a40f20f6d9 Refactor UpdateEndpointAuthProcedure and add handler
Expanded UpdateEndpointAuthProcedure with new properties and removed the ToObjectProcedure method. Introduced UpdateEndpointAuthProcedureHandler using MediatR's ISender for command handling, improving separation of concerns and enabling dependency injection.
2026-03-24 09:59:21 +01:00
ee1f6a8753 Refactor InsertEndpointAuthProcedure handling
Move insert logic from InsertEndpointAuthProcedure to a new InsertEndpointAuthProcedureHandler using MediatR. Remove ToObjectProcedure method and update usings. The record now serves as a pure data structure.
2026-03-24 09:51:59 +01:00
1e35b6e263 Refactor DeleteEndpointAuthProcedure to use MediatR handler
Refactored DeleteEndpointAuthProcedure by removing the ToObjectProcedure method and introducing DeleteEndpointAuthProcedureHandler, which implements IRequestHandler and delegates deletion via MediatR's ISender. Consolidated using directives and namespace declarations.
2026-03-24 09:51:21 +01:00
e152e9a37a Refactor ChangedWho handling in UpdateObjectProcedure
ChangedWho is now initialized directly and no longer settable via a public method. Removed the ChangedBy method and related extension methods. Added a TODO to move ChangedWho assignment to authentication middleware in the future.
2026-03-24 09:48:37 +01:00
554aaa8b6c Refactor InsertObjectProcedure AddedWho handling
Removed AddedBy method and related extension; AddedWho is now set to a default value internally. Added a TODO to move AddedWho assignment to authentication middleware in the future.
2026-03-24 09:47:24 +01:00
329d156d08 Update IUpdateProcedure to use MediatR IRequest<int>
Refactored IUpdateProcedure to inherit from MediatR's IRequest<int> for integration with the MediatR pipeline. Removed the ToObjectProcedure method and added the necessary using directive for MediatR. This simplifies the interface and standardizes request handling.
2026-03-24 09:44:41 +01:00
246362812a Refactor IInsertProcedure for MediatR compatibility
IInsertProcedure now inherits from IRequest<long> to integrate with MediatR's request/response pattern. Removed the ToObjectProcedure method and added the necessary MediatR using directive.
2026-03-24 09:43:57 +01:00
71430918ac Refactor IDeleteProcedure to use MediatR IRequest<int>
IDeleteProcedure now inherits from MediatR's IRequest<int>, aligning it with MediatR request/response patterns. Removed the ToObjectProcedure method from the interface. Added the MediatR using directive. Note: The namespace and using directive are now on the same line, which may need formatting correction.
2026-03-24 09:43:36 +01:00
7a1705365b Add dynamic SQL execution to IRecDbContext interface
Added Database property to IRecDbContext for database operations. Introduced ExecuteDynamicSqlAsync extension method to run arbitrary SQL and return results as JSON. This enables flexible querying and result serialization.
2026-03-24 09:42:59 +01:00
acf136e689 Refactor UpdateProfileProcedure and add MediatR handler
Refactored UpdateProfileProcedure to implement IUpdateProcedure and expanded its properties. Removed ToObjectProcedure method. Introduced UpdateProfileProcedureHandler using MediatR's ISender for command dispatch. Modernized structure to use record types and handler classes.
2026-03-24 09:41:17 +01:00
6b4897702a Refactor DeleteActionProcedure to use MediatR handler
Refactored DeleteActionProcedure to implement IDeleteProcedure directly and removed the ToObjectProcedure method. Introduced DeleteActionProcedureHandler using MediatR's IRequestHandler to delegate deletion logic via ISender. Updated using directives for MediatR integration.
2026-03-19 23:19:07 +01:00
7d4e082958 Refactor InsertActionProcedure to use MediatR handler
Replaces the ToObjectProcedure method with an InsertActionProcedureHandler that implements IRequestHandler using MediatR. The handler maps InsertActionProcedure to InsertObjectProcedure and sends it via ISender. Also updates using statements to include MediatR.
2026-03-19 23:18:57 +01:00
d1dd021952 Refactor UpdateActionProcedure and add handler class
Expanded UpdateActionProcedure with new properties and removed the ToObjectProcedure method. Introduced UpdateActionProcedureHandler using MediatR to handle update logic and delegate to UpdateObjectProcedure. Centralized update logic in the handler for better maintainability.
2026-03-19 23:18:47 +01:00
5afc1791b0 Refactor DeleteResultProcedure to use MediatR handler
Remove ToObjectProcedure method and add DeleteResultProcedureHandler implementing IRequestHandler. The handler sends DeleteObjectProcedure via MediatR, mapping relevant properties. Also update using directives and namespace.
2026-03-19 23:18:38 +01:00
2ec07d7e96 Refactor InsertResultProcedure to use MediatR handler
Refactored InsertResultProcedure by removing its ToObjectProcedure method and introducing InsertResultProcedureHandler, which implements IRequestHandler and delegates object insertion via MediatR's ISender. This shifts conversion logic from the record to the handler and improves separation of concerns.
2026-03-19 23:18:29 +01:00
cbe4f1ba3c Refactor UpdateResultProcedure to use MediatR handler
Refactored UpdateResultProcedure to implement IUpdateProcedure directly and removed the ToObjectProcedure method. Introduced UpdateResultProcedureHandler using MediatR's IRequestHandler pattern, delegating update logic via ISender. This improves code structure and maintainability.
2026-03-19 23:18:17 +01:00
16155da033 Add Info and Error properties to OutResDto
Added two new nullable string properties, Info and Error, to the OutResDto record to support additional informational and error messages in responses.
2026-03-19 18:51:33 +01:00
0aa1414ea6 Add @pRESULT_INFO and @pRESULT_ERROR SQL parameters
Added two new SQL parameters, @pRESULT_INFO and @pRESULT_ERROR, to InsertObjectProcedure.cs. These are set from request.Result.Info and request.Result.Error, or to DBNull.Value if null, to support additional result data in the procedure.
2026-03-19 18:50:47 +01:00
181a9a83fd Add Info and Error properties to InsertResultProcedure
Added nullable string properties Info and Error to the InsertResultProcedure record to allow storing additional information and error messages related to insert operations.
2026-03-19 18:50:34 +01:00
5e3e12bad8 Add Info and Error properties to entity mapping
Added Info and Error properties to the entity configuration, mapping them to the RESULT_INFO and RESULT_ERROR columns in the database using HasColumnName. This allows the entity to store and retrieve additional result information and error details.
2026-03-19 18:49:28 +01:00
6dcc128ad5 Add Info, Error, AddedWho, and ChangedWho to ResultView
Extended ResultView with four new nullable string properties:
Info and Error for additional details and error messages,
and AddedWho and ChangedWho for tracking user metadata.
2026-03-19 18:49:08 +01:00
754ef88644 Bump version to 2.0.2-beta in ReC.API.csproj
Updated project, assembly, and file versions from 2.0.1-beta/2.0.1.0 to 2.0.2-beta/2.0.2.0 to reflect new release. No other changes were made.
2026-03-16 13:46:10 +01:00
95ece6fdcf Remove unused imports from ResultController.cs
Removed unnecessary using statements for ReC.API.Extensions and ReC.API.Models to clean up the code and improve maintainability. No functional changes were made.
2026-03-16 13:44:38 +01:00
87194df697 Refactor and expand REST action authentication support
Refactored authentication logic for REST actions to use a structured switch block, adding explicit support for ApiKey, BearerToken, JwtBearer, OAuth2, BasicAuth, and NTLM authentication types. Introduced dedicated HttpClient/Handler for NTLM with proper disposal. Improved extensibility, clarity, and resource management. Added IOptions and Options usage for configuration.
2026-03-16 13:43:27 +01:00
b38d53248c Force HTTP/1.1 for NTLM when UseHttp1ForNtlm is enabled
Added logic to set HTTP/1.1 and exact version policy for NTLM
authentication requests when the UseHttp1ForNtlm option is true.
This ensures compatibility with NTLM endpoints requiring HTTP/1.1.
2026-03-16 13:41:04 +01:00
56b604bd35 Add UseHttp1ForNtlm option to RecAction config
Added the boolean UseHttp1ForNtlm property to the RecAction section in appsettings.json and RecActionOptions class. This option defaults to false and allows control over using HTTP/1 for NTLM authentication.
2026-03-16 13:38:45 +01:00
f67579dba9 Move AddedWho config to RecActionOptions and refactor usage
Centralize AddedWho under RecAction in appsettings.json and add it to RecActionOptions. Update InvokeRecActionViewCommandHandler to use IOptions<RecActionOptions> for strongly-typed configuration access, replacing previous config-based retrieval. Removes global AddedWho property for improved maintainability.
2026-03-16 13:32:34 +01:00
636397efb8 Remove MaxConcurrentInvocations from RecAction config
Removed the MaxConcurrentInvocations property from the RecActionOptions class and deleted the corresponding setting from the RecAction section in appsettings.json. This makes RecActionOptions an empty class.
2026-03-16 13:28:50 +01:00
ef4d0767e9 Remove FakeProfileId config and related extension method
Removed the GetFakeProfileId extension method and its class from ConfigExtensions.cs, along with the "FakeProfileId" entry from appsettings.json. Also fixed a trailing comma in appsettings.json to ensure valid JSON syntax.
2026-03-16 13:26:08 +01:00
f15725ade2 Support NTLM password substitution in DEBUG mode
In DEBUG builds, replace "%NTLM_PW%" in NTLM auth password with a value from config. This enables dynamic credential testing without hardcoding passwords.
2026-03-16 13:18:24 +01:00
382eef0089 Enable User Secrets in ReC.API.csproj for dev config
Added <UserSecretsId> to the project file to support ASP.NET Core User Secrets, allowing secure storage of sensitive development configuration data.
2026-03-16 12:28:58 +01:00
81 changed files with 1051 additions and 824 deletions

View File

@@ -25,7 +25,7 @@ public class CommonController(IMediator mediator) : ControllerBase
} }
[HttpDelete] [HttpDelete]
public async Task<IActionResult> DeleteObject([FromBody] DeleteObjectProcedure procedure, CancellationToken cancel) public async Task<IActionResult> DeleteObject([FromQuery] DeleteObjectProcedure procedure, CancellationToken cancel)
{ {
var result = await mediator.Send(procedure, cancel); var result = await mediator.Send(procedure, cancel);
return Ok(result); return Ok(result);

View File

@@ -1,15 +1,13 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.EndpointAuth.Commands; using ReC.Application.EndpointAuth.Commands;
namespace ReC.API.Controllers; namespace ReC.API.Controllers;
[Route("api/[controller]")] [Route("api/[controller]")]
[ApiController] [ApiController]
public class EndpointAuthController(IMediator mediator, IConfiguration config) : ControllerBase public class EndpointAuthController(IMediator mediator) : ControllerBase
{ {
/// <summary> /// <summary>
/// Inserts an endpoint authentication record via the ENDPOINT_AUTH insert procedure. /// Inserts an endpoint authentication record via the ENDPOINT_AUTH insert procedure.
@@ -19,38 +17,38 @@ public class EndpointAuthController(IMediator mediator, IConfiguration config) :
/// <returns>The created ENDPOINT_AUTH identifier.</returns> /// <returns>The created ENDPOINT_AUTH identifier.</returns>
[HttpPost] [HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Post([FromBody] InsertEndpointAuthProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Post([FromBody] InsertEndpointAuthCommand procedure, CancellationToken cancel)
{ {
var id = await mediator.ExecuteInsertProcedure(procedure, config["AddedWho"], cancel); var id = await mediator.Send(procedure, cancel);
return StatusCode(StatusCodes.Status201Created, id); return StatusCode(StatusCodes.Status201Created, id);
} }
/// <summary> /// <summary>
/// Updates an endpoint authentication record via the ENDPOINT_AUTH update procedure. /// Updates an endpoint authentication record via the ENDPOINT_AUTH update procedure.
/// </summary> /// </summary>
/// <param name="id">ENDPOINT_AUTH identifier to update.</param> /// <param name="id">The identifier of the ENDPOINT_AUTH record to update.</param>
/// <param name="procedure">UpdateEndpointAuthProcedure payload.</param> /// <param name="data">UpdateEndpointAuthProcedure payload.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpPut("{id:long}")] [HttpPut("{id:long}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointAuthProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointAuthDto data, CancellationToken cancel)
{ {
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel); await mediator.Send(new UpdateEndpointAuthCommand() { Id = id, Data = data}, cancel);
return NoContent(); return NoContent();
} }
/// <summary> /// <summary>
/// Deletes endpoint authentication records via the ENDPOINT_AUTH delete procedure for the specified id range. /// Deletes endpoint authentication records via the ENDPOINT_AUTH delete procedure for the specified id range.
/// </summary> /// </summary>
/// <param name="procedure">DeleteEndpointAuthProcedure payload (Start, End, Force).</param> /// <param name="command">DeleteEndpointAuthProcedure payload (Start, End, Force).</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpDelete] [HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete([FromBody] DeleteEndpointAuthProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Delete([FromQuery] DeleteEndpointAuthCommand command, CancellationToken cancel)
{ {
await mediator.ExecuteDeleteProcedure(procedure, cancel); await mediator.Send(command, cancel);
return NoContent(); return NoContent();
} }
} }

View File

@@ -1,15 +1,13 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.EndpointParams.Commands; using ReC.Application.EndpointParams.Commands;
namespace ReC.API.Controllers; namespace ReC.API.Controllers;
[Route("api/[controller]")] [Route("api/[controller]")]
[ApiController] [ApiController]
public class EndpointParamsController(IMediator mediator, IConfiguration config) : ControllerBase public class EndpointParamsController(IMediator mediator) : ControllerBase
{ {
/// <summary> /// <summary>
/// Inserts endpoint parameter records via the ENDPOINT_PARAMS insert procedure. /// Inserts endpoint parameter records via the ENDPOINT_PARAMS insert procedure.
@@ -19,38 +17,38 @@ public class EndpointParamsController(IMediator mediator, IConfiguration config)
/// <returns>The created ENDPOINT_PARAMS identifier.</returns> /// <returns>The created ENDPOINT_PARAMS identifier.</returns>
[HttpPost] [HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Post([FromBody] InsertEndpointParamsProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Post([FromBody] InsertEndpointParamsCommand procedure, CancellationToken cancel)
{ {
var id = await mediator.ExecuteInsertProcedure(procedure, config["AddedWho"], cancel); var id = await mediator.Send(procedure, cancel);
return StatusCode(StatusCodes.Status201Created, id); return StatusCode(StatusCodes.Status201Created, id);
} }
/// <summary> /// <summary>
/// Updates endpoint parameter records via the ENDPOINT_PARAMS update procedure. /// Updates endpoint parameter records via the ENDPOINT_PARAMS update procedure.
/// </summary> /// </summary>
/// <param name="id">ENDPOINT_PARAMS identifier to update.</param> /// <param name="id">The identifier of the ENDPOINT_PARAMS record to update.</param>
/// <param name="procedure">UpdateEndpointParamsProcedure payload.</param> /// <param name="data">UpdateEndpointParamsProcedure payload.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpPut("{id:long}")] [HttpPut("{id:long}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointParamsProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointParamsDto data, CancellationToken cancel)
{ {
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel); await mediator.Send(new UpdateEndpointParamsCommand() { Id = id, Data = data }, cancel);
return NoContent(); return NoContent();
} }
/// <summary> /// <summary>
/// Deletes endpoint parameter records via the ENDPOINT_PARAMS delete procedure for the specified id range. /// Deletes endpoint parameter records via the ENDPOINT_PARAMS delete procedure for the specified id range.
/// </summary> /// </summary>
/// <param name="procedure">DeleteEndpointParamsProcedure payload (Start, End, Force).</param> /// <param name="command">DeleteEndpointParamsProcedure payload (Start, End, Force).</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpDelete] [HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete([FromBody] DeleteEndpointParamsProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Delete([FromQuery] DeleteEndpointParamsCommand command, CancellationToken cancel)
{ {
await mediator.ExecuteDeleteProcedure(procedure, cancel); await mediator.Send(command, cancel);
return NoContent(); return NoContent();
} }
} }

View File

@@ -1,15 +1,13 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Endpoints.Commands; using ReC.Application.Endpoints.Commands;
namespace ReC.API.Controllers; namespace ReC.API.Controllers;
[Route("api/[controller]")] [Route("api/[controller]")]
[ApiController] [ApiController]
public class EndpointsController(IMediator mediator, IConfiguration config) : ControllerBase public class EndpointsController(IMediator mediator) : ControllerBase
{ {
/// <summary> /// <summary>
/// Inserts an endpoint via the ENDPOINT insert procedure. /// Inserts an endpoint via the ENDPOINT insert procedure.
@@ -19,38 +17,38 @@ public class EndpointsController(IMediator mediator, IConfiguration config) : Co
/// <returns>The created ENDPOINT identifier.</returns> /// <returns>The created ENDPOINT identifier.</returns>
[HttpPost] [HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Post([FromBody] InsertEndpointProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Post([FromBody] InsertEndpointCommand procedure, CancellationToken cancel)
{ {
var id = await mediator.ExecuteInsertProcedure(procedure, config["AddedWho"], cancel); var id = await mediator.Send(procedure, cancel);
return StatusCode(StatusCodes.Status201Created, id); return StatusCode(StatusCodes.Status201Created, id);
} }
/// <summary> /// <summary>
/// Updates an endpoint via the ENDPOINT update procedure. /// Updates an endpoint via the ENDPOINT update procedure.
/// </summary> /// </summary>
/// <param name="id">ENDPOINT identifier to update.</param> /// <param name="id">The identifier of the ENDPOINT record to update.</param>
/// <param name="procedure">UpdateEndpointProcedure payload.</param> /// <param name="data">UpdateEndpointProcedure payload.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpPut("{id:long}")] [HttpPut("{id:long}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointDto data, CancellationToken cancel)
{ {
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel); await mediator.Send(new UpdateEndpointCommand() { Id = id, Data = data }, cancel);
return NoContent(); return NoContent();
} }
/// <summary> /// <summary>
/// Deletes endpoints via the ENDPOINT delete procedure for the specified id range. /// Deletes endpoints via the ENDPOINT delete procedure for the specified id range.
/// </summary> /// </summary>
/// <param name="procedure">DeleteEndpointProcedure payload (Start, End, Force).</param> /// <param name="command">DeleteEndpointProcedure payload (Start, End, Force).</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpDelete] [HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete([FromBody] DeleteEndpointProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Delete([FromQuery] DeleteEndpointCommand command, CancellationToken cancel)
{ {
await mediator.ExecuteDeleteProcedure(procedure, cancel); await mediator.Send(command, cancel);
return NoContent(); return NoContent();
} }
} }

View File

@@ -1,8 +1,6 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Profile.Commands; using ReC.Application.Profile.Commands;
using ReC.Application.Profile.Queries; using ReC.Application.Profile.Queries;
@@ -26,38 +24,38 @@ public class ProfileController(IMediator mediator) : ControllerBase
/// <returns>The created profile identifier.</returns> /// <returns>The created profile identifier.</returns>
[HttpPost] [HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Post([FromBody] InsertProfileProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Post([FromBody] InsertProfileCommand procedure, CancellationToken cancel)
{ {
var id = await mediator.ExecuteInsertProcedure(procedure, cancel: cancel); var id = await mediator.Send(procedure, cancel);
return CreatedAtAction(nameof(Get), new { id }, id); return CreatedAtAction(nameof(Get), new { id }, id);
} }
/// <summary> /// <summary>
/// Updates a profile via the PROFILE update procedure. /// Updates a profile via the PROFILE update procedure.
/// </summary> /// </summary>
/// <param name="id">Profile identifier to update.</param> /// <param name="id">The identifier of the PROFILE record to update.</param>
/// <param name="procedure">UpdateProfileProcedure payload.</param> /// <param name="data">UpdateProfileProcedure payload.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpPut("{id:long}")] [HttpPut("{id:long}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateProfileProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateProfileDto data, CancellationToken cancel)
{ {
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel); await mediator.Send(new UpdateProfileCommand() { Id = id, Data = data }, cancel);
return NoContent(); return NoContent();
} }
/// <summary> /// <summary>
/// Deletes profile records via the PROFILE delete procedure for the specified id range. /// Deletes profile records via the PROFILE delete procedure for the specified id range.
/// </summary> /// </summary>
/// <param name="procedure">DeleteProfileProcedure payload (Start, End, Force).</param> /// <param name="command">DeleteProfileProcedure payload (Start, End, Force).</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpDelete] [HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete([FromBody] DeleteProfileProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Delete([FromQuery] DeleteProfileCommand command, CancellationToken cancel)
{ {
await mediator.ExecuteDeleteProcedure(procedure, cancel); await mediator.Send(command, cancel);
return NoContent(); return NoContent();
} }
} }

View File

@@ -1,8 +1,6 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.RecActions.Commands; using ReC.Application.RecActions.Commands;
using ReC.Application.RecActions.Queries; using ReC.Application.RecActions.Queries;
@@ -10,19 +8,19 @@ namespace ReC.API.Controllers;
[Route("api/[controller]")] [Route("api/[controller]")]
[ApiController] [ApiController]
public class RecActionController(IMediator mediator, IConfiguration config) : ControllerBase public class RecActionController(IMediator mediator) : ControllerBase
{ {
/// <summary> /// <summary>
/// Invokes a batch of RecActions for a given profile. /// Invokes a batch of RecActions for a given profile.
/// </summary> /// </summary>
/// <param name="profileId">The ID of the profile.</param> /// <param name="command">The command containing the profile ID.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>An HTTP 202 Accepted response indicating the process has been started.</returns> /// <returns>An HTTP 202 Accepted response indicating the process has been started.</returns>
[HttpPost("invoke/{profileId}")] [HttpPost("invoke/{command}")]
[ProducesResponseType(StatusCodes.Status202Accepted)] [ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Invoke([FromRoute] int profileId, CancellationToken cancel) public async Task<IActionResult> Invoke([FromRoute] InvokeBatchRecActionViewsCommand command, CancellationToken cancel)
{ {
await mediator.InvokeBatchRecActionView(profileId, cancel); await mediator.Send(command, cancel);
return Accepted(); return Accepted();
} }
@@ -45,9 +43,9 @@ public class RecActionController(IMediator mediator, IConfiguration config) : Co
/// <returns>An HTTP 201 Created response.</returns> /// <returns>An HTTP 201 Created response.</returns>
[HttpPost] [HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Create([FromBody] InsertActionProcedure command, CancellationToken cancel) public async Task<IActionResult> Create([FromBody] InsertActionCommand command, CancellationToken cancel)
{ {
await mediator.ExecuteInsertProcedure(command, config["AddedWho"], cancel); await mediator.Send(command, cancel);
return StatusCode(StatusCodes.Status201Created); return StatusCode(StatusCodes.Status201Created);
} }
@@ -55,29 +53,29 @@ public class RecActionController(IMediator mediator, IConfiguration config) : Co
/// <summary> /// <summary>
/// Updates a RecAction via the ACTION update procedure. /// Updates a RecAction via the ACTION update procedure.
/// </summary> /// </summary>
/// <param name="id">RecAction identifier to update.</param> /// <param name="id">The identifier of the ACTION record to update.</param>
/// <param name="procedure">UpdateActionProcedure payload.</param> /// <param name="data">UpdateActionProcedure payload.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpPut("{id:long}")] [HttpPut("{id:long}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Update([FromRoute] long id, [FromBody] UpdateActionProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Update([FromRoute] long id, [FromBody] UpdateActionDto data, CancellationToken cancel)
{ {
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel); await mediator.Send(new UpdateActionCommand() { Id = id, Data = data }, cancel);
return NoContent(); return NoContent();
} }
/// <summary> /// <summary>
/// Deletes RecActions via the ACTION delete procedure for the specified id range. /// Deletes RecActions via the ACTION delete procedure for the specified id range.
/// </summary> /// </summary>
/// <param name="procedure">DeleteActionProcedure payload (Start, End, Force).</param> /// <param name="command">DeleteActionProcedure payload (Start, End, Force).</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>An HTTP 204 No Content response upon successful deletion.</returns> /// <returns>An HTTP 204 No Content response upon successful deletion.</returns>
[HttpDelete] [HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete([FromBody] DeleteActionProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Delete([FromQuery] DeleteActionCommand command, CancellationToken cancel)
{ {
await mediator.ExecuteDeleteProcedure(procedure, cancel); await mediator.Send(command, cancel);
return NoContent(); return NoContent();
} }
#endregion CRUD #endregion CRUD

View File

@@ -1,10 +1,6 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ReC.API.Extensions; using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
using ReC.API.Models;
using ReC.Application.Common.Procedures.DeleteProcedure;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Results.Commands; using ReC.Application.Results.Commands;
using ReC.Application.Results.Queries; using ReC.Application.Results.Queries;
@@ -32,38 +28,38 @@ public class ResultController(IMediator mediator) : ControllerBase
/// <returns>The created RESULT identifier.</returns> /// <returns>The created RESULT identifier.</returns>
[HttpPost] [HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Post([FromBody] InsertResultProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Post([FromBody] InsertResultCommand procedure, CancellationToken cancel)
{ {
var id = await mediator.ExecuteInsertProcedure(procedure, cancel: cancel); var id = await mediator.Send(procedure, cancel);
return CreatedAtAction(nameof(Get), new { actionId = procedure.ActionId }, new { id, procedure.ActionId }); return CreatedAtAction(nameof(Get), new { actionId = procedure.ActionId }, new { id, procedure.ActionId });
} }
/// <summary> /// <summary>
/// Updates a RESULT record via the update procedure. /// Updates a RESULT record via the update procedure.
/// </summary> /// </summary>
/// <param name="id">RESULT identifier to update.</param> /// <param name="id">The identifier of the RESULT record to update.</param>
/// <param name="procedure">UpdateResultProcedure payload.</param> /// <param name="data">UpdateResultProcedure payload.</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpPut("{id:long}")] [HttpPut("{id:long}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateResultProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateResultDto data, CancellationToken cancel)
{ {
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel); await mediator.Send(new UpdateResultCommand() { Id = id, Data = data }, cancel);
return NoContent(); return NoContent();
} }
/// <summary> /// <summary>
/// Deletes RESULT records via the delete procedure for the specified id range. /// Deletes RESULT records via the delete procedure for the specified id range.
/// </summary> /// </summary>
/// <param name="procedure">DeleteResultProcedure payload (Start, End, Force).</param> /// <param name="command">DeleteResultProcedure payload (Start, End, Force).</param>
/// <param name="cancel">A token to cancel the operation.</param> /// <param name="cancel">A token to cancel the operation.</param>
/// <returns>No content on success.</returns> /// <returns>No content on success.</returns>
[HttpDelete] [HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Delete([FromBody] DeleteResultProcedure procedure, CancellationToken cancel) public async Task<IActionResult> Delete([FromQuery] DeleteResultCommand command, CancellationToken cancel)
{ {
await mediator.ExecuteDeleteProcedure(procedure, cancel); await mediator.Send(command, cancel);
return NoContent(); return NoContent();
} }
} }

View File

@@ -1,6 +0,0 @@
namespace ReC.API.Extensions;
public static class ConfigurationExtensions
{
public static int GetFakeProfileId(this IConfiguration config) => config.GetValue("FakeProfileId", 2);
}

View File

@@ -7,13 +7,11 @@ using System.Text.Json;
namespace ReC.API.Middleware; namespace ReC.API.Middleware;
//TODO: Fix and use DigitalData.Core.Exceptions.Middleware
/// <summary> /// <summary>
/// Middleware for handling exceptions globally in the application. /// Middleware for handling exceptions globally in the application.
/// Captures exceptions thrown during the request pipeline execution, /// Captures exceptions thrown during the request pipeline execution,
/// logs them, and returns an appropriate HTTP response with a JSON error details. /// logs them, and returns an appropriate HTTP response with a JSON error details.
/// </summary> /// </summary>
[Obsolete("Use DigitalData.Core.Exceptions.Middleware")]
public class ExceptionHandlingMiddleware public class ExceptionHandlingMiddleware
{ {
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
@@ -164,6 +162,22 @@ public class ExceptionHandlingMiddleware
}; };
break; break;
case RecActionException recActionEx:
logger.LogWarning(
recActionEx,
"Rec action failed. ActionId: {ActionId}, ProfileId: {ProfileId}",
recActionEx.ActionId,
recActionEx.ProfileId);
context.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity;
details = new()
{
Title = "Rec Action Failed",
Detail = recActionEx.InnerException?.Message
?? "An error occurred while executing the rec action. Check the logs for more details."
};
break;
default: default:
logger.LogError(exception, "Unhandled exception occurred."); logger.LogError(exception, "Unhandled exception occurred.");
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

View File

@@ -70,9 +70,7 @@ try
var app = builder.Build(); var app = builder.Build();
#pragma warning disable CS0618
app.UseMiddleware<ExceptionHandlingMiddleware>(); app.UseMiddleware<ExceptionHandlingMiddleware>();
#pragma warning restore CS0618
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment() || config.GetValue<bool>("UseSwagger")) if (app.Environment.IsDevelopment() || config.GetValue<bool>("UseSwagger"))

View File

@@ -10,13 +10,14 @@
<Product>ReC.API</Product> <Product>ReC.API</Product>
<PackageIcon>Assets\icon.ico</PackageIcon> <PackageIcon>Assets\icon.ico</PackageIcon>
<PackageTags>digital data rest-caller rec api</PackageTags> <PackageTags>digital data rest-caller rec api</PackageTags>
<Version>2.0.1-beta</Version> <Version>2.0.2-beta</Version>
<AssemblyVersion>2.0.1.0</AssemblyVersion> <AssemblyVersion>2.0.2.0</AssemblyVersion>
<FileVersion>2.0.1.0</FileVersion> <FileVersion>2.0.2.0</FileVersion>
<InformationalVersion>2.0.1-beta</InformationalVersion> <InformationalVersion>2.0.1-beta</InformationalVersion>
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright> <Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn> <NoWarn>$(NoWarn);1591</NoWarn>
<UserSecretsId>cf893b96-c71a-4a96-a6a7-40004249e1a3</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -6,13 +6,12 @@
"AllowedHosts": "*", "AllowedHosts": "*",
"LuckyPennySoftwareLicenseKey": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx1Y2t5UGVubnlTb2Z0d2FyZUxpY2Vuc2VLZXkvYmJiMTNhY2I1OTkwNGQ4OWI0Y2IxYzg1ZjA4OGNjZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2x1Y2t5cGVubnlzb2Z0d2FyZS5jb20iLCJhdWQiOiJMdWNreVBlbm55U29mdHdhcmUiLCJleHAiOiIxNzg0ODUxMjAwIiwiaWF0IjoiMTc1MzM2MjQ5MSIsImFjY291bnRfaWQiOiIwMTk4M2M1OWU0YjM3MjhlYmZkMzEwM2MyYTQ4NmU4NSIsImN1c3RvbWVyX2lkIjoiY3RtXzAxazB5NmV3MmQ4YTk4Mzg3aDJnbTRuOWswIiwic3ViX2lkIjoiLSIsImVkaXRpb24iOiIwIiwidHlwZSI6IjIifQ.ZqsFG7kv_-xGfxS6ACk3i0iuNiVUXX2AvPI8iAcZ6-z2170lGv__aO32tWpQccD9LCv5931lBNLWSblKS0MT3gOt-5he2TEftwiSQGFwoIBgtOHWsNRMinUrg2trceSp3IhyS3UaMwnxZDrCvx4-0O-kpOzVpizeHUAZNr5U7oSCWO34bpKdae6grtM5e3f93Z1vs7BW_iPgItd-aLvPwApbaG9VhmBTKlQ7b4Jh64y7UXJ9mKP7Qb_Oa97oEg0oY5DPHOWTZWeE1EzORgVr2qkK2DELSHuZ_EIUhODojkClPNAKtvEl_qEjpq0HZCIvGwfCCRlKlSkQqIeZdFkiXg", "LuckyPennySoftwareLicenseKey": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx1Y2t5UGVubnlTb2Z0d2FyZUxpY2Vuc2VLZXkvYmJiMTNhY2I1OTkwNGQ4OWI0Y2IxYzg1ZjA4OGNjZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2x1Y2t5cGVubnlzb2Z0d2FyZS5jb20iLCJhdWQiOiJMdWNreVBlbm55U29mdHdhcmUiLCJleHAiOiIxNzg0ODUxMjAwIiwiaWF0IjoiMTc1MzM2MjQ5MSIsImFjY291bnRfaWQiOiIwMTk4M2M1OWU0YjM3MjhlYmZkMzEwM2MyYTQ4NmU4NSIsImN1c3RvbWVyX2lkIjoiY3RtXzAxazB5NmV3MmQ4YTk4Mzg3aDJnbTRuOWswIiwic3ViX2lkIjoiLSIsImVkaXRpb24iOiIwIiwidHlwZSI6IjIifQ.ZqsFG7kv_-xGfxS6ACk3i0iuNiVUXX2AvPI8iAcZ6-z2170lGv__aO32tWpQccD9LCv5931lBNLWSblKS0MT3gOt-5he2TEftwiSQGFwoIBgtOHWsNRMinUrg2trceSp3IhyS3UaMwnxZDrCvx4-0O-kpOzVpizeHUAZNr5U7oSCWO34bpKdae6grtM5e3f93Z1vs7BW_iPgItd-aLvPwApbaG9VhmBTKlQ7b4Jh64y7UXJ9mKP7Qb_Oa97oEg0oY5DPHOWTZWeE1EzORgVr2qkK2DELSHuZ_EIUhODojkClPNAKtvEl_qEjpq0HZCIvGwfCCRlKlSkQqIeZdFkiXg",
"RecAction": { "RecAction": {
"MaxConcurrentInvocations": 5 "AddedWho": "ReC.API",
"UseHttp1ForNtlm": false
}, },
// Bad request SqlException numbers numbers can be updated at runtime; no restart required. // Bad request SqlException numbers numbers can be updated at runtime; no restart required.
"SqlException": { "SqlException": {
// https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlexception.number // https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlexception.number
"BadRequestSqlExceptionNumbers": [ 515, 547, 2601, 2627, 50000 ] "BadRequestSqlExceptionNumbers": [ 515, 547, 2601, 2627, 50000 ]
}, }
"AddedWho": "ReC.API",
"FakeProfileId": 2
} }

View File

@@ -0,0 +1,49 @@
using MediatR;
using ReC.Application.Common.Exceptions;
using ReC.Application.Common.Interfaces;
using ReC.Application.RecActions.Commands;
using ReC.Application.Results.Commands;
using ReC.Domain.Constants;
using System.Text.Json;
namespace ReC.Application.Common.Behaviors.InvokeAction;
public class PostprocessingBehavior(IRecDbContext context, ISender sender) : IPipelineBehavior<InvokeRecActionViewCommand, Unit>
{
public async Task<Unit> Handle(InvokeRecActionViewCommand request, RequestHandlerDelegate<Unit> next, CancellationToken cancel)
{
await next(cancel);
try
{
if (request.Action.PostprocessingQuery is string query)
{
var result = await context.ExecuteDynamicSqlAsync(query, cancel);
var info = JsonSerializer.Serialize(result);
await sender.Send(new InsertResultCommand()
{
ActionId = request.Action.Id,
Info = info,
Type = ResultType.Post
}, cancel);
}
}
catch (Exception ex)
{
var error = ex.ToString();
await sender.Send(new InsertResultCommand()
{
ActionId = request.Action.Id,
Error = error,
Type = ResultType.Post
}, cancel);
if (request.Action.ErrorAction == ErrorAction.Stop)
throw new RecActionException(request.Action.Id, request.Action.ProfileId, ex);
}
return Unit.Value;
}
}

View File

@@ -0,0 +1,44 @@
using MediatR;
using ReC.Application.Common.Exceptions;
using ReC.Application.Common.Interfaces;
using ReC.Application.RecActions.Commands;
using ReC.Application.Results.Commands;
using ReC.Domain.Constants;
using System.Text.Json;
namespace ReC.Application.Common.Behaviors.InvokeAction;
public class PreprocessingBehavior(IRecDbContext context, ISender sender) : IPipelineBehavior<InvokeRecActionViewCommand, Unit>
{
public async Task<Unit> Handle(InvokeRecActionViewCommand request, RequestHandlerDelegate<Unit> next, CancellationToken cancel)
{
try
{
if (request.Action.PreprocessingQuery is string query)
{
var result = await context.ExecuteDynamicSqlAsync(query, cancel);
await sender.Send(new InsertResultCommand()
{
ActionId = request.Action.Id,
Info = JsonSerializer.Serialize(result),
Type = ResultType.Pre
}, cancel);
}
}
catch (Exception ex)
{
await sender.Send(new InsertResultCommand()
{
ActionId = request.Action.Id,
Error = ex.ToString(),
Type = ResultType.Pre
}, cancel);
if (request.Action.ErrorAction == ErrorAction.Stop)
throw new RecActionException(request.Action.Id, request.Action.ProfileId, ex);
}
return await next(cancel);
}
}

View File

@@ -1,18 +1,38 @@
namespace ReC.Application.Common.Dto; using ReC.Domain.Constants;
namespace ReC.Application.Common.Dto;
public record OutResDto public record OutResDto
{ {
public long Id { get; set; } public long Id { get; set; }
public long ActionId { get; set; } public long? ActionId { get; set; }
public RecActionDto? Action { get; set; }
public long? ProfileId { get; set; }
public ProfileDto? Profile { get; set; }
public string? ProfileName { get; set; }
public short? StatusCode { get; set; }
public string? StatusName { get; set; }
public ResultType? Type { get; set; }
public string? Header { get; set; } public string? Header { get; set; }
public string? Body { get; set; } public string? Body { get; set; }
public string AddedWho { get; set; } = null!; public string? Info { get; set; }
public DateTime AddedWhen { get; set; } public string? Error { get; set; }
public string? AddedWho { get; set; }
public DateTime? AddedWhen { get; set; }
public string? ChangedWho { get; set; } public string? ChangedWho { get; set; }

View File

@@ -0,0 +1,9 @@
namespace ReC.Application.Common.Exceptions;
public class RecActionException(long actionId, long? profileId, Exception innerException)
: Exception($"Rec action failed. ActionId: {actionId}, ProfileId: {profileId}", innerException)
{
public long ActionId { get; } = actionId;
public long? ProfileId { get; } = profileId;
}

View File

@@ -1,6 +1,8 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using ReC.Domain.QueryOutput; using ReC.Domain.QueryOutput;
using ReC.Domain.Views; using ReC.Domain.Views;
using System.Text.Json;
namespace ReC.Application.Common.Interfaces; namespace ReC.Application.Common.Interfaces;
@@ -21,4 +23,39 @@ public interface IRecDbContext
#endregion DbSets #endregion DbSets
public Task<int> SaveChangesAsync(CancellationToken cancel = default); public Task<int> SaveChangesAsync(CancellationToken cancel = default);
public DatabaseFacade Database { get; }
}
public static class RecDbContextSaveExtensions
{
//TODO: Once it is finalized, move it to Common.Infrastructure
public static async Task<IEnumerable<Dictionary<string, object?>>> ExecuteDynamicSqlAsync(this IRecDbContext context, string sql, CancellationToken cancel = default)
{
var result = new List<Dictionary<string, object?>>();
using var command = context.Database.GetDbConnection().CreateCommand();
command.CommandText = sql;
await context.Database.OpenConnectionAsync(cancel);
using var reader = await command.ExecuteReaderAsync(cancel);
while (await reader.ReadAsync(cancel))
{
var row = new Dictionary<string, object?>();
for (int i = 0; i < reader.FieldCount; i++)
{
var columnName = reader.GetName(i);
var value = reader.IsDBNull(i) ? null : reader.GetValue(i);
row[columnName] = value;
}
result.Add(row);
}
return result;
}
} }

View File

@@ -2,5 +2,5 @@
public class RecActionOptions public class RecActionOptions
{ {
public int MaxConcurrentInvocations { get; set; } = 5; public bool UseHttp1ForNtlm { get; set; } = false;
} }

View File

@@ -31,25 +31,6 @@ public record DeleteObjectProcedure : IRequest<int>
public bool Force { get; set; } public bool Force { get; set; }
} }
public static class DeleteObjectProcedureExtensions
{
public static Task<int> ExecuteDeleteProcedure(this ISender sender, IDeleteProcedure procedure, CancellationToken cancel = default)
{
return sender.Send(procedure.ToObjectProcedure(), cancel);
}
public static Task<int> ExecuteDeleteProcedure(this ISender sender, string entity, long start, long end = 0, bool force = false, CancellationToken cancel = default)
{
return sender.Send(new DeleteObjectProcedure
{
Entity = entity,
Start = start,
End = end,
Force = force
}, cancel);
}
}
public class DeleteObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<DeleteObjectProcedure, int> public class DeleteObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<DeleteObjectProcedure, int>
{ {
public async Task<int> Handle(DeleteObjectProcedure request, CancellationToken cancel) public async Task<int> Handle(DeleteObjectProcedure request, CancellationToken cancel)

View File

@@ -1,6 +1,7 @@
using MediatR;
namespace ReC.Application.Common.Procedures.DeleteProcedure; namespace ReC.Application.Common.Procedures.DeleteProcedure;
public interface IDeleteProcedure public interface IDeleteProcedure : IRequest<int>
{ {
public DeleteObjectProcedure ToObjectProcedure();
} }

View File

@@ -1,6 +1,7 @@
namespace ReC.Application.Common.Procedures.InsertProcedure; using MediatR;
public interface IInsertProcedure namespace ReC.Application.Common.Procedures.InsertProcedure;
public interface IInsertProcedure : IRequest<long>
{ {
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null);
} }

View File

@@ -21,28 +21,15 @@ public record InsertObjectProcedure : IRequest<long>
/// </summary> /// </summary>
public string Entity { get; set; } = null!; public string Entity { get; set; } = null!;
internal string? AddedWho { get; private set; } //TODO: update to set in authentication middleware or similar, and remove from procedure properties
internal string? AddedWho { get; private set; } = "ReC.API";
public InsertObjectProcedure AddedBy(string? addedWho = null) public InsertActionCommand? Action { get; set; }
{ public InsertEndpointCommand? Endpoint { get; set; }
AddedWho = addedWho ?? "ReC.API"; public InsertEndpointAuthCommand? EndpointAuth { get; set; }
return this; public InsertProfileCommand? Profile { get; set; }
} public InsertResultCommand? Result { get; set; }
public InsertEndpointParamsCommand? EndpointParams { get; set; }
public InsertActionProcedure Action { get; set; } = new();
public InsertEndpointProcedure Endpoint { get; set; } = new();
public InsertEndpointAuthProcedure EndpointAuth { get; set; } = new();
public InsertProfileProcedure Profile { get; set; } = new();
public InsertResultProcedure Result { get; set; } = new();
public InsertEndpointParamsProcedure EndpointParams { get; set; } = new();
}
public static class InsertObjectProcedureExtensions
{
public static Task<long> ExecuteInsertProcedure(this ISender sender, IInsertProcedure procedure, string? addedWho = null, CancellationToken cancel = default)
{
return sender.Send(procedure.ToObjectProcedure(addedWho ?? "Rec.API"), cancel);
}
} }
public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<InsertObjectProcedure, long> public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<InsertObjectProcedure, long>
@@ -56,55 +43,58 @@ public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
new SqlParameter("@pADDED_WHO", (object?)request.AddedWho ?? DBNull.Value), new SqlParameter("@pADDED_WHO", (object?)request.AddedWho ?? DBNull.Value),
new SqlParameter("@pADDED_WHEN", (object?)DateTime.UtcNow ?? DBNull.Value), new SqlParameter("@pADDED_WHEN", (object?)DateTime.UtcNow ?? DBNull.Value),
new SqlParameter("@pACTION_PROFILE_ID", (object?)request.Action.ProfileId ?? DBNull.Value), new SqlParameter("@pACTION_PROFILE_ID", (object?)request.Action?.ProfileId ?? DBNull.Value),
new SqlParameter("@pACTION_ACTIVE", (object?)request.Action.Active ?? DBNull.Value), new SqlParameter("@pACTION_ACTIVE", (object?)request.Action?.Active ?? DBNull.Value),
new SqlParameter("@pACTION_SEQUENCE", (object?)request.Action.Sequence ?? DBNull.Value), new SqlParameter("@pACTION_SEQUENCE", (object?)request.Action?.Sequence ?? DBNull.Value),
new SqlParameter("@pACTION_ENDPOINT_ID", (object?)request.Action.EndpointId ?? DBNull.Value), new SqlParameter("@pACTION_ENDPOINT_ID", (object?)request.Action?.EndpointId ?? DBNull.Value),
new SqlParameter("@pACTION_ENDPOINT_AUTH_ID", (object?)request.Action.EndpointAuthId ?? DBNull.Value), new SqlParameter("@pACTION_ENDPOINT_AUTH_ID", (object?)request.Action?.EndpointAuthId ?? DBNull.Value),
new SqlParameter("@pACTION_ENDPOINT_PARAMS_ID", (object?)request.Action.EndpointParamsId ?? DBNull.Value), new SqlParameter("@pACTION_ENDPOINT_PARAMS_ID", (object?)request.Action?.EndpointParamsId ?? DBNull.Value),
new SqlParameter("@pACTION_SQL_CONNECTION_ID", (object?)request.Action.SqlConnectionId ?? DBNull.Value), new SqlParameter("@pACTION_SQL_CONNECTION_ID", (object?)request.Action?.SqlConnectionId ?? DBNull.Value),
new SqlParameter("@pACTION_TYPE_ID", (object?)(byte?)request.Action.TypeId ?? DBNull.Value), new SqlParameter("@pACTION_TYPE_ID", (object?)(byte?)request.Action?.TypeId ?? DBNull.Value),
new SqlParameter("@pACTION_PRE_SQL", (object?)request.Action.PreSql ?? DBNull.Value), new SqlParameter("@pACTION_PRE_SQL", (object?)request.Action?.PreSql ?? DBNull.Value),
new SqlParameter("@pACTION_HEADER_SQL", (object?)request.Action.HeaderSql ?? DBNull.Value), new SqlParameter("@pACTION_HEADER_SQL", (object?)request.Action?.HeaderSql ?? DBNull.Value),
new SqlParameter("@pACTION_BODY_SQL", (object?)request.Action.BodySql ?? DBNull.Value), new SqlParameter("@pACTION_BODY_SQL", (object?)request.Action?.BodySql ?? DBNull.Value),
new SqlParameter("@pACTION_POST_SQL", (object?)request.Action.PostSql ?? DBNull.Value), new SqlParameter("@pACTION_POST_SQL", (object?)request.Action?.PostSql ?? DBNull.Value),
new SqlParameter("@pACTION_ERROR_ACTION_ID", (object?)request.Action.ErrorActionId ?? DBNull.Value), new SqlParameter("@pACTION_ERROR_ACTION_ID", (object?)request.Action?.ErrorActionId ?? DBNull.Value),
new SqlParameter("@pENDPOINT_ACTIVE", (object?)request.Endpoint.Active ?? DBNull.Value), new SqlParameter("@pENDPOINT_ACTIVE", (object?)request.Endpoint?.Active ?? DBNull.Value),
new SqlParameter("@pENDPOINT_DESCRIPTION", (object?)request.Endpoint.Description ?? DBNull.Value), new SqlParameter("@pENDPOINT_DESCRIPTION", (object?)request.Endpoint?.Description ?? DBNull.Value),
new SqlParameter("@pENDPOINT_URI", (object?)request.Endpoint.Uri ?? DBNull.Value), new SqlParameter("@pENDPOINT_URI", (object?)request.Endpoint?.Uri ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_ACTIVE", (object?)request.EndpointAuth.Active ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_ACTIVE", (object?)request.EndpointAuth?.Active ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_DESCRIPTION", (object?)request.EndpointAuth.Description ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_DESCRIPTION", (object?)request.EndpointAuth?.Description ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_TYPE_ID", (object?)request.EndpointAuth.TypeId ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_TYPE_ID", (object?)request.EndpointAuth?.TypeId ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_API_KEY", (object?)request.EndpointAuth.ApiKey ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_API_KEY", (object?)request.EndpointAuth?.ApiKey ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_API_VALUE", (object?)request.EndpointAuth.ApiValue ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_API_VALUE", (object?)request.EndpointAuth?.ApiValue ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_API_KEY_ADD_TO_ID", (object?)request.EndpointAuth.ApiKeyAddToId ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_API_KEY_ADD_TO_ID", (object?)request.EndpointAuth?.ApiKeyAddToId ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_TOKEN", (object?)request.EndpointAuth.Token ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_TOKEN", (object?)request.EndpointAuth?.Token ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_USERNAME", (object?)request.EndpointAuth.Username ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_USERNAME", (object?)request.EndpointAuth?.Username ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_PASSWORD", (object?)request.EndpointAuth.Password ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_PASSWORD", (object?)request.EndpointAuth?.Password ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_DOMAIN", (object?)request.EndpointAuth.Domain ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_DOMAIN", (object?)request.EndpointAuth?.Domain ?? DBNull.Value),
new SqlParameter("@pENDPOINT_AUTH_WORKSTATION", (object?)request.EndpointAuth.Workstation ?? DBNull.Value), new SqlParameter("@pENDPOINT_AUTH_WORKSTATION", (object?)request.EndpointAuth?.Workstation ?? DBNull.Value),
new SqlParameter("@pPROFILE_ACTIVE", (object?)request.Profile.Active ?? DBNull.Value), new SqlParameter("@pPROFILE_ACTIVE", (object?)request.Profile?.Active ?? DBNull.Value),
new SqlParameter("@pPROFILE_TYPE_ID", (object?)request.Profile.TypeId ?? DBNull.Value), new SqlParameter("@pPROFILE_TYPE_ID", (object?)request.Profile?.TypeId ?? DBNull.Value),
new SqlParameter("@pPROFILE_MANDANTOR", (object?)request.Profile.Mandantor ?? DBNull.Value), new SqlParameter("@pPROFILE_MANDANTOR", (object?)request.Profile?.Mandantor ?? DBNull.Value),
new SqlParameter("@pPROFILE_NAME", (object?)request.Profile.Name ?? DBNull.Value), new SqlParameter("@pPROFILE_NAME", (object?)request.Profile?.Name ?? DBNull.Value),
new SqlParameter("@pPROFILE_DESCRIPTION", (object?)request.Profile.Description ?? DBNull.Value), new SqlParameter("@pPROFILE_DESCRIPTION", (object?)request.Profile?.Description ?? DBNull.Value),
new SqlParameter("@pPROFILE_LOG_LEVEL_ID", (object?)request.Profile.LogLevelId ?? DBNull.Value), new SqlParameter("@pPROFILE_LOG_LEVEL_ID", (object?)request.Profile?.LogLevelId ?? DBNull.Value),
new SqlParameter("@pPROFILE_LANGUAGE_ID", (object?)request.Profile.LanguageId ?? DBNull.Value), new SqlParameter("@pPROFILE_LANGUAGE_ID", (object?)request.Profile?.LanguageId ?? DBNull.Value),
new SqlParameter("@pRESULT_ACTION_ID", (object?)request.Result.ActionId ?? DBNull.Value), new SqlParameter("@pRESULT_ACTION_ID", (object?)request.Result?.ActionId ?? DBNull.Value),
new SqlParameter("@pRESULT_STATUS_ID", (object?)request.Result.StatusId ?? DBNull.Value), new SqlParameter("@pRESULT_STATUS_ID", (object?)request.Result?.StatusId ?? DBNull.Value),
new SqlParameter("@pRESULT_HEADER", (object?)request.Result.Header ?? DBNull.Value), new SqlParameter("@pRESULT_HEADER", (object?)request.Result?.Header ?? DBNull.Value),
new SqlParameter("@pRESULT_BODY", (object?)request.Result.Body ?? DBNull.Value), new SqlParameter("@pRESULT_BODY", (object?)request.Result?.Body ?? DBNull.Value),
new SqlParameter("@pRESULT_INFO", (object?)request.Result?.Info ?? DBNull.Value),
new SqlParameter("@pRESULT_ERROR", (object?)request.Result?.Error ?? DBNull.Value),
new SqlParameter("@pRESULT_TYPE_ID", (object?)(byte?)request.Result?.Type ?? DBNull.Value),
new SqlParameter("@pENDPOINT_PARAMS_ACTIVE", (object?)request.EndpointParams.Active ?? DBNull.Value), new SqlParameter("@pENDPOINT_PARAMS_ACTIVE", (object?)request.EndpointParams?.Active ?? DBNull.Value),
new SqlParameter("@pENDPOINT_PARAMS_DESCRIPTION", (object?)request.EndpointParams.Description ?? DBNull.Value), new SqlParameter("@pENDPOINT_PARAMS_DESCRIPTION", (object?)request.EndpointParams?.Description ?? DBNull.Value),
new SqlParameter("@pENDPOINT_PARAMS_GROUP_ID", (object?)request.EndpointParams.GroupId ?? DBNull.Value), new SqlParameter("@pENDPOINT_PARAMS_GROUP_ID", (object?)request.EndpointParams?.GroupId ?? DBNull.Value),
new SqlParameter("@pENDPOINT_PARAMS_SEQUENCE", (object?)request.EndpointParams.Sequence ?? DBNull.Value), new SqlParameter("@pENDPOINT_PARAMS_SEQUENCE", (object?)request.EndpointParams?.Sequence ?? DBNull.Value),
new SqlParameter("@pENDPOINT_PARAMS_KEY", (object?)request.EndpointParams.Key ?? DBNull.Value), new SqlParameter("@pENDPOINT_PARAMS_KEY", (object?)request.EndpointParams?.Key ?? DBNull.Value),
new SqlParameter("@pENDPOINT_PARAMS_VALUE", (object?)request.EndpointParams.Value ?? DBNull.Value), new SqlParameter("@pENDPOINT_PARAMS_VALUE", (object?)request.EndpointParams?.Value ?? DBNull.Value),
new SqlParameter new SqlParameter
{ {
@@ -123,7 +113,7 @@ public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
"@pENDPOINT_ACTIVE, @pENDPOINT_DESCRIPTION, @pENDPOINT_URI, " + "@pENDPOINT_ACTIVE, @pENDPOINT_DESCRIPTION, @pENDPOINT_URI, " +
"@pENDPOINT_AUTH_ACTIVE, @pENDPOINT_AUTH_DESCRIPTION, @pENDPOINT_AUTH_TYPE_ID, @pENDPOINT_AUTH_API_KEY, @pENDPOINT_AUTH_API_VALUE, @pENDPOINT_AUTH_API_KEY_ADD_TO_ID, @pENDPOINT_AUTH_TOKEN, @pENDPOINT_AUTH_USERNAME, @pENDPOINT_AUTH_PASSWORD, @pENDPOINT_AUTH_DOMAIN, @pENDPOINT_AUTH_WORKSTATION, " + "@pENDPOINT_AUTH_ACTIVE, @pENDPOINT_AUTH_DESCRIPTION, @pENDPOINT_AUTH_TYPE_ID, @pENDPOINT_AUTH_API_KEY, @pENDPOINT_AUTH_API_VALUE, @pENDPOINT_AUTH_API_KEY_ADD_TO_ID, @pENDPOINT_AUTH_TOKEN, @pENDPOINT_AUTH_USERNAME, @pENDPOINT_AUTH_PASSWORD, @pENDPOINT_AUTH_DOMAIN, @pENDPOINT_AUTH_WORKSTATION, " +
"@pPROFILE_ACTIVE, @pPROFILE_TYPE_ID, @pPROFILE_MANDANTOR, @pPROFILE_NAME, @pPROFILE_DESCRIPTION, @pPROFILE_LOG_LEVEL_ID, @pPROFILE_LANGUAGE_ID, " + "@pPROFILE_ACTIVE, @pPROFILE_TYPE_ID, @pPROFILE_MANDANTOR, @pPROFILE_NAME, @pPROFILE_DESCRIPTION, @pPROFILE_LOG_LEVEL_ID, @pPROFILE_LANGUAGE_ID, " +
"@pRESULT_ACTION_ID, @pRESULT_STATUS_ID, @pRESULT_HEADER, @pRESULT_BODY, " + "@pRESULT_ACTION_ID, @pRESULT_STATUS_ID, @pRESULT_HEADER, @pRESULT_BODY, @pRESULT_INFO, @pRESULT_ERROR, @pRESULT_TYPE_ID, " +
"@pENDPOINT_PARAMS_ACTIVE, @pENDPOINT_PARAMS_DESCRIPTION, @pENDPOINT_PARAMS_GROUP_ID, @pENDPOINT_PARAMS_SEQUENCE, @pENDPOINT_PARAMS_KEY, @pENDPOINT_PARAMS_VALUE, " + "@pENDPOINT_PARAMS_ACTIVE, @pENDPOINT_PARAMS_DESCRIPTION, @pENDPOINT_PARAMS_GROUP_ID, @pENDPOINT_PARAMS_SEQUENCE, @pENDPOINT_PARAMS_KEY, @pENDPOINT_PARAMS_VALUE, " +
"@oGUID OUTPUT", "@oGUID OUTPUT",
parameters, parameters,

View File

@@ -1,8 +1,6 @@
using ReC.Application.Common.Procedures.UpdateProcedure; namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
namespace ReC.Application.RecActions.Commands; public record UpdateActionDto
public record UpdateActionProcedure : IUpdateProcedure
{ {
public long? ProfileId { get; set; } public long? ProfileId { get; set; }
public bool? Active { get; set; } public bool? Active { get; set; }
@@ -17,14 +15,4 @@ public record UpdateActionProcedure : IUpdateProcedure
public string? BodySql { get; set; } public string? BodySql { get; set; }
public string? PostSql { get; set; } public string? PostSql { get; set; }
public byte? ErrorActionId { get; set; } public byte? ErrorActionId { get; set; }
}
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "ACTION",
Id = id,
Action = this
}.ChangedBy(changedWho);
}
}

View File

@@ -1,8 +1,6 @@
using ReC.Application.Common.Procedures.InsertProcedure; namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
namespace ReC.Application.EndpointAuth.Commands; public record UpdateEndpointAuthDto
public record InsertEndpointAuthProcedure : IInsertProcedure
{ {
public bool? Active { get; set; } public bool? Active { get; set; }
public string? Description { get; set; } public string? Description { get; set; }
@@ -15,13 +13,4 @@ public record InsertEndpointAuthProcedure : IInsertProcedure
public string? Password { get; set; } public string? Password { get; set; }
public string? Domain { get; set; } public string? Domain { get; set; }
public string? Workstation { get; set; } public string? Workstation { get; set; }
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
{
return new InsertObjectProcedure
{
Entity = "ENDPOINT_AUTH",
EndpointAuth = this
}.AddedBy(addedWho);
}
} }

View File

@@ -0,0 +1,8 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
public record UpdateEndpointDto
{
public bool? Active { get; set; }
public string? Description { get; set; }
public string? Uri { get; set; }
}

View File

@@ -0,0 +1,11 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
public record UpdateEndpointParamsDto
{
public bool? Active { get; set; }
public string? Description { get; set; }
public short? GroupId { get; set; }
public byte? Sequence { get; set; }
public string? Key { get; set; }
public string? Value { get; set; }
}

View File

@@ -0,0 +1,15 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
public record UpdateProfileDto
{
public bool? Active { get; set; }
public byte? TypeId { get; set; }
public string? Mandantor { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public byte? LogLevelId { get; set; }
public short? LanguageId { get; set; }
public DateTime? FirstRun { get; set; }
public DateTime? LastRun { get; set; }
public string? LastResult { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
public record UpdateResultDto
{
public long? ActionId { get; set; }
public short? StatusId { get; set; }
public string? Header { get; set; }
public string? Body { get; set; }
}

View File

@@ -1,6 +1,10 @@
using MediatR;
namespace ReC.Application.Common.Procedures.UpdateProcedure; namespace ReC.Application.Common.Procedures.UpdateProcedure;
public interface IUpdateProcedure public interface IUpdateProcedure<T> : IRequest<int>
{ {
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null); public long Id { get; set; }
}
public T Data { get; set; }
}

View File

@@ -5,6 +5,7 @@ using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using ReC.Application.Common.Exceptions; using ReC.Application.Common.Exceptions;
using ReC.Application.Common.Options; using ReC.Application.Common.Options;
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
using ReC.Application.EndpointAuth.Commands; using ReC.Application.EndpointAuth.Commands;
using ReC.Application.EndpointParams.Commands; using ReC.Application.EndpointParams.Commands;
using ReC.Application.Endpoints.Commands; using ReC.Application.Endpoints.Commands;
@@ -26,28 +27,15 @@ public record UpdateObjectProcedure : IRequest<int>
/// </summary> /// </summary>
public long Id { get; set; } public long Id { get; set; }
internal string? ChangedWho { get; private set; } //TODO: update to set in authentication middleware or similar, and remove from procedure properties
internal string? ChangedWho { get; private set; } = "ReC.API";
public UpdateObjectProcedure ChangedBy(string? changedWho = null) public UpdateActionDto Action { get; set; } = new();
{ public UpdateEndpointDto Endpoint { get; set; } = new();
ChangedWho = changedWho ?? "ReC.API"; public UpdateEndpointAuthDto EndpointAuth { get; set; } = new();
return this; public UpdateProfileDto Profile { get; set; } = new();
} public UpdateResultDto Result { get; set; } = new();
public UpdateEndpointParamsDto EndpointParams { get; set; } = new();
public UpdateActionProcedure Action { get; set; } = new();
public UpdateEndpointProcedure Endpoint { get; set; } = new();
public UpdateEndpointAuthProcedure EndpointAuth { get; set; } = new();
public UpdateProfileProcedure Profile { get; set; } = new();
public UpdateResultProcedure Result { get; set; } = new();
public UpdateEndpointParamsProcedure EndpointParams { get; set; } = new();
}
public static class UpdateObjectProcedureExtensions
{
public static Task<int> ExecuteUpdateProcedure(this ISender sender, IUpdateProcedure procedure, long id, string? changedWho = null, CancellationToken cancel = default)
{
return sender.Send(procedure.ToObjectProcedure(id, changedWho ?? "ReC.API"), cancel);
}
} }
public class UpdateObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<UpdateObjectProcedure, int> public class UpdateObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<UpdateObjectProcedure, int>

View File

@@ -2,11 +2,11 @@
using MediatR; using MediatR;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using ReC.Application.Common.Behaviors; using ReC.Application.Common.Behaviors;
using ReC.Application.Common.Behaviors.InvokeAction;
using ReC.Application.Common.Constants; using ReC.Application.Common.Constants;
using ReC.Application.Common.Options; using ReC.Application.Common.Options;
using ReC.Application.Common.Procedures; using ReC.Application.RecActions.Commands;
using System.Reflection; using System.Reflection;
namespace ReC.Application; namespace ReC.Application;
@@ -35,6 +35,8 @@ public static class DependencyInjection
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
cfg.AddOpenBehaviors([typeof(BodyQueryBehavior<,>), typeof(HeaderQueryBehavior<,>)]); cfg.AddOpenBehaviors([typeof(BodyQueryBehavior<,>), typeof(HeaderQueryBehavior<,>)]);
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>)); cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
cfg.AddBehavior(typeof(IPipelineBehavior<InvokeRecActionViewCommand, Unit>), typeof(PostprocessingBehavior));
cfg.AddBehavior(typeof(IPipelineBehavior<InvokeRecActionViewCommand, Unit>), typeof(PreprocessingBehavior));
cfg.LicenseKey = configOpt.LuckyPennySoftwareLicenseKey; cfg.LicenseKey = configOpt.LuckyPennySoftwareLicenseKey;
}); });

View File

@@ -1,8 +1,9 @@
using MediatR;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.DeleteProcedure;
namespace ReC.Application.EndpointAuth.Commands; namespace ReC.Application.EndpointAuth.Commands;
public record DeleteEndpointAuthProcedure : IDeleteProcedure public record DeleteEndpointAuthCommand : IDeleteProcedure
{ {
/// <summary> /// <summary>
/// Start GUID/ID (inclusive) /// Start GUID/ID (inclusive)
@@ -18,15 +19,18 @@ public record DeleteEndpointAuthProcedure : IDeleteProcedure
/// If true, delete even if dependent ACTION data exists /// If true, delete even if dependent ACTION data exists
/// </summary> /// </summary>
public bool Force { get; set; } public bool Force { get; set; }
}
public DeleteObjectProcedure ToObjectProcedure() public class DeleteEndpointAuthProcedureHandler(ISender sender) : IRequestHandler<DeleteEndpointAuthCommand, int>
{
public async Task<int> Handle(DeleteEndpointAuthCommand request, CancellationToken cancel)
{ {
return new DeleteObjectProcedure return await sender.Send(new DeleteObjectProcedure
{ {
Entity = "ENDPOINT_AUTH", Entity = "ENDPOINT_AUTH",
Start = Start, Start = request.Start,
End = End, End = request.End,
Force = Force Force = request.Force
}; }, cancel);
} }
} }

View File

@@ -1,8 +1,9 @@
using ReC.Application.Common.Procedures.UpdateProcedure; using MediatR;
using ReC.Application.Common.Procedures.InsertProcedure;
namespace ReC.Application.EndpointAuth.Commands; namespace ReC.Application.EndpointAuth.Commands;
public record UpdateEndpointAuthProcedure : IUpdateProcedure public record InsertEndpointAuthCommand : IInsertProcedure
{ {
public bool? Active { get; set; } public bool? Active { get; set; }
public string? Description { get; set; } public string? Description { get; set; }
@@ -15,14 +16,16 @@ public record UpdateEndpointAuthProcedure : IUpdateProcedure
public string? Password { get; set; } public string? Password { get; set; }
public string? Domain { get; set; } public string? Domain { get; set; }
public string? Workstation { get; set; } public string? Workstation { get; set; }
}
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null) public class InsertEndpointAuthProcedureHandler(ISender sender) : IRequestHandler<InsertEndpointAuthCommand, long>
{
public async Task<long> Handle(InsertEndpointAuthCommand request, CancellationToken cancel)
{ {
return new UpdateObjectProcedure return await sender.Send(new InsertObjectProcedure
{ {
Entity = "ENDPOINT_AUTH", Entity = "ENDPOINT_AUTH",
Id = id, EndpointAuth = request
EndpointAuth = this }, cancel);
}.ChangedBy(changedWho);
} }
} }

View File

@@ -0,0 +1,25 @@
using MediatR;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
namespace ReC.Application.EndpointAuth.Commands;
public record UpdateEndpointAuthCommand : IUpdateProcedure<UpdateEndpointAuthDto>
{
public long Id { get; set; }
public UpdateEndpointAuthDto Data { get; set; } = null!;
}
public class UpdateEndpointAuthProcedureHandler(ISender sender) : IRequestHandler<UpdateEndpointAuthCommand, int>
{
public async Task<int> Handle(UpdateEndpointAuthCommand request, CancellationToken cancel)
{
return await sender.Send(new UpdateObjectProcedure
{
Entity = "ENDPOINT_AUTH",
Id = request.Id,
EndpointAuth = request.Data
}, cancel);
}
}

View File

@@ -1,8 +1,9 @@
using MediatR;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.DeleteProcedure;
namespace ReC.Application.EndpointParams.Commands; namespace ReC.Application.EndpointParams.Commands;
public record DeleteEndpointParamsProcedure : IDeleteProcedure public record DeleteEndpointParamsCommand : IDeleteProcedure
{ {
/// <summary> /// <summary>
/// Start GUID/ID (inclusive) /// Start GUID/ID (inclusive)
@@ -18,15 +19,18 @@ public record DeleteEndpointParamsProcedure : IDeleteProcedure
/// If true, delete even if dependent ACTION data exists /// If true, delete even if dependent ACTION data exists
/// </summary> /// </summary>
public bool Force { get; set; } public bool Force { get; set; }
}
public DeleteObjectProcedure ToObjectProcedure() public class DeleteEndpointParamsProcedureHandler(ISender sender) : IRequestHandler<DeleteEndpointParamsCommand, int>
{
public async Task<int> Handle(DeleteEndpointParamsCommand request, CancellationToken cancel)
{ {
return new DeleteObjectProcedure return await sender.Send(new DeleteObjectProcedure
{ {
Entity = "ENDPOINT_PARAMS", Entity = "ENDPOINT_PARAMS",
Start = Start, Start = request.Start,
End = End, End = request.End,
Force = Force Force = request.Force
}; }, cancel);
} }
} }

View File

@@ -0,0 +1,26 @@
using MediatR;
using ReC.Application.Common.Procedures.InsertProcedure;
namespace ReC.Application.EndpointParams.Commands;
public record InsertEndpointParamsCommand : IInsertProcedure
{
public bool? Active { get; set; }
public string? Description { get; set; }
public short? GroupId { get; set; }
public byte? Sequence { get; set; }
public string? Key { get; set; }
public string? Value { get; set; }
}
public class InsertEndpointParamsProcedureHandler(ISender sender) : IRequestHandler<InsertEndpointParamsCommand, long>
{
public async Task<long> Handle(InsertEndpointParamsCommand request, CancellationToken cancel)
{
return await sender.Send(new InsertObjectProcedure
{
Entity = "ENDPOINT_PARAMS",
EndpointParams = request
}, cancel);
}
}

View File

@@ -1,22 +0,0 @@
using ReC.Application.Common.Procedures.InsertProcedure;
namespace ReC.Application.EndpointParams.Commands;
public record InsertEndpointParamsProcedure : IInsertProcedure
{
public bool? Active { get; set; }
public string? Description { get; set; }
public short? GroupId { get; set; }
public byte? Sequence { get; set; }
public string? Key { get; set; }
public string? Value { get; set; }
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
{
return new InsertObjectProcedure
{
Entity = "ENDPOINT_PARAMS",
EndpointParams = this
}.AddedBy(addedWho);
}
}

View File

@@ -0,0 +1,25 @@
using MediatR;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
namespace ReC.Application.EndpointParams.Commands;
public record UpdateEndpointParamsCommand : IUpdateProcedure<UpdateEndpointParamsDto>
{
public long Id { get; set; }
public UpdateEndpointParamsDto Data { get; set; } = null!;
}
public class UpdateEndpointParamsProcedureHandler(ISender sender) : IRequestHandler<UpdateEndpointParamsCommand, int>
{
public async Task<int> Handle(UpdateEndpointParamsCommand request, CancellationToken cancel)
{
return await sender.Send(new UpdateObjectProcedure
{
Entity = "ENDPOINT_PARAMS",
Id = request.Id,
EndpointParams = request.Data
}, cancel);
}
}

View File

@@ -1,23 +0,0 @@
using ReC.Application.Common.Procedures.UpdateProcedure;
namespace ReC.Application.EndpointParams.Commands;
public record UpdateEndpointParamsProcedure : IUpdateProcedure
{
public bool? Active { get; set; }
public string? Description { get; set; }
public short? GroupId { get; set; }
public byte? Sequence { get; set; }
public string? Key { get; set; }
public string? Value { get; set; }
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "ENDPOINT_PARAMS",
Id = id,
EndpointParams = this
}.ChangedBy(changedWho);
}
}

View File

@@ -1,8 +1,9 @@
using MediatR;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.DeleteProcedure;
namespace ReC.Application.Endpoints.Commands; namespace ReC.Application.Endpoints.Commands;
public record DeleteEndpointProcedure : IDeleteProcedure public record DeleteEndpointCommand : IDeleteProcedure
{ {
/// <summary> /// <summary>
/// Start GUID/ID (inclusive) /// Start GUID/ID (inclusive)
@@ -18,15 +19,18 @@ public record DeleteEndpointProcedure : IDeleteProcedure
/// If true, delete even if dependent ACTION data exists /// If true, delete even if dependent ACTION data exists
/// </summary> /// </summary>
public bool Force { get; set; } public bool Force { get; set; }
}
public DeleteObjectProcedure ToObjectProcedure() public class DeleteEndpointProcedureHandler(ISender sender) : IRequestHandler<DeleteEndpointCommand, int>
{
public async Task<int> Handle(DeleteEndpointCommand request, CancellationToken cancel)
{ {
return new DeleteObjectProcedure return await sender.Send(new DeleteObjectProcedure
{ {
Entity = "ENDPOINT", Entity = "ENDPOINT",
Start = Start, Start = request.Start,
End = End, End = request.End,
Force = Force Force = request.Force
}; }, cancel);
} }
} }

View File

@@ -0,0 +1,23 @@
using MediatR;
using ReC.Application.Common.Procedures.InsertProcedure;
namespace ReC.Application.Endpoints.Commands;
public record InsertEndpointCommand : IInsertProcedure
{
public bool? Active { get; set; }
public string? Description { get; set; }
public string? Uri { get; set; }
}
public class InsertEndpointProcedureHandler(ISender sender) : IRequestHandler<InsertEndpointCommand, long>
{
public async Task<long> Handle(InsertEndpointCommand request, CancellationToken cancel)
{
return await sender.Send(new InsertObjectProcedure
{
Entity = "ENDPOINT",
Endpoint = request
}, cancel);
}
}

View File

@@ -1,19 +0,0 @@
using ReC.Application.Common.Procedures.InsertProcedure;
namespace ReC.Application.Endpoints.Commands;
public record InsertEndpointProcedure : IInsertProcedure
{
public bool? Active { get; set; }
public string? Description { get; set; }
public string? Uri { get; set; }
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
{
return new InsertObjectProcedure
{
Entity = "ENDPOINT",
Endpoint = this
}.AddedBy(addedWho);
}
}

View File

@@ -0,0 +1,25 @@
using MediatR;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
namespace ReC.Application.Endpoints.Commands;
public record UpdateEndpointCommand : IUpdateProcedure<UpdateEndpointDto>
{
public long Id { get; set; }
public UpdateEndpointDto Data { get; set; } = null!;
}
public class UpdateEndpointProcedureHandler(ISender sender) : IRequestHandler<UpdateEndpointCommand, int>
{
public async Task<int> Handle(UpdateEndpointCommand request, CancellationToken cancel)
{
return await sender.Send(new UpdateObjectProcedure
{
Entity = "ENDPOINT",
Id = request.Id,
Endpoint = request.Data
}, cancel);
}
}

View File

@@ -1,20 +0,0 @@
using ReC.Application.Common.Procedures.UpdateProcedure;
namespace ReC.Application.Endpoints.Commands;
public record UpdateEndpointProcedure : IUpdateProcedure
{
public bool? Active { get; set; }
public string? Description { get; set; }
public string? Uri { get; set; }
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "ENDPOINT",
Id = id,
Endpoint = this
}.ChangedBy(changedWho);
}
}

View File

@@ -1,8 +1,9 @@
using MediatR;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.DeleteProcedure;
namespace ReC.Application.Profile.Commands; namespace ReC.Application.Profile.Commands;
public record DeleteProfileProcedure : IDeleteProcedure public record DeleteProfileCommand : IDeleteProcedure
{ {
/// <summary> /// <summary>
/// Start GUID/ID (inclusive) /// Start GUID/ID (inclusive)
@@ -18,15 +19,18 @@ public record DeleteProfileProcedure : IDeleteProcedure
/// If true, delete even if dependent ACTION data exists /// If true, delete even if dependent ACTION data exists
/// </summary> /// </summary>
public bool Force { get; set; } public bool Force { get; set; }
}
public DeleteObjectProcedure ToObjectProcedure() public class DeleteProfileProcedureHandler(ISender sender) : IRequestHandler<DeleteProfileCommand, int>
{
public async Task<int> Handle(DeleteProfileCommand request, CancellationToken cancel)
{ {
return new DeleteObjectProcedure return await sender.Send(new DeleteObjectProcedure
{ {
Entity = "PROFILE", Entity = "PROFILE",
Start = Start, Start = request.Start,
End = End, End = request.End,
Force = Force Force = request.Force
}; }, cancel);
} }
} }

View File

@@ -0,0 +1,27 @@
using MediatR;
using ReC.Application.Common.Procedures.InsertProcedure;
namespace ReC.Application.Profile.Commands;
public record InsertProfileCommand : IInsertProcedure
{
public bool? Active { get; set; }
public byte? TypeId { get; set; }
public string? Mandantor { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public byte? LogLevelId { get; set; }
public short? LanguageId { get; set; }
}
public class InsertProfileProcedureHandler(ISender sender) : IRequestHandler<InsertProfileCommand, long>
{
public async Task<long> Handle(InsertProfileCommand request, CancellationToken cancel)
{
return await sender.Send(new InsertObjectProcedure
{
Entity = "PROFILE",
Profile = request
}, cancel);
}
}

View File

@@ -1,23 +0,0 @@
using ReC.Application.Common.Procedures.InsertProcedure;
namespace ReC.Application.Profile.Commands;
public record InsertProfileProcedure : IInsertProcedure
{
public bool? Active { get; set; }
public byte? TypeId { get; set; }
public string? Mandantor { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public byte? LogLevelId { get; set; }
public short? LanguageId { get; set; }
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
{
return new InsertObjectProcedure
{
Entity = "PROFILE",
Profile = this
}.AddedBy(addedWho);
}
}

View File

@@ -0,0 +1,25 @@
using MediatR;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
namespace ReC.Application.Profile.Commands;
public record UpdateProfileCommand : IUpdateProcedure<UpdateProfileDto>
{
public long Id { get; set; }
public UpdateProfileDto Data { get; set; } = null!;
}
public class UpdateProfileProcedureHandler(ISender sender) : IRequestHandler<UpdateProfileCommand, int>
{
public async Task<int> Handle(UpdateProfileCommand request, CancellationToken cancel)
{
return await sender.Send(new UpdateObjectProcedure
{
Entity = "PROFILE",
Id = request.Id,
Profile = request.Data
}, cancel);
}
}

View File

@@ -1,27 +0,0 @@
using ReC.Application.Common.Procedures.UpdateProcedure;
namespace ReC.Application.Profile.Commands;
public record UpdateProfileProcedure : IUpdateProcedure
{
public bool? Active { get; set; }
public byte? TypeId { get; set; }
public string? Mandantor { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public byte? LogLevelId { get; set; }
public short? LanguageId { get; set; }
public DateTime? FirstRun { get; set; }
public DateTime? LastRun { get; set; }
public string? LastResult { get; set; }
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "PROFILE",
Id = id,
Profile = this
}.ChangedBy(changedWho);
}
}

View File

@@ -23,4 +23,9 @@
<ProjectReference Include="..\ReC.Domain\ReC.Domain.csproj" /> <ProjectReference Include="..\ReC.Domain\ReC.Domain.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Common\Behaviors\Action\" />
<Folder Include="Common\Options\DbModel\" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,8 +1,9 @@
using MediatR;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.DeleteProcedure;
namespace ReC.Application.RecActions.Commands; namespace ReC.Application.RecActions.Commands;
public record DeleteActionProcedure : IDeleteProcedure public record DeleteActionCommand : IDeleteProcedure
{ {
/// <summary> /// <summary>
/// Start GUID/ID (inclusive) /// Start GUID/ID (inclusive)
@@ -18,15 +19,18 @@ public record DeleteActionProcedure : IDeleteProcedure
/// If true, delete even if dependent RESULT data exists /// If true, delete even if dependent RESULT data exists
/// </summary> /// </summary>
public bool Force { get; set; } public bool Force { get; set; }
}
public DeleteObjectProcedure ToObjectProcedure() public class DeleteActionProcedureHandler(ISender sender) : IRequestHandler<DeleteActionCommand, int>
{
public async Task<int> Handle(DeleteActionCommand request, CancellationToken cancel)
{ {
return new DeleteObjectProcedure return await sender.Send(new DeleteObjectProcedure
{ {
Entity = "ACTION", Entity = "ACTION",
Start = Start, Start = request.Start,
End = End, End = request.End,
Force = Force Force = request.Force
}; }, cancel);
} }
} }

View File

@@ -1,9 +1,10 @@
using ReC.Application.Common.Procedures.InsertProcedure; using MediatR;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Domain.Constants; using ReC.Domain.Constants;
namespace ReC.Application.RecActions.Commands; namespace ReC.Application.RecActions.Commands;
public record InsertActionProcedure : IInsertProcedure public record InsertActionCommand : IInsertProcedure
{ {
public long? ProfileId { get; set; } public long? ProfileId { get; set; }
public bool? Active { get; set; } public bool? Active { get; set; }
@@ -18,13 +19,16 @@ public record InsertActionProcedure : IInsertProcedure
public string? BodySql { get; set; } public string? BodySql { get; set; }
public string? PostSql { get; set; } public string? PostSql { get; set; }
public byte? ErrorActionId { get; set; } public byte? ErrorActionId { get; set; }
}
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null) public class InsertActionProcedureHandler(ISender sender) : IRequestHandler<InsertActionCommand, long>
{
public async Task<long> Handle(InsertActionCommand request, CancellationToken cancel)
{ {
return new InsertObjectProcedure return await sender.Send(new InsertObjectProcedure
{ {
Entity = "ACTION", Entity = "ACTION",
Action = this Action = request
}.AddedBy(addedWho); }, cancel);
} }
} }

View File

@@ -1,5 +1,6 @@
using DigitalData.Core.Abstractions.Interfaces; using MediatR;
using MediatR; using Microsoft.Extensions.Logging;
using ReC.Application.Common.Exceptions;
using ReC.Application.RecActions.Queries; using ReC.Application.RecActions.Queries;
using ReC.Domain.Constants; using ReC.Domain.Constants;
@@ -10,13 +11,7 @@ public record InvokeBatchRecActionViewsCommand : IRequest
public long ProfileId { get; init; } public long ProfileId { get; init; }
} }
public static class InvokeBatchRecActionViewsCommandExtensions public class InvokeRecActionViewsCommandHandler(ISender sender, ILogger<InvokeRecActionViewsCommandHandler>? logger = null) : IRequestHandler<InvokeBatchRecActionViewsCommand>
{
public static Task InvokeBatchRecActionView(this ISender sender, long profileId, CancellationToken cancel = default)
=> sender.Send(new InvokeBatchRecActionViewsCommand { ProfileId = profileId }, cancel);
}
public class InvokeRecActionViewsCommandHandler(ISender sender) : IRequestHandler<InvokeBatchRecActionViewsCommand>
{ {
public async Task Handle(InvokeBatchRecActionViewsCommand request, CancellationToken cancel) public async Task Handle(InvokeBatchRecActionViewsCommand request, CancellationToken cancel)
{ {
@@ -24,15 +19,34 @@ public class InvokeRecActionViewsCommandHandler(ISender sender) : IRequestHandle
foreach (var action in actions) foreach (var action in actions)
{ {
var ok = await sender.Send(new InvokeRecActionViewCommand() { Action = action }, cancel); try
if (!ok) {
await sender.Send(new InvokeRecActionViewCommand() { Action = action }, cancel);
}
catch (RecActionException ex)
{
switch (action.ErrorAction) switch (action.ErrorAction)
{ {
case ErrorAction.Continue: case ErrorAction.Continue:
logger?.LogWarning(ex, "Rec action failed but continuing. ActionId: {ActionId}, ProfileId: {ProfileId}", ex.ActionId, ex.ProfileId);
break; break;
default: default:
return; // Rethrow the exception to stop processing further actions
throw;
} }
}
catch (Exception ex)
{
switch (action.ErrorAction)
{
case ErrorAction.Continue:
logger?.LogError(ex, "Unexpected error during rec action. ActionId: {ActionId}, ProfileId: {ProfileId}", action.Id, action.ProfileId);
break;
default:
// Rethrow the exception to stop processing further actions
throw;
}
}
} }
} }
} }

View File

@@ -1,10 +1,10 @@
using MediatR; using MediatR;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using ReC.Application.Common; using Microsoft.Extensions.Options;
using ReC.Application.Common.Constants; using ReC.Application.Common.Constants;
using ReC.Application.Common.Dto; using ReC.Application.Common.Dto;
using ReC.Application.Common.Exceptions; using ReC.Application.Common.Exceptions;
using ReC.Application.Common.Procedures.InsertProcedure; using ReC.Application.Common.Options;
using ReC.Application.Results.Commands; using ReC.Application.Results.Commands;
using ReC.Domain.Constants; using ReC.Domain.Constants;
using System.Net; using System.Net;
@@ -14,125 +14,161 @@ using System.Text.Json;
namespace ReC.Application.RecActions.Commands; namespace ReC.Application.RecActions.Commands;
public record InvokeRecActionViewCommand : IRequest<bool> public record InvokeRecActionViewCommand : IRequest
{ {
public RecActionViewDto Action { get; set; } = null!; public RecActionViewDto Action { get; set; } = null!;
} }
public class InvokeRecActionViewCommandHandler( public class InvokeRecActionViewCommandHandler(
IOptions<RecActionOptions> options,
ISender sender, ISender sender,
IHttpClientFactory clientFactory, IHttpClientFactory clientFactory,
IConfiguration? config = null IConfiguration? config = null
) : IRequestHandler<InvokeRecActionViewCommand, bool> ) : IRequestHandler<InvokeRecActionViewCommand>
{ {
public async Task<bool> Handle(InvokeRecActionViewCommand request, CancellationToken cancel) private readonly RecActionOptions _options = options.Value;
public async Task Handle(InvokeRecActionViewCommand request, CancellationToken cancel)
{ {
var action = request.Action; var action = request.Action;
HttpClient? ntlmClient = null;
using var http = clientFactory.CreateClient(Http.ClientName); try
if (action.RestType is not RestType restType)
throw new DataIntegrityException(
$"Rec action could not be invoked because the RestType value is null. " +
$"ProfileId: {action.ProfileId}, " +
$"Id: {action.Id}"
);
using var httpReq = CreateHttpRequestMessage(restType, action.EndpointUri);
if (action.Body is not null)
httpReq.Content = new StringContent(action.Body);
if (action.Headers is not null)
foreach (var header in action.Headers)
httpReq.Headers.Add(header.Key, header.Value);
switch (action.EndpointAuthType)
{ {
case EndpointAuthType.NoAuth: if (action.RestType is not RestType restType)
break; throw new DataIntegrityException(
$"Rec action could not be invoked because the RestType value is null. " +
case EndpointAuthType.ApiKey:
if (action.EndpointAuthApiKey is string apiKey && action.EndpointAuthApiValue is string apiValue)
{
switch (action.EndpointAuthApiKeyAddTo)
{
case ApiKeyLocation.Header:
httpReq.Headers.Add(apiKey, apiValue);
break;
case ApiKeyLocation.Query:
var uriBuilder = new UriBuilder(httpReq.RequestUri!);
var query = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
query[apiKey] = apiValue;
uriBuilder.Query = query.ToString();
httpReq.RequestUri = uriBuilder.Uri;
break;
default:
throw new DataIntegrityException(
$"The API key location '{action.EndpointAuthApiKeyAddTo}' is not supported. " +
$"ProfileId: {action.ProfileId}, " +
$"Id: {action.Id}"
);
}
}
break;
case EndpointAuthType.BearerToken:
case EndpointAuthType.JwtBearer:
case EndpointAuthType.OAuth2:
if (action.EndpointAuthToken is string authToken)
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
break;
case EndpointAuthType.BasicAuth:
if (action.EndpointAuthUsername is string authUsername && action.EndpointAuthPassword is string authPassword)
{
var basicAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{authUsername}:{authPassword}"));
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Basic", basicAuth);
}
break;
case EndpointAuthType.NtlmAuth:
if (!string.IsNullOrWhiteSpace(action.EndpointAuthUsername))
{
var credentials = new NetworkCredential(
action.EndpointAuthUsername,
action.EndpointAuthPassword,
action.EndpointAuthDomain);
var credentialCache = new CredentialCache { { httpReq.RequestUri!, "NTLM", credentials } };
httpReq.Options.Set(new HttpRequestOptionsKey<CredentialCache>("Credentials"), credentialCache);
}
break;
case EndpointAuthType.DigestAuth:
case EndpointAuthType.OAuth1:
case EndpointAuthType.AwsSignature:
// These authentication methods require more complex implementations,
// often involving multi-step handshakes or specialized libraries.
// They are left as placeholders for future implementation.
default:
throw new NotImplementedException(
$"The authentication type '{action.EndpointAuthType}' is not supported yet. " +
$"ProfileId: {action.ProfileId}, " + $"ProfileId: {action.ProfileId}, " +
$"Id: {action.Id}" $"Id: {action.Id}"
); );
using var httpReq = CreateHttpRequestMessage(restType, action.EndpointUri);
if (action.Body is not null)
httpReq.Content = new StringContent(action.Body);
if (action.Headers is not null)
foreach (var header in action.Headers)
httpReq.Headers.Add(header.Key, header.Value);
switch (action.EndpointAuthType)
{
case EndpointAuthType.NoAuth:
break;
case EndpointAuthType.ApiKey:
if (action.EndpointAuthApiKey is string apiKey && action.EndpointAuthApiValue is string apiValue)
{
switch (action.EndpointAuthApiKeyAddTo)
{
case ApiKeyLocation.Header:
httpReq.Headers.Add(apiKey, apiValue);
break;
case ApiKeyLocation.Query:
var uriBuilder = new UriBuilder(httpReq.RequestUri!);
var query = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
query[apiKey] = apiValue;
uriBuilder.Query = query.ToString();
httpReq.RequestUri = uriBuilder.Uri;
break;
default:
throw new DataIntegrityException(
$"The API key location '{action.EndpointAuthApiKeyAddTo}' is not supported. " +
$"ProfileId: {action.ProfileId}, " +
$"Id: {action.Id}"
);
}
}
break;
case EndpointAuthType.BearerToken:
case EndpointAuthType.JwtBearer:
case EndpointAuthType.OAuth2:
if (action.EndpointAuthToken is string authToken)
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
break;
case EndpointAuthType.BasicAuth:
if (action.EndpointAuthUsername is string authUsername && action.EndpointAuthPassword is string authPassword)
{
var basicAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{authUsername}:{authPassword}"));
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Basic", basicAuth);
}
break;
case EndpointAuthType.NtlmAuth:
if (!string.IsNullOrWhiteSpace(action.EndpointAuthUsername))
{
if (_options.UseHttp1ForNtlm)
{
httpReq.Version = HttpVersion.Version11;
httpReq.VersionPolicy = HttpVersionPolicy.RequestVersionExact;
}
var endpointAuthPassword = action.EndpointAuthPassword
#if DEBUG
?.Replace("%NTLM_PW%", config?.GetValue<string>("%NTLM_PW%"))
#endif
;
var credentials = new NetworkCredential(
action.EndpointAuthUsername,
endpointAuthPassword,
action.EndpointAuthDomain);
var credentialCache = new CredentialCache { { httpReq.RequestUri!, "NTLM", credentials } };
var ntlmHandler = new HttpClientHandler
{
Credentials = credentialCache,
UseDefaultCredentials = false
};
ntlmClient = new HttpClient(ntlmHandler, disposeHandler: true);
}
break;
case EndpointAuthType.DigestAuth:
case EndpointAuthType.OAuth1:
case EndpointAuthType.AwsSignature:
// These authentication methods require more complex implementations,
// often involving multi-step handshakes or specialized libraries.
// They are left as placeholders for future implementation.
default:
throw new NotImplementedException(
$"The authentication type '{action.EndpointAuthType}' is not supported yet. " +
$"ProfileId: {action.ProfileId}, " +
$"Id: {action.Id}"
);
}
var http = ntlmClient ?? clientFactory.CreateClient(Http.ClientName);
using var response = await http.SendAsync(httpReq, cancel);
var resBody = await response.Content.ReadAsStringAsync(cancel);
var resHeaders = response.Headers.ToDictionary();
var statusCode = (short)response.StatusCode;
await sender.Send(new InsertResultCommand()
{
StatusId = statusCode,
ActionId = action.Id,
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }),
Body = resBody,
Type = ResultType.Main
}, cancel);
} }
catch(Exception ex)
using var response = await http.SendAsync(httpReq, cancel);
var resBody = await response.Content.ReadAsStringAsync(cancel);
var resHeaders = response.Headers.ToDictionary();
var statusCode = (short)response.StatusCode;
await sender.ExecuteInsertProcedure(new InsertResultProcedure()
{ {
StatusId = statusCode, await sender.Send(new InsertResultCommand()
ActionId = action.Id, {
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }), ActionId = action.Id,
Body = resBody Error = ex.ToString(),
}, config?["AddedWho"], cancel); Type = ResultType.Main
}, cancel);
return response.IsSuccessStatusCode; if (action.ErrorAction == ErrorAction.Stop)
throw new RecActionException(action.Id, action.ProfileId, ex);
}
finally
{
ntlmClient?.Dispose();
}
} }
private static HttpRequestMessage CreateHttpRequestMessage(RestType restType, string? endpointUri) private static HttpRequestMessage CreateHttpRequestMessage(RestType restType, string? endpointUri)

View File

@@ -0,0 +1,25 @@
using MediatR;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
namespace ReC.Application.RecActions.Commands;
public record UpdateActionCommand : IUpdateProcedure<UpdateActionDto>
{
public long Id { get; set; }
public UpdateActionDto Data { get; set; } = null!;
}
public class UpdateActionProcedureHandler(ISender sender) : IRequestHandler<UpdateActionCommand, int>
{
public async Task<int> Handle(UpdateActionCommand request, CancellationToken cancel)
{
return await sender.Send(new UpdateObjectProcedure
{
Entity = "ACTION",
Id = request.Id,
Action = request.Data
}, cancel);
}
}

View File

@@ -1,8 +1,9 @@
using MediatR;
using ReC.Application.Common.Procedures.DeleteProcedure; using ReC.Application.Common.Procedures.DeleteProcedure;
namespace ReC.Application.Results.Commands; namespace ReC.Application.Results.Commands;
public record DeleteResultProcedure : IDeleteProcedure public record DeleteResultCommand : IDeleteProcedure
{ {
/// <summary> /// <summary>
/// Start GUID/ID (inclusive) /// Start GUID/ID (inclusive)
@@ -18,15 +19,18 @@ public record DeleteResultProcedure : IDeleteProcedure
/// Force parameter (not used for RESULT entity as it has no dependencies) /// Force parameter (not used for RESULT entity as it has no dependencies)
/// </summary> /// </summary>
public bool Force { get; set; } public bool Force { get; set; }
}
public DeleteObjectProcedure ToObjectProcedure() public class DeleteResultProcedureHandler(ISender sender) : IRequestHandler<DeleteResultCommand, int>
{
public async Task<int> Handle(DeleteResultCommand request, CancellationToken cancel)
{ {
return new DeleteObjectProcedure return await sender.Send(new DeleteObjectProcedure
{ {
Entity = "RESULT", Entity = "RESULT",
Start = Start, Start = request.Start,
End = End, End = request.End,
Force = Force Force = request.Force
}; }, cancel);
} }
} }

View File

@@ -0,0 +1,28 @@
using MediatR;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Domain.Constants;
namespace ReC.Application.Results.Commands;
public record InsertResultCommand : IInsertProcedure
{
public long? ActionId { get; set; }
public short? StatusId { get; set; }
public string? Header { get; set; }
public string? Body { get; set; }
public string? Info { get; set; }
public string? Error { get; set; }
public required ResultType Type { get; set; }
}
public class InsertResultProcedureHandler(ISender sender) : IRequestHandler<InsertResultCommand, long>
{
public async Task<long> Handle(InsertResultCommand request, CancellationToken cancel)
{
return await sender.Send(new InsertObjectProcedure
{
Entity = "RESULT",
Result = request
}, cancel);
}
}

View File

@@ -1,20 +0,0 @@
using ReC.Application.Common.Procedures.InsertProcedure;
namespace ReC.Application.Results.Commands;
public record InsertResultProcedure : IInsertProcedure
{
public long? ActionId { get; set; }
public short? StatusId { get; set; }
public string? Header { get; set; }
public string? Body { get; set; }
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
{
return new InsertObjectProcedure
{
Entity = "RESULT",
Result = this
}.AddedBy(addedWho ?? "Rec.API");
}
}

View File

@@ -0,0 +1,25 @@
using MediatR;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
namespace ReC.Application.Results.Commands;
public record UpdateResultCommand : IUpdateProcedure<UpdateResultDto>
{
public long Id { get; set; }
public UpdateResultDto Data { get; set; } = null!;
}
public class UpdateResultProcedureHandler(ISender sender) : IRequestHandler<UpdateResultCommand, int>
{
public async Task<int> Handle(UpdateResultCommand request, CancellationToken cancel)
{
return await sender.Send(new UpdateObjectProcedure
{
Entity = "RESULT",
Id = request.Id,
Result = request.Data
}, cancel);
}
}

View File

@@ -1,21 +0,0 @@
using ReC.Application.Common.Procedures.UpdateProcedure;
namespace ReC.Application.Results.Commands;
public record UpdateResultProcedure : IUpdateProcedure
{
public long? ActionId { get; set; }
public short? StatusId { get; set; }
public string? Header { get; set; }
public string? Body { get; set; }
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "RESULT",
Id = id,
Result = this
}.ChangedBy(changedWho);
}
}

View File

@@ -0,0 +1,8 @@
namespace ReC.Domain.Constants;
public enum ResultType
{
Pre = 1,
Main,
Post
}

View File

@@ -1,6 +1,9 @@
namespace ReC.Domain.QueryOutput; using System.ComponentModel.DataAnnotations.Schema;
namespace ReC.Domain.QueryOutput;
public class BodyQueryResult public class BodyQueryResult
{ {
[Column("REQUEST_BODY")]
public string? RawBody { get; init; } public string? RawBody { get; init; }
} }

View File

@@ -1,6 +1,9 @@
namespace ReC.Domain.QueryOutput; using System.ComponentModel.DataAnnotations.Schema;
namespace ReC.Domain.QueryOutput;
public class HeaderQueryResult public class HeaderQueryResult
{ {
[Column("REQUEST_HEADER")]
public string? RawHeader { get; init; } public string? RawHeader { get; init; }
} }

View File

@@ -4,5 +4,6 @@ namespace ReC.Domain.QueryOutput;
public class InsertObjectResult public class InsertObjectResult
{ {
[Column("oGUID")]
public required long NewObjectId { get; set; } public required long NewObjectId { get; set; }
} }

View File

@@ -1,4 +1,5 @@
using ReC.Domain.Constants; using ReC.Domain.Constants;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
namespace ReC.Domain.Views; namespace ReC.Domain.Views;
@@ -8,39 +9,58 @@ public record ProfileView
{ {
public virtual IEnumerable<RecActionView>? Actions { get; init; } public virtual IEnumerable<RecActionView>? Actions { get; init; }
[Key]
[Column("PROFILE_GUID")]
public long Id { get; init; } public long Id { get; init; }
[Column("ACTIVE")]
public bool Active { get; init; } public bool Active { get; init; }
[Column("TYPE_ID")]
public ProfileType TypeId { get; init; } public ProfileType TypeId { get; init; }
[Column("TYPE")]
public string? Type { get; init; } public string? Type { get; init; }
[Column("MANDANTOR")]
public string? Mandantor { get; init; } public string? Mandantor { get; init; }
[Column("PROFILE_NAME")]
public string? ProfileName { get; init; } public string? ProfileName { get; init; }
[Column("DESCRIPTION")]
public string? Description { get; init; } public string? Description { get; init; }
[Column("LOG_LEVEL_ID")]
public byte LogLevelId { get; init; } public byte LogLevelId { get; init; }
[Column("LOG_LEVEL")]
public string? LogLevel { get; init; } public string? LogLevel { get; init; }
[Column("LANGUAGE_ID")]
public short LanguageId { get; init; } public short LanguageId { get; init; }
[Column("LANGUAGE")]
public string? Language { get; init; } public string? Language { get; init; }
[Column("ADDED_WHO")]
public string? AddedWho { get; init; } public string? AddedWho { get; init; }
[Column("ADDED_WHEN")]
public DateTime AddedWhen { get; init; } public DateTime AddedWhen { get; init; }
[Column("CHANGED_WHO")]
public string? ChangedWho { get; init; } public string? ChangedWho { get; init; }
[Column("CHANGED_WHEN")]
public DateTime? ChangedWhen { get; init; } public DateTime? ChangedWhen { get; init; }
[Column("FIRST_RUN")]
public DateTime? FirstRun { get; init; } public DateTime? FirstRun { get; init; }
[Column("LAST_RUN")]
public DateTime? LastRun { get; init; } public DateTime? LastRun { get; init; }
[Column("LAST_RESULT")]
public string? LastResult { get; init; } public string? LastResult { get; init; }
} }

View File

@@ -1,4 +1,5 @@
using ReC.Domain.Constants; using ReC.Domain.Constants;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
namespace ReC.Domain.Views; namespace ReC.Domain.Views;
@@ -16,72 +17,106 @@ public class RecActionView
{ {
public virtual IEnumerable<ResultView>? Results { get; set; } public virtual IEnumerable<ResultView>? Results { get; set; }
[Key]
[Column("ACTION_GUID")]
public required long Id { get; set; } public required long Id { get; set; }
[Column("PROFILE_ID")]
public long? ProfileId { get; set; } public long? ProfileId { get; set; }
[ForeignKey("ProfileId")] [ForeignKey("ProfileId")]
public ProfileView? Profile { get; set; } public ProfileView? Profile { get; set; }
[Column("PROFILE_NAME")]
public string? ProfileName { get; set; } public string? ProfileName { get; set; }
[Column("PROFILE_TYPE_ID")]
public ProfileType? ProfileType { get; set; } public ProfileType? ProfileType { get; set; }
[Column("SEQUENCE")]
public byte? Sequence { get; set; } public byte? Sequence { get; set; }
[Column("ENDPOINT_ID")]
public long? EndpointId { get; set; } public long? EndpointId { get; set; }
[Column("ENDPOINT_URI")]
public string? EndpointUri { get; set; } public string? EndpointUri { get; set; }
[Column("ENDPOINT_AUTH_ID")]
public long? EndpointAuthId { get; set; } public long? EndpointAuthId { get; set; }
[Column("ENDPOINT_AUTH_TYPE_ID")]
public EndpointAuthType? EndpointAuthType { get; set; } public EndpointAuthType? EndpointAuthType { get; set; }
[Column("ENDPOINT_AUTH_TYPE")]
public string? EndpointAuthTypeName { get; set; } public string? EndpointAuthTypeName { get; set; }
[Column("ENDPOINT_AUTH_API_KEY")]
public string? EndpointAuthApiKey { get; set; } public string? EndpointAuthApiKey { get; set; }
[Column("ENDPOINT_AUTH_API_VALUE")]
public string? EndpointAuthApiValue { get; set; } public string? EndpointAuthApiValue { get; set; }
[Column("ENDPOINT_AUTH_API_KEY_ADD_TO_ID")]
public ApiKeyLocation? EndpointAuthApiKeyAddTo { get; set; } public ApiKeyLocation? EndpointAuthApiKeyAddTo { get; set; }
[Column("ENDPOINT_AUTH_API_KEY_ADD_TO")]
public string? EndpointAuthApiKeyAddToName { get; set; } public string? EndpointAuthApiKeyAddToName { get; set; }
[Column("ENDPOINT_AUTH_TOKEN")]
public string? EndpointAuthToken { get; set; } public string? EndpointAuthToken { get; set; }
[Column("ENDPOINT_AUTH_USERNAME")]
public string? EndpointAuthUsername { get; set; } public string? EndpointAuthUsername { get; set; }
[Column("ENDPOINT_AUTH_PASSWORD")]
public string? EndpointAuthPassword { get; set; } public string? EndpointAuthPassword { get; set; }
[Column("ENDPOINT_AUTH_DOMAIN")]
public string? EndpointAuthDomain { get; set; } public string? EndpointAuthDomain { get; set; }
[Column("ENDPOINT_AUTH_WORKSTATION")]
public string? EndpointAuthWorkstation { get; set; } public string? EndpointAuthWorkstation { get; set; }
[Column("ENDPOINT_PARAMS_ID")]
public short? EndpointParamsId { get; set; } public short? EndpointParamsId { get; set; }
[Column("SQL_CONNECTION_ID")]
public short? SqlConnectionId { get; set; } public short? SqlConnectionId { get; set; }
[Column("SQL_CONNECTION_SERVER")]
public string? SqlConnectionServer { get; set; } public string? SqlConnectionServer { get; set; }
[Column("SQL_CONNECTION_DB")]
public string? SqlConnectionDb { get; set; } public string? SqlConnectionDb { get; set; }
[Column("SQL_CONNECTION_USERNAME")]
public string? SqlConnectionUsername { get; set; } public string? SqlConnectionUsername { get; set; }
[Column("SQL_CONNECTION_PASSWORD")]
public string? SqlConnectionPassword { get; set; } public string? SqlConnectionPassword { get; set; }
[Column("REST_TYPE_ID")]
public RestType? RestType { get; set; } public RestType? RestType { get; set; }
[Column("REST_TYPE")]
public string? RestTypeName { get; set; } public string? RestTypeName { get; set; }
[Column("PREPROCESSING_QUERY")]
public string? PreprocessingQuery { get; set; } public string? PreprocessingQuery { get; set; }
[Column("HEADER_QUERY")]
public string? HeaderQuery { get; set; } public string? HeaderQuery { get; set; }
[Column("BODY_QUERY")]
public string? BodyQuery { get; set; } public string? BodyQuery { get; set; }
[Column("POSTPROCESSING_QUERY")]
public string? PostprocessingQuery { get; set; } public string? PostprocessingQuery { get; set; }
[Column("ERROR_ACTION_ID")]
public ErrorAction? ErrorAction { get; set; } public ErrorAction? ErrorAction { get; set; }
[Column("ERROR_ACTION")]
public string? ErrorActionName { get; set; } public string? ErrorActionName { get; set; }
} }

View File

@@ -1,35 +1,62 @@
using System.ComponentModel.DataAnnotations.Schema; using ReC.Domain.Constants;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ReC.Domain.Views; namespace ReC.Domain.Views;
[Table("VWREC_RESULT", Schema = "dbo")] [Table("VWREC_RESULT", Schema = "dbo")]
public class ResultView public class ResultView
{ {
[Key]
[Column("RESULT_GUID")]
public long Id { get; set; } public long Id { get; set; }
[Column("ACTION_ID")]
public long? ActionId { get; set; } public long? ActionId { get; set; }
public RecActionView? Action { get; set; } public RecActionView? Action { get; set; }
[Column("PROFILE_ID")]
public long? ProfileId { get; set; } public long? ProfileId { get; set; }
public ProfileView? Profile { get; set; } public ProfileView? Profile { get; set; }
[Column("PROFILE_NAME")]
public string? ProfileName { get; set; } public string? ProfileName { get; set; }
[Column("STATUS_ID")]
public short? StatusCode { get; set; } public short? StatusCode { get; set; }
[Column("STATUS")]
public string? StatusName { get; set; } public string? StatusName { get; set; }
[Column("RESULT_TYPE_ID")]
public ResultType? Type { get; set; }
[Column("RESULT_TYPE")]
public string? TypeName { get; set; }
[Column("RESULT_HEADER")]
public string? Header { get; set; } public string? Header { get; set; }
[Column("RESULT_BODY")]
public string? Body { get; set; } public string? Body { get; set; }
[Column("RESULT_INFO")]
public string? Info { get; set; }
[Column("RESULT_ERROR")]
public string? Error { get; set; }
[Column("ADDED_WHO")]
public string? AddedWho { get; set; } public string? AddedWho { get; set; }
[Column("ADDED_WHEN")]
public DateTime? AddedWhen { get; set; } public DateTime? AddedWhen { get; set; }
[Column("CHANGED_WHO")]
public string? ChangedWho { get; set; } public string? ChangedWho { get; set; }
[Column("CHANGED_WHEN")]
public DateTime? ChangedWhen { get; set; } public DateTime? ChangedWhen { get; set; }
} }

View File

@@ -1,12 +0,0 @@
namespace ReC.Infrastructure.Exceptions;
public class DbModelConfigurationException : Exception
{
public DbModelConfigurationException(string message) : base(message)
{
}
public DbModelConfigurationException()
{
}
}

View File

@@ -1,23 +0,0 @@
using ReC.Infrastructure.Exceptions;
using ReC.Infrastructure.Options.Shared;
namespace ReC.Infrastructure.Options;
public record DbModelOptions
{
public Dictionary<string, EntityOptions> Entities { get; init; } = [];
public Dictionary<string, VirtualEntityOptions> VirtualEntities { get; init; } = [];
public void EnsureEntity<T>(bool isVirtual)
{
var entities = isVirtual
? VirtualEntities.ToDictionary(kvp => kvp.Key, kvp => kvp.Value as EntityBaseOptions)
: Entities.ToDictionary(kvp => kvp.Key, kvp => kvp.Value as EntityBaseOptions);
if(entities.TryGetValue(nameof(T), out var entityOptions))
entityOptions.EnsureProperties<T>();
else
throw new DbModelConfigurationException($"Entity options for type '{typeof(T).FullName}' not found.");
}
}

View File

@@ -1,33 +0,0 @@
using ReC.Domain.Attributes;
using ReC.Infrastructure.Exceptions;
namespace ReC.Infrastructure.Options.Shared;
public record EntityBaseOptions()
{
public Dictionary<string, string> ColumnMappings { get; init; } = [];
public IEnumerable<string> PropertyNames => ColumnMappings.Select(col => col.Key);
public IEnumerable<string> ColumnNames => ColumnMappings.Select(col => col.Value);
public void EnsureProperties(IEnumerable<string> propertyNames)
{
var missingProperties = propertyNames.Except(PropertyNames).ToList();
if (missingProperties.Count != 0)
throw new DbModelConfigurationException($"The following properties are not configured: {string.Join(", ", missingProperties)}");
}
public void EnsureProperties(params string[] propertyNames)
=> EnsureProperties(propertyNames.AsEnumerable());
public void EnsureProperties<T>()
{
var propertyNames = typeof(T)
.GetProperties()
.Where(prop => Attribute.IsDefined(prop, typeof(MustConfiguredAttribute)))
.Select(prop => prop.Name);
EnsureProperties(propertyNames);
}
}

View File

@@ -1,3 +0,0 @@
namespace ReC.Infrastructure.Options.Shared;
public record EntityOptions(TableOptions Table) : EntityBaseOptions;

View File

@@ -1,3 +0,0 @@
namespace ReC.Infrastructure.Options.Shared;
public record TableOptions(string Name, string? Schema = null);

View File

@@ -1,3 +0,0 @@
namespace ReC.Infrastructure.Options.Shared;
public record VirtualEntityOptions : EntityBaseOptions;

View File

@@ -21,7 +21,6 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
public DbSet<InsertObjectResult> RecResults { get; set; } public DbSet<InsertObjectResult> RecResults { get; set; }
#endregion DB Sets #endregion DB Sets
// TODO: Update to configure via appsettings.json
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
base.OnModelCreating(modelBuilder); base.OnModelCreating(modelBuilder);
@@ -29,41 +28,6 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
modelBuilder.Entity<RecActionView>(b => modelBuilder.Entity<RecActionView>(b =>
{ {
b.ToView("VWREC_ACTION", "dbo"); b.ToView("VWREC_ACTION", "dbo");
b.HasKey(e => e.Id);
b.Property(e => e.Id).HasColumnName("ACTION_GUID");
b.Property(e => e.ProfileId).HasColumnName("PROFILE_ID");
b.Property(e => e.ProfileName).HasColumnName("PROFILE_NAME");
b.Property(e => e.ProfileType).HasColumnName("PROFILE_TYPE_ID");
b.Property(e => e.Sequence).HasColumnName("SEQUENCE");
b.Property(e => e.EndpointId).HasColumnName("ENDPOINT_ID");
b.Property(e => e.EndpointUri).HasColumnName("ENDPOINT_URI");
b.Property(e => e.EndpointAuthId).HasColumnName("ENDPOINT_AUTH_ID");
b.Property(e => e.EndpointAuthType).HasColumnName("ENDPOINT_AUTH_TYPE_ID");
b.Property(e => e.EndpointAuthTypeName).HasColumnName("ENDPOINT_AUTH_TYPE");
b.Property(e => e.EndpointAuthApiKey).HasColumnName("ENDPOINT_AUTH_API_KEY");
b.Property(e => e.EndpointAuthApiValue).HasColumnName("ENDPOINT_AUTH_API_VALUE");
b.Property(e => e.EndpointAuthApiKeyAddTo).HasColumnName("ENDPOINT_AUTH_API_KEY_ADD_TO_ID");
b.Property(e => e.EndpointAuthApiKeyAddToName).HasColumnName("ENDPOINT_AUTH_API_KEY_ADD_TO");
b.Property(e => e.EndpointAuthToken).HasColumnName("ENDPOINT_AUTH_TOKEN");
b.Property(e => e.EndpointAuthUsername).HasColumnName("ENDPOINT_AUTH_USERNAME");
b.Property(e => e.EndpointAuthPassword).HasColumnName("ENDPOINT_AUTH_PASSWORD");
b.Property(e => e.EndpointAuthDomain).HasColumnName("ENDPOINT_AUTH_DOMAIN");
b.Property(e => e.EndpointAuthWorkstation).HasColumnName("ENDPOINT_AUTH_WORKSTATION");
b.Property(e => e.EndpointParamsId).HasColumnName("ENDPOINT_PARAMS_ID");
b.Property(e => e.SqlConnectionId).HasColumnName("SQL_CONNECTION_ID");
b.Property(e => e.SqlConnectionServer).HasColumnName("SQL_CONNECTION_SERVER");
b.Property(e => e.SqlConnectionDb).HasColumnName("SQL_CONNECTION_DB");
b.Property(e => e.SqlConnectionUsername).HasColumnName("SQL_CONNECTION_USERNAME");
b.Property(e => e.SqlConnectionPassword).HasColumnName("SQL_CONNECTION_PASSWORD");
b.Property(e => e.RestType).HasColumnName("REST_TYPE_ID");
b.Property(e => e.RestTypeName).HasColumnName("REST_TYPE");
b.Property(e => e.PreprocessingQuery).HasColumnName("PREPROCESSING_QUERY");
b.Property(e => e.HeaderQuery).HasColumnName("HEADER_QUERY");
b.Property(e => e.BodyQuery).HasColumnName("BODY_QUERY");
b.Property(e => e.PostprocessingQuery).HasColumnName("POSTPROCESSING_QUERY");
b.Property(e => e.ErrorAction).HasColumnName("ERROR_ACTION_ID");
b.Property(e => e.ErrorActionName).HasColumnName("ERROR_ACTION");
b.HasMany(e => e.Results) b.HasMany(e => e.Results)
.WithOne(r => r.Action) .WithOne(r => r.Action)
@@ -73,44 +37,11 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
modelBuilder.Entity<ProfileView>(b => modelBuilder.Entity<ProfileView>(b =>
{ {
b.ToView("VWREC_PROFILE", "dbo"); b.ToView("VWREC_PROFILE", "dbo");
b.HasKey(e => e.Id);
b.Property(e => e.Id).HasColumnName("PROFILE_GUID");
b.Property(e => e.Active).HasColumnName("ACTIVE");
b.Property(e => e.TypeId).HasColumnName("TYPE_ID");
b.Property(e => e.Type).HasColumnName("TYPE");
b.Property(e => e.Mandantor).HasColumnName("MANDANTOR");
b.Property(e => e.ProfileName).HasColumnName("PROFILE_NAME");
b.Property(e => e.Description).HasColumnName("DESCRIPTION");
b.Property(e => e.LogLevelId).HasColumnName("LOG_LEVEL_ID");
b.Property(e => e.LogLevel).HasColumnName("LOG_LEVEL");
b.Property(e => e.LanguageId).HasColumnName("LANGUAGE_ID");
b.Property(e => e.Language).HasColumnName("LANGUAGE");
b.Property(e => e.AddedWho).HasColumnName("ADDED_WHO");
b.Property(e => e.AddedWhen).HasColumnName("ADDED_WHEN");
b.Property(e => e.ChangedWho).HasColumnName("CHANGED_WHO");
b.Property(e => e.ChangedWhen).HasColumnName("CHANGED_WHEN");
b.Property(e => e.FirstRun).HasColumnName("FIRST_RUN");
b.Property(e => e.LastRun).HasColumnName("LAST_RUN");
b.Property(e => e.LastResult).HasColumnName("LAST_RESULT");
}); });
modelBuilder.Entity<ResultView>(b => modelBuilder.Entity<ResultView>(b =>
{ {
b.ToView("VWREC_RESULT", "dbo"); b.ToView("VWREC_RESULT", "dbo");
b.HasKey(e => e.Id);
b.Property(e => e.Id).HasColumnName("RESULT_GUID");
b.Property(e => e.ActionId).HasColumnName("ACTION_ID");
b.Property(e => e.ProfileId).HasColumnName("PROFILE_ID");
b.Property(e => e.ProfileName).HasColumnName("PROFILE_NAME");
b.Property(e => e.StatusCode).HasColumnName("STATUS_ID");
b.Property(e => e.StatusName).HasColumnName("STATUS");
b.Property(e => e.Header).HasColumnName("RESULT_HEADER");
b.Property(e => e.Body).HasColumnName("RESULT_BODY");
b.Property(e => e.AddedWho).HasColumnName("ADDED_WHO");
b.Property(e => e.AddedWhen).HasColumnName("ADDED_WHEN");
b.Property(e => e.ChangedWho).HasColumnName("CHANGED_WHO");
b.Property(e => e.ChangedWhen).HasColumnName("CHANGED_WHEN");
b.HasOne(r => r.Action) b.HasOne(r => r.Action)
.WithMany(a => a.Results) .WithMany(a => a.Results)
@@ -124,19 +55,16 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
modelBuilder.Entity<HeaderQueryResult>(b => modelBuilder.Entity<HeaderQueryResult>(b =>
{ {
b.HasNoKey(); b.HasNoKey();
b.Property(e => e.RawHeader).HasColumnName("REQUEST_HEADER");
}); });
modelBuilder.Entity<BodyQueryResult>(b => modelBuilder.Entity<BodyQueryResult>(b =>
{ {
b.HasNoKey(); b.HasNoKey();
b.Property(e => e.RawBody).HasColumnName("REQUEST_BODY");
}); });
modelBuilder.Entity<InsertObjectResult>(b => modelBuilder.Entity<InsertObjectResult>(b =>
{ {
b.HasNoKey(); b.HasNoKey();
b.Property(e => e.NewObjectId).HasColumnName("oGUID");
}); });
} }
} }

View File

@@ -23,12 +23,11 @@ public class EndpointAuthProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task InsertEndpointAuthProcedure_runs_via_mediator() public async Task InsertEndpointAuthProcedure_runs_via_mediator()
{ {
var procedure = new InsertEndpointAuthProcedure { Active = true, Description = "auth", TypeId = 1, ApiKey = "key", ApiValue = "value" }; var procedure = new InsertEndpointAuthCommand { Active = true, Description = "auth", TypeId = 1, ApiKey = "key", ApiValue = "value" };
var objectProc = procedure.ToObjectProcedure("ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.GreaterThan(0)); Assert.That(result, Is.GreaterThan(0));
} }
@@ -36,12 +35,11 @@ public class EndpointAuthProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task UpdateEndpointAuthProcedure_runs_via_mediator() public async Task UpdateEndpointAuthProcedure_runs_via_mediator()
{ {
var procedure = new UpdateEndpointAuthProcedure { Active = false, Description = "auth-update", TypeId = 2 }; var procedure = new UpdateEndpointAuthCommand { Data = { Active = false, Description = "auth-update", TypeId = 2 }, Id = 15 };
var objectProc = procedure.ToObjectProcedure(15, "ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }
@@ -49,12 +47,11 @@ public class EndpointAuthProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task DeleteEndpointAuthProcedure_runs_via_mediator() public async Task DeleteEndpointAuthProcedure_runs_via_mediator()
{ {
var procedure = new DeleteEndpointAuthProcedure { Start = 3, End = 4, Force = false }; var procedure = new DeleteEndpointAuthCommand { Start = 3, End = 4, Force = false };
var objectProc = procedure.ToObjectProcedure();
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }

View File

@@ -1,12 +1,6 @@
using System.Threading.Tasks;
using MediatR; using MediatR;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;
using ReC.Application.Common.Procedures.DeleteProcedure;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure;
using ReC.Application.EndpointParams.Commands; using ReC.Application.EndpointParams.Commands;
using ReC.Tests.Application;
namespace ReC.Tests.Application.EndpointParams; namespace ReC.Tests.Application.EndpointParams;
@@ -23,12 +17,11 @@ public class EndpointParamsProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task InsertEndpointParamsProcedure_runs_via_mediator() public async Task InsertEndpointParamsProcedure_runs_via_mediator()
{ {
var procedure = new InsertEndpointParamsProcedure { Active = true, Description = "param", GroupId = 1, Sequence = 1, Key = "k", Value = "v" }; var procedure = new InsertEndpointParamsCommand { Active = true, Description = "param", GroupId = 1, Sequence = 1, Key = "k", Value = "v" };
var objectProc = procedure.ToObjectProcedure("ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.GreaterThan(0)); Assert.That(result, Is.GreaterThan(0));
} }
@@ -36,12 +29,11 @@ public class EndpointParamsProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task UpdateEndpointParamsProcedure_runs_via_mediator() public async Task UpdateEndpointParamsProcedure_runs_via_mediator()
{ {
var procedure = new UpdateEndpointParamsProcedure { Active = false, Description = "param-update", GroupId = 2, Sequence = 2, Key = "k2", Value = "v2" }; var procedure = new UpdateEndpointParamsCommand { Data = { Active = false, Description = "param-update", GroupId = 2, Sequence = 2, Key = "k2", Value = "v2" }, Id = 25 };
var objectProc = procedure.ToObjectProcedure(25, "ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }
@@ -49,12 +41,11 @@ public class EndpointParamsProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task DeleteEndpointParamsProcedure_runs_via_mediator() public async Task DeleteEndpointParamsProcedure_runs_via_mediator()
{ {
var procedure = new DeleteEndpointParamsProcedure { Start = 5, End = 6, Force = true }; var procedure = new DeleteEndpointParamsCommand { Start = 5, End = 6, Force = true };
var objectProc = procedure.ToObjectProcedure();
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }

View File

@@ -23,12 +23,11 @@ public class EndpointProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task InsertEndpointProcedure_runs_via_mediator() public async Task InsertEndpointProcedure_runs_via_mediator()
{ {
var procedure = new InsertEndpointProcedure { Active = true, Description = "desc", Uri = "http://example" }; var procedure = new InsertEndpointCommand { Active = true, Description = "desc", Uri = "http://example" };
var objectProc = procedure.ToObjectProcedure("ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.GreaterThan(0)); Assert.That(result, Is.GreaterThan(0));
} }
@@ -36,12 +35,11 @@ public class EndpointProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task UpdateEndpointProcedure_runs_via_mediator() public async Task UpdateEndpointProcedure_runs_via_mediator()
{ {
var procedure = new UpdateEndpointProcedure { Active = false, Description = "updated", Uri = "http://updated" }; var procedure = new UpdateEndpointCommand { Data = { Active = false, Description = "updated", Uri = "http://updated" }, Id = 12 };
var objectProc = procedure.ToObjectProcedure(12, "ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }
@@ -49,12 +47,11 @@ public class EndpointProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task DeleteEndpointProcedure_runs_via_mediator() public async Task DeleteEndpointProcedure_runs_via_mediator()
{ {
var procedure = new DeleteEndpointProcedure { Start = 1, End = 2, Force = true }; var procedure = new DeleteEndpointCommand { Start = 1, End = 2, Force = true };
var objectProc = procedure.ToObjectProcedure();
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }

View File

@@ -23,11 +23,11 @@ public class ProcedureExecutionTests : RecApplicationTestBase
[Test] [Test]
public async Task ExecuteInsertProcedure_runs_with_addedWho() public async Task ExecuteInsertProcedure_runs_with_addedWho()
{ {
var procedure = new InsertProfileProcedure { Name = "name" }; var procedure = new InsertProfileCommand { Name = "name" };
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.ExecuteInsertProcedure(procedure, "ReC.Tests"); var result = await sender.Send(procedure);
Assert.That(result, Is.GreaterThan(0)); Assert.That(result, Is.GreaterThan(0));
} }
@@ -35,11 +35,11 @@ public class ProcedureExecutionTests : RecApplicationTestBase
[Test] [Test]
public async Task ExecuteUpdateProcedure_runs_with_changedWho() public async Task ExecuteUpdateProcedure_runs_with_changedWho()
{ {
var procedure = new UpdateProfileProcedure { Name = "updated" }; var procedure = new UpdateProfileCommand { Data = { Name = "updated" }, Id = 123 };
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.ExecuteUpdateProcedure(procedure, 123, "ReC.Tests"); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }
@@ -47,11 +47,11 @@ public class ProcedureExecutionTests : RecApplicationTestBase
[Test] [Test]
public async Task ExecuteDeleteProcedure_runs() public async Task ExecuteDeleteProcedure_runs()
{ {
var procedure = new DeleteProfileProcedure { Start = 1, End = 2, Force = true }; var procedure = new DeleteProfileCommand { Start = 1, End = 2, Force = true };
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.ExecuteDeleteProcedure(procedure); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }

View File

@@ -23,12 +23,11 @@ public class ProfileProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task InsertProfileProcedure_runs_via_mediator() public async Task InsertProfileProcedure_runs_via_mediator()
{ {
var procedure = new InsertProfileProcedure { Active = true, TypeId = 1, Name = "name", Mandantor = "man" }; var procedure = new InsertProfileCommand { Active = true, TypeId = 1, Name = "name", Mandantor = "man" };
var objectProc = procedure.ToObjectProcedure("ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.GreaterThan(0)); Assert.That(result, Is.GreaterThan(0));
} }
@@ -36,12 +35,11 @@ public class ProfileProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task UpdateProfileProcedure_runs_via_mediator() public async Task UpdateProfileProcedure_runs_via_mediator()
{ {
var procedure = new UpdateProfileProcedure { Active = false, TypeId = 2, Name = "updated", Mandantor = "man2" }; var procedure = new UpdateProfileCommand { Data = { Active = false, TypeId = 2, Name = "updated", Mandantor = "man2" }, Id = 45 };
var objectProc = procedure.ToObjectProcedure(45, "ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }
@@ -49,12 +47,11 @@ public class ProfileProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task DeleteProfileProcedure_runs_via_mediator() public async Task DeleteProfileProcedure_runs_via_mediator()
{ {
var procedure = new DeleteProfileProcedure { Start = 9, End = 10, Force = false }; var procedure = new DeleteProfileCommand { Start = 9, End = 10, Force = false };
var objectProc = procedure.ToObjectProcedure();
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }

View File

@@ -25,12 +25,11 @@ public class RecActionProcedureTests : RecApplicationTestBase
{ {
try try
{ {
var procedure = new InsertActionProcedure { ProfileId = 1, Active = true, Sequence = 1, EndpointId = 1 }; var procedure = new InsertActionCommand { ProfileId = 1, Active = true, Sequence = 1, EndpointId = 1 };
var objectProc = procedure.ToObjectProcedure("ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.GreaterThan(0), "Expected a valid ID greater than 0 to be returned from the insert operation."); Assert.That(result, Is.GreaterThan(0), "Expected a valid ID greater than 0 to be returned from the insert operation.");
} }
@@ -54,12 +53,11 @@ public class RecActionProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task UpdateActionProcedure_runs_via_mediator() public async Task UpdateActionProcedure_runs_via_mediator()
{ {
var procedure = new UpdateActionProcedure { ProfileId = 2, Active = false, Sequence = 2 }; var procedure = new UpdateActionCommand { Data = { ProfileId = 2, Active = false, Sequence = 2 }, Id = 35 };
var objectProc = procedure.ToObjectProcedure(35, "ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }
@@ -67,12 +65,11 @@ public class RecActionProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task DeleteActionProcedure_runs_via_mediator() public async Task DeleteActionProcedure_runs_via_mediator()
{ {
var procedure = new DeleteActionProcedure { Start = 7, End = 8, Force = true }; var procedure = new DeleteActionCommand { Start = 7, End = 8, Force = true };
var objectProc = procedure.ToObjectProcedure();
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }

View File

@@ -23,12 +23,11 @@ public class ResultProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task InsertResultProcedure_runs_via_mediator() public async Task InsertResultProcedure_runs_via_mediator()
{ {
var procedure = new InsertResultProcedure { ActionId = 1, StatusId = 200, Header = "h", Body = "b" }; var procedure = new InsertResultCommand { ActionId = 1, StatusId = 200, Header = "h", Body = "b", Type = Domain.Constants.ResultType.Main };
var objectProc = procedure.ToObjectProcedure("ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.GreaterThan(0)); Assert.That(result, Is.GreaterThan(0));
} }
@@ -36,12 +35,11 @@ public class ResultProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task UpdateResultProcedure_runs_via_mediator() public async Task UpdateResultProcedure_runs_via_mediator()
{ {
var procedure = new UpdateResultProcedure { ActionId = 2, StatusId = 500, Header = "h2", Body = "b2" }; var procedure = new UpdateResultCommand { Data = { ActionId = 2, StatusId = 500, Header = "h2", Body = "b2" }, Id = 55 };
var objectProc = procedure.ToObjectProcedure(55, "ReC.Tests");
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }
@@ -49,12 +47,11 @@ public class ResultProcedureTests : RecApplicationTestBase
[Test] [Test]
public async Task DeleteResultProcedure_runs_via_mediator() public async Task DeleteResultProcedure_runs_via_mediator()
{ {
var procedure = new DeleteResultProcedure { Start = 11, End = 12, Force = false }; var procedure = new DeleteResultCommand { Start = 11, End = 12, Force = false };
var objectProc = procedure.ToObjectProcedure();
var (sender, scope) = CreateScopedSender(); var (sender, scope) = CreateScopedSender();
using var _ = scope; using var _ = scope;
var result = await sender.Send(objectProc); var result = await sender.Send(procedure);
Assert.That(result, Is.Not.EqualTo(default(int))); Assert.That(result, Is.Not.EqualTo(default(int)));
} }