AutoCorrect Event
Summary
The AutoCorrect event automatically transforms or normalizes a property value before validation occurs. Use it for formatting rules such as uppercasing codes, trimming whitespace, or rounding numbers to the correct precision.
When does it fire?
AutoCorrect fires during the set pipeline, after the read-only check and before validation:
Set property → ReadOnly check → AutoCorrect → Validate → Dirty dependents → Changed
Data type–level AutoCorrect runs first, then property-level AutoCorrect.
Syntax
Property-level syntax:
product.Sku.AutoCorrect()
.Transform(value => value?.ToUpperInvariant());
Entity-level syntax:
product.AutoCorrect(p => p.Sku)
.Transform(value => value?.ToUpperInvariant());
Fluent API
| Step | Method | Description |
|---|---|---|
| Required | .Transform(expression) |
The function that transforms and returns the corrected value |
Transform overloads
| Signature | Description |
|---|---|
.Transform(value => newValue) |
Transform the value only |
.Transform((value, args) => newValue) |
Transform with access to the entity and services via args |
Scenarios
1. Uppercasing a product SKU
Ensure all product SKUs are stored in uppercase regardless of how the user types them.
[Logic]
public class ProductBL(Product.Logic product)
{
[RegisterLogic]
public void AutoCorrectSku()
{
product.AutoCorrect(p => p.Sku)
.Transform(sku => sku?.ToUpperInvariant());
}
}
2. Rounding a currency value to the correct precision
Round the product cost to the configured number of decimal places.
[Logic]
public class ProductBL(Product.Logic product)
{
[RegisterLogic]
public void AutoCorrectCost()
{
product.AutoCorrect(p => p.Cost)
.Transform((cost, args) =>
Math.Round(cost, args.Entity.UnitPriceDecimals, MidpointRounding.AwayFromZero));
}
}
3. Auto-incrementing a duplicate document number
If a document number already exists, automatically append a suffix to make it unique.
[Logic]
public class SalesOrderBL(SalesOrder.Logic salesOrder)
{
[RegisterLogic]
public void AutoCorrectDocNumber()
{
salesOrder.AutoCorrect(o => o.DocNumber)
.Transform((number, args) =>
{
string original = number;
int suffix = 1;
while (args.GetEntities<SalesOrder>()
.Any(o => o.DocNumber == number && o.Guid != args.Entity.Guid))
{
number = $"{original}-{suffix}";
suffix++;
}
return number;
});
}
}
4. Trimming whitespace from a customer ID
Customer IDs should not have leading or trailing whitespace.
[Logic]
public class CustomerBL(Customer.Logic customer)
{
[RegisterLogic]
public void AutoCorrectId()
{
customer.AutoCorrect(c => c.Id)
.Transform(id => id?.Trim());
}
}
5. Normalizing a phone number
Strip non-digit characters so phone numbers are stored in a consistent format.
[Logic]
public class ContactBL(Contact.Logic contact)
{
[RegisterLogic]
public void AutoCorrectPhone()
{
contact.AutoCorrect(c => c.Phone)
.Transform(phone =>
{
if (string.IsNullOrEmpty(phone)) return phone;
return new string(phone.Where(char.IsDigit).ToArray());
});
}
}
AutoCorrect vs. Validate
| AutoCorrect | Validate | |
|---|---|---|
| Purpose | Fix the value silently | Reject invalid values with an error |
| When | Before validation | After auto-correct |
| Result | Returns a transformed value | Returns accept/reject with a message |
| User sees | The corrected value | An error message |
Notes
- AutoCorrect should never reject a value — it only transforms. Use Validate for rejection.
- Data type–level AutoCorrect (defined on custom data types) runs before property-level AutoCorrect.
- AutoCorrect should be idempotent — running it twice on the same value should produce the same result.