Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/AuditLogCommands.cs
T
Joseph Doherty 09108018f1 fix(management): audit-config query returned {} for every filter — project the repo ValueTuple into a named result record
Deferred-work register row 46. HandleQueryAuditLog returned ICentralUiRepository's
(IReadOnlyList<AuditLogEntry> Entries, int TotalCount) ValueTuple straight to
ManagementActor.SerializeResult. System.Text.Json writes properties only, and a
ValueTuple exposes Item1/Item2 as public FIELDS, so the whole payload serialized to
the literal "{}" — the CLI faithfully printed an empty object no matter how many
AuditLogEntries rows matched, with no error anywhere in the stack.

Fixed at the handler (the layer that leaks the tuple), not the CLI: new Commons record
AuditLogQueryResult(Entries, TotalCount), mirroring the SecuredWriteListResult shape
already used by the other paged management query.

Also guards the whole class of bug: SerializeResult now throws on any ITuple result,
so the next handler that returns a tuple fails loudly instead of silently emitting {}.

Tests (fail-before verified — the query test asserted exactly "{}"):
- QueryAuditLogCommand_ReturnsEntriesAndTotalCount
- SerializeResult_TupleResult_ThrowsInsteadOfEmittingEmptyObject
- SerializeResult_AuditLogQueryResult_EmitsEntriesAndTotalCount

Docs: Component-CLI.md + CLI README document the response shape and why it is a record.
2026-08-15 11:38:28 -04:00

26 lines
1.3 KiB
C#

using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
public record QueryAuditLogCommand(
string? User = null, string? EntityType = null, string? Action = null,
DateTimeOffset? From = null, DateTimeOffset? To = null,
int Page = 1, int PageSize = 50);
/// <summary>
/// Result wrapper for <see cref="QueryAuditLogCommand"/>.
/// </summary>
/// <remarks>
/// This record exists specifically so the handler does not return the repository's
/// <c>(IReadOnlyList&lt;AuditLogEntry&gt; Entries, int TotalCount)</c> ValueTuple directly.
/// A ValueTuple exposes <c>Item1</c>/<c>Item2</c> as public <em>fields</em>, and
/// <see cref="System.Text.Json"/> serializes only properties unless
/// <c>JsonSerializerOptions.IncludeFields</c> is set — so a tuple result serialized to
/// the literal string <c>{}</c> and every <c>audit-config query</c> looked empty no
/// matter how many rows the query matched (deferred-work register row 46). Mirrors the
/// <c>SecuredWriteListResult</c> shape used by the other paged management query.
/// </remarks>
/// <param name="Entries">The page of configuration-change audit entries.</param>
/// <param name="TotalCount">Total number of rows matching the filters (unpaged).</param>
public record AuditLogQueryResult(IReadOnlyList<AuditLogEntry> Entries, int TotalCount);