feat: Enhance error logging for PDF preview failures and SQL timeouts

- Implemented a new method `ShapeTableNames` to gather entity and navigation table names, ensuring no blanks or duplicates are included.
- Updated `FdsMfrClient` to handle cases where schema queries return no tables, logging appropriate warnings and preventing misleading errors.
- Introduced `PdfPreviewAsync` in `IntranetController` to manage PDF preview rendering, capturing detailed logs for failures and notifying users with readable error messages.
- Added comprehensive unit tests for error logging and table name shaping to ensure robustness and correctness.
- Documented decision to persist user action failures to the `fds__admin_logdebug` table, enhancing support diagnostics.
This commit is contained in:
Stefan
2026-09-16 16:35:04 +02:00
parent 38e0d55b09
commit fce83c528f
19 changed files with 609 additions and 56 deletions
+27 -7
View File
@@ -92,21 +92,41 @@ public class FdsMfrClient : IDisposable
foreach (DataRow nprw in dset.Tables("navigation_properties").Rows)
NavProperties[nprw.nz("name").ToLower()] = nprw.toStringDictionary();
var sqlList = new List<string> { NewDatatableSql(EntityTableName) };
var tableNames = new List<string> { EntityTableName };
foreach (DataRow ttrw in dset.Tables("tables").Rows)
// When mfr__getSchema itself failed (deadlock victim / timeout) there is no table name
// to build the TOP(0) shape queries from. Running them anyway produced a second, misleading
// "FROM [dbo].[]" error per sync and hid the real cause; the caller sees IsValid=false.
var shapeTables = ShapeTableNames(EntityTableName, dset.Tables("tables").Rows);
if (shapeTables.Length == 0)
{
sqlList.Add(NewDatatableSql(ttrw.nz("tablename")));
tableNames.Add(ttrw.nz("tablename"));
logger?.LogWarning("DatabaseSchema for {Entity}: schema query returned no entity table (exception={Exception}); skipping table-shape load",
ThisEntityName, dset.Exception);
_tableSet = new DataSet();
return;
}
_tableSet = Task.Run(async () => await getSQLDataSet_async(
string.Join(Environment.NewLine, sqlList),
string.Join(Environment.NewLine, shapeTables.Select(NewDatatableSql)),
FdsShared.FDSConnectionString(),
tablenames: tableNames.ToArray(),
tablenames: shapeTables,
options: new FdsSqlOptions(logger: logger))).Result.DataSet;
}
/// <summary>
/// Entity table plus its navigation tables, without blanks: the list of tables whose
/// (empty) shape is loaded. Empty when the entity table itself is unknown.
/// </summary>
internal static string[] ShapeTableNames(string entityTableName, DataRowCollection navTables)
{
if (string.IsNullOrWhiteSpace(entityTableName)) return Array.Empty<string>();
var names = new List<string> { entityTableName };
foreach (DataRow row in navTables)
{
string tbl = row.nz("tablename");
if (!string.IsNullOrWhiteSpace(tbl) && !names.Contains(tbl)) names.Add(tbl);
}
return names.ToArray();
}
public DataSet TgtDataset(string setId)
{
var dset = new DataSet();
+6
View File
@@ -16,6 +16,12 @@
<member name="F:fds.FdsMfr.InvoiceFileDownloadConcurrency">
<summary>Max parallel invoice-file downloads (independent per file).</summary>
</member>
<member name="M:fds.FdsMfrClient.DatabaseSchema.ShapeTableNames(System.String,System.Data.DataRowCollection)">
<summary>
Entity table plus its navigation tables, without blanks: the list of tables whose
(empty) shape is loaded. Empty when the entity table itself is unknown.
</summary>
</member>
<member name="T:fds.FdsConfig">
<summary>
Holds the application <see cref="T:Microsoft.Extensions.Configuration.IConfiguration"/> supplied by the host (the Fuchs web app).