Skip to content

Project model-state errors into view models

Translate ASP.NET model-state validation errors into JSON-friendly, grid-row-correlated view models. Trigger: Controller action returning validation results, typically as JSON.

Field Value
Operation ID OP-16
Trigger Controller action returning validation results, typically as JSON
Inputs ModelStateDictionary, optional grid property and row-id expressions
Outputs ErrorViewModel[]
Primary components ModelStateExtensions.GetErrors overload family (GetErrors(ModelStateDictionary), GetErrors<TGridRow, TProperty>(ModelStateDictionary, Expression, Expression), GetErrors<TGridRow, TProperty>(ModelStateDictionary, params GridErrorArguments<TGridRow, TProperty>[]))
Entry point src/Web.Mvc/Extensions/ModelStateExtensions.cs

Steps

  1. GetErrors() (no arguments) uses a grid-row-id selector that always returns "", disabling grid correlation.
  2. The grid overloads build GridErrorArguments from lambda expressions, capturing the grid property name and row-id property name through ExpressionHelper.GetExpressionText.
  3. For each model-state key, the gridRowKey selector picks the first translator whose GridName prefixes the key and whose key does not contain .Added[, .Deleted[, or .Updated[ — pending-change collections are excluded from grid error correlation (BR-34).
  4. GridRowKey normalizes the key: truncate at the last ]; when the key already targets the view-model path ({grid}.Rows[) use it directly if it ends with the row-id name, otherwise append .{rowIdName}; when it targets the domain-model path, insert .Rows after the grid name before applying the same rule (BR-35).
  5. GridRowId resolves the normalized key back through ModelState and reads its AttemptedValue as the row identifier, or "" when no grid key applies.
  6. Emit one ErrorViewModel per model-state entry that has errors, with Key having . replaced by _ for DOM friendliness, Values set to all error messages, and GridRowId set to the resolved row id (BR-36).
  7. LoadValidationErrors(ModelStateDictionary, IValidationResult) is the inbound counterpart: it adds one model error per result.Errors entry using PropertyName and ErrorMessage.

Process flow

The following diagram visualizes this operation's control flow.

flowchart TD
    Start([Controller returns validation result])
    Args[Build GridErrorArguments from lambdas]
    Key[Select grid translator per model-state key]
    Norm[Normalize key via GridRowKey]
    RowId[Resolve GridRowId from ModelState]
    Emit[Emit ErrorViewModel array]
    EndOk([Return ErrorViewModel[]])
    Start --> Args
    Args --> Key
    Key --> Norm
    Norm --> RowId
    RowId --> Emit
    Emit --> EndOk

Failure and edge-case behavior

  • No unexpected failure paths beyond argument-guard exceptions and delegated dependency behavior were identified for this operation.

Sources

  • src/Web.Mvc/Extensions/ModelStateExtensions.cs