3 Commits

Author SHA1 Message Date
29bc0cf8b5 Relax RESULT validation to allow StatusId, Info, or Error
Previously, RESULT required a non-null StatusId. Now, validation passes if at least one of StatusId, Info, or Error is provided, making the requirements more flexible.
2026-03-27 09:46:43 +01:00
c8b264cef6 Improve null safety in InsertObjectProcedureValidator
Updated validation logic to use null-forgiving operators and added null checks for nested properties in When clauses. This ensures rules are only applied when parent objects are not null, preventing possible null reference errors and improving overall robustness.
2026-03-27 09:40:33 +01:00
078525d85d Refactor RecAction invoke endpoint to use profileId param
Changed the HTTP POST route to accept a profileId instead of a command object, updated XML documentation accordingly, and refactored the method to construct the command internally using the provided profileId before sending it to the mediator. This improves clarity and API usability.
2026-03-27 09:26:13 +01:00
2 changed files with 26 additions and 26 deletions

View File

@@ -13,14 +13,14 @@ public class RecActionController(IMediator mediator) : ControllerBase
/// <summary>
/// Invokes a batch of RecActions for a given profile.
/// </summary>
/// <param name="command">The command containing the profile ID.</param>
/// <param name="profileId">The identifier of the profile whose RecActions should be invoked.</param>
/// <param name="cancel">A token to cancel the operation.</param>
/// <returns>An HTTP 202 Accepted response indicating the process has been started.</returns>
[HttpPost("invoke/{command}")]
[HttpPost("invoke/{profileId}")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Invoke([FromRoute] InvokeBatchRecActionViewsCommand command, CancellationToken cancel)
public async Task<IActionResult> Invoke([FromRoute] long profileId, CancellationToken cancel)
{
await mediator.Send(command, cancel);
await mediator.Send(new InvokeBatchRecActionViewsCommand { ProfileId = profileId }, cancel);
return Accepted();
}

View File

@@ -14,59 +14,59 @@ public class InsertObjectProcedureValidator : AbstractValidator<InsertObjectProc
.WithMessage("ENTITY must be one of: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT.");
// ACTION validation
When(x => x.Entity == "ACTION", () =>
When(x => x.Action != null, () =>
{
RuleFor(x => x.Action.ProfileId)
RuleFor(x => x.Action!.ProfileId)
.NotNull()
.WithMessage("ACTION requires ActionProfileId (maps to @pACTION_PROFILE_ID).");
RuleFor(x => x.Action.EndpointId)
RuleFor(x => x.Action!.EndpointId)
.NotNull()
.WithMessage("ACTION requires ActionEndpointId (maps to @pACTION_ENDPOINT_ID).");
});
// ENDPOINT validation
When(x => x.Entity == "ENDPOINT", () =>
When(x => x.Endpoint != null, () =>
{
RuleFor(x => x.Endpoint.Uri)
RuleFor(x => x.Endpoint!.Uri)
.NotEmpty()
.WithMessage("ENDPOINT requires EndpointUri (maps to @pENDPOINT_URI).")
.MaximumLength(2000);
});
// PROFILE validation
When(x => x.Entity == "PROFILE", () =>
When(x => x.Profile != null, () =>
{
RuleFor(x => x.Profile.Name)
RuleFor(x => x.Profile!.Name)
.NotEmpty()
.WithMessage("PROFILE requires ProfileName (maps to @pPROFILE_NAME).")
.MaximumLength(50);
RuleFor(x => x.Profile.Mandantor)
RuleFor(x => x.Profile!.Mandantor)
.MaximumLength(50)
.When(x => x.Profile.Mandantor != null);
.When(x => x.Profile!.Mandantor != null);
RuleFor(x => x.Profile.Description)
RuleFor(x => x.Profile!.Description)
.MaximumLength(250)
.When(x => x.Profile.Description != null);
.When(x => x.Profile!.Description != null);
});
// RESULT validation
When(x => x.Entity == "RESULT", () =>
When(x => x.Result != null, () =>
{
RuleFor(x => x.Result.ActionId)
RuleFor(x => x.Result!.ActionId)
.NotNull()
.WithMessage("RESULT requires ResultActionId (maps to @pRESULT_ACTION_ID).");
RuleFor(x => x.Result.StatusId)
.NotNull()
.WithMessage("RESULT requires ResultStatusId (maps to @pRESULT_STATUS_ID).");
RuleFor(x => x.Result!)
.Must(r => r.StatusId != null || r.Info != null || r.Error != null)
.WithMessage("RESULT requires at least one of: StatusId, Info, or Error.");
});
// ENDPOINT_PARAMS validation
When(x => x.Entity == "ENDPOINT_PARAMS", () =>
When(x => x.EndpointParams != null, () =>
{
RuleFor(x => x.EndpointParams.GroupId)
RuleFor(x => x.EndpointParams!.GroupId)
.NotNull()
.WithMessage("ENDPOINT_PARAMS requires EndpointParamsGroupId (maps to @pENDPOINT_PARAMS_GROUP_ID).");
});
@@ -76,12 +76,12 @@ public class InsertObjectProcedureValidator : AbstractValidator<InsertObjectProc
.MaximumLength(50)
.When(x => x.AddedWho != null);
RuleFor(x => x.Endpoint.Description)
RuleFor(x => x.Endpoint!.Description)
.MaximumLength(250)
.When(x => x.Endpoint.Description != null);
.When(x => x.Endpoint is { Description: not null });
RuleFor(x => x.EndpointAuth.Description)
RuleFor(x => x.EndpointAuth!.Description)
.MaximumLength(250)
.When(x => x.EndpointAuth.Description != null);
.When(x => x.EndpointAuth is { Description: not null });
}
}