https://github.com/tomashubelbauer/asp-conditional-validations
Shared conditional validations approach for ASP .NET Core
https://github.com/tomashubelbauer/asp-conditional-validations
asp asp-net asp-net-core fluent-validations form-validation validation validations validator
Last synced: 5 months ago
JSON representation
Shared conditional validations approach for ASP .NET Core
- Host: GitHub
- URL: https://github.com/tomashubelbauer/asp-conditional-validations
- Owner: TomasHubelbauer
- Created: 2019-12-11T09:56:13.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2022-04-14T19:35:02.000Z (about 4 years ago)
- Last Synced: 2025-06-01T16:42:48.333Z (about 1 year ago)
- Topics: asp, asp-net, asp-net-core, fluent-validations, form-validation, validation, validations, validator
- Language: HTML
- Homepage:
- Size: 682 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# ASP .NET Core Conditional Validations
[**WEB**](https://tomashubelbauer.github.io/asp-conditional-validations)
Have custom `Required` attribute, which uses the validation context to decide
whether to apply itself or not - this is the server side validation.
The attribute would also have a property, which would be a JavaScript expression
for the client side and on the client side, the form elements which are created
and have their validation attributes set by ASP .NET Core would also be
decorated and there would be a hook which would run the JavaScript expression so
that they can also conditionally disable themselves based on the same rules.
A more systematic approach to this would be to not duplicate the expression,
once for the attribute `IsValid` override in C# and then for the client as the
JavaScript expression property which gets passed to the client, but is semantically
equivalent and instead have a DSL which generates the `IsValid` override logic as
well as the JavaScript expression for the client.
In case of the above DSL, instead of using attributes, Fluent Validation could
also be used and its rules configured from the declarative shared object and the
same object could be serialized for the client and the same object could be used
to generate the validation rules for jQuery validator or similar.
This way the validation rules would be only in once place and would stay in sync
across the backend and the frontend, enabling for conditional attributes based on
complex logic.
Whether to keep using data annotation attributes or Fluent Validations and to use
a plain JavaScript expression, jQuery validation, Kendo validator etc. on the client
would be a matter of choice as a "DSL backend" implementation.
## Example
Model:
```cs
class Model
{
[Required]
string Title { get; set; }
[Required]
string Category { get; set; }
[RequiredIfCategory("category1")]
string Category1Description { get; set; }
[RequiredIfCategory("category2")]
string Category2Description { get; set; }
}
```
This is using the data annotation attributes. `RequiredIfCategory` would be a custom
attribute with custom `IsValid` logic which would use the validation context from the
2nd argument to access the `Category` field on the model and either apply self or not
based on the field value.
```cs
class RequiredIfCategoryAttribute: RequiredAttribute
{
public RequiredIfCategoryAttribute(string category)
{
}
IsValid(object model, ValidationContext validationContext)
{
if (model.Category == _category) {
// Required
}
else {
// Not required
}
}
}
```
https://stackoverflow.com/a/16100455/2715716
This takes care of the backend, but on the frontend, the form element would still have
a required HTML attribute on itself, because this attribute still derives from `Required`
so that the ASP .NET Core validations framework would most likely still print that HTML
attribute since this custom attribute is based on the `Required` one.
To solve the client side, we would need to distinguish form elements which have been
marked with the required attribute based on the `Required` framework attribute or our
custom attribute.
If we could do that, we could run a JavaScript expression, which would find these
fields marked by the custom attribute and use the same logic which the attribute
implements on the backend side to do the same logic on the client side, resulting in
semantically equivalent validations on the server and on the client.
Of course this would mean duplicating the validation logic in C# and JS, so ideally,
there could be a DSL or a declarative validation ruleset object, which would be
executed by a generalized validator on both the server and the client.
This way, instead of the attribute implementing the C# logic and also accepting the
semantically equivalent JS expression, it would just be a generic custom attribute
accepting this DSL ruleset and deriving the server logic from it as well as marking
the form element on the client so that a geenralized client side logic could go through
these form elements and based on the same DSL ruleset, execute a JavaScript equivalent
of those checks.
Instead of using a custom attribute, then, a custom Fluent Validations chain could be
derived from the DSL instead and same on the client for the various client side
validation libraries.
https://fluentvalidation.net/start
https://github.com/JeremySkinner/FluentValidation#example
https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation
## Running
`dotnet run` or `dotnet watch run`
## To-Do
### Make `JobTitle` on `DemoModel` required if `IsEmployed` is true
### Get client side validations to run with the out of the box functionality
https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms
### Set up the required attribute on the server to use the validation context
Apply itself or not depending on `IsEmployed`.
### Generate the client side validations based on the generalized declarative model
### Figure out how to distinguish form components marked by ASP .NET and custom attribute
See above.