-
Notifications
You must be signed in to change notification settings - Fork 24
Implement new .NET8 specific attributes to entry-format validation #516
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
98622d8
08e9b6a
fada832
de352db
7fc15fa
9a1e61d
a675a5a
5a9be62
3a19f4c
3154cc6
cb1bc96
245a0bf
e0883d1
6a9b52b
2818113
9d3852f
00c588d
d644bc8
18b3077
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,8 +18,8 @@ | |
| <!-- Package versions for package references across all projects --> | ||
| <ItemGroup> | ||
| <!--3rd party dependencies--> | ||
| <PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.8.0" /> | ||
| <PackageReference Update="Moq" Version="4.20.69" /> | ||
| <PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.*" /> | ||
| <PackageReference Update="Moq" Version="4.*" /> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would not use a generic version here. Make it explict. |
||
| <PackageReference Update="NUnit" Version="3.14.0" /> | ||
| <PackageReference Update="NUnit3TestAdapter" Version="4.5.0" /> | ||
| <PackageReference Update="coverlet.collector" Version="6.0.0" > | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 8.4.0 | ||
| 10.0.0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,33 +54,109 @@ The recursive `SubEntries` structure represents properties of a `EntryValueType. | |
| Example class: | ||
|
|
||
| ````cs | ||
| public class Root | ||
| public class PackagingResource | ||
1nf0rmagician marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Root sounds better than this |
||
| { | ||
| [DisplayName("Bob")] | ||
| public Foo Blah { get; set; } | ||
| [EntrySerialize] | ||
| [isRequiered] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isnt it |
||
| public Product Product_1 { get; set; } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No underscores in property-names |
||
|
|
||
| [EntrySerialize] | ||
| [DisplayName("Material"), DefaultValue("material1")] | ||
| public string MaterialType { get; set; } | ||
| } | ||
| public class Foo | ||
|
|
||
| public class Product | ||
| { | ||
| public int ValueA { get; set; } | ||
| [EntrySerialize] | ||
| [isRequiered, Length(7,8)] | ||
| public int ProductID { get; set; } | ||
|
|
||
| [DefaultValue("Hello")] | ||
| public string ValueB { get; set; } | ||
| [EntrySerialize] | ||
| [DisplayName("Name"), MaxLength(10)] | ||
| public string ProductName { get; set; } | ||
| } | ||
| ```` | ||
|
|
||
| The root object as a entry tree: | ||
|
|
||
| ````sh | ||
| Entry | ||
| - Key { Identifier = "Blah", Name = "Bob" } | ||
| - Value { Current = "Foo" } | ||
| - SubEntries | ||
| -- Entry-A | ||
| --- Key { Identifier = "ValueA", Name = "ValueA" } | ||
| --- Value { Current = "10" } | ||
| -- Entry-B | ||
| --- Key { Identifier = "ValueB", Name = "ValueB" } | ||
| --- Value { Current = "SomeString", Default = "Hello" } | ||
| The PackagingResource object as a serialized entry tree: | ||
| ````JSON | ||
| { | ||
| "identifier": "Product1", | ||
| "displayName": "Product1", | ||
| "description": null, | ||
| "value": { | ||
| "type": "Product", | ||
| "unitType": null, | ||
| "current": "", | ||
| "default": null, | ||
| "possible": null, | ||
| "isReadOnly": false | ||
| }, | ||
| "validation": { | ||
| "isRequired": true, | ||
| }, | ||
| "subEntries": [ | ||
| { | ||
| "identifier": "ProductID", | ||
| "displayName": "ProductID", | ||
| "description": null, | ||
| "value": { | ||
| "type": "int", | ||
| "unitType": null, | ||
| "current": "", | ||
| "default": null, | ||
| "possible": null, | ||
| "isReadOnly": false | ||
| }, | ||
| "validation": { | ||
| "isRequired": true, | ||
| "minimum": 7, | ||
| "maximum": 8 | ||
| }, | ||
| "subEntries": [], | ||
| "prototypes": [] | ||
| }, | ||
| { | ||
| "identifier": "ProductName", | ||
| "displayName": "Name", | ||
| "description": null, | ||
| "value": { | ||
| "type": "string", | ||
| "unitType": null, | ||
| "current": "", | ||
| "default": null, | ||
| "possible": null, | ||
| "isReadOnly": false | ||
| }, | ||
| "validation": { | ||
| "isRequired": true | ||
| "maximum": 10, | ||
| }, | ||
| "subEntries": [], | ||
| "prototypes": [] | ||
|
|
||
| } | ||
| ], | ||
| "prototypes": [] | ||
|
|
||
| }, | ||
| { | ||
| "identifier": "MaterialType", | ||
| "displayName": "Marterial", | ||
| "description": null, | ||
| "value": { | ||
| "type": "String", | ||
| "unitType": null, | ||
| "current": null, | ||
| "default": "material1", | ||
| "possible": null, | ||
| "isReadOnly": false | ||
| }, | ||
| "validation": { | ||
| }, | ||
| "subEntries": [], | ||
| "prototypes": [] | ||
|
|
||
| } | ||
| ```` | ||
|
|
||
| ## Prototypes | ||
|
|
||
1nf0rmagician marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,13 @@ | ||
| /* | ||
| * Copyright (c) 2020, Phoenix Contact GmbH & Co. KG | ||
| * Licensed under the Apache License, Version 2.0 | ||
| */ | ||
|
|
||
| export default class EntryValidation { | ||
| public minimum: number; | ||
| public maximum: number; | ||
| public regex: string; | ||
| public isRequired: boolean; | ||
| public isPassword: boolean; | ||
| } | ||
| /* | ||
| * Copyright (c) 2020, Phoenix Contact GmbH & Co. KG | ||
| * Licensed under the Apache License, Version 2.0 | ||
| */ | ||
|
|
||
| export default class EntryValidation { | ||
| public minimum: number; | ||
| public maximum: number; | ||
| public regex: string; | ||
| public isRequired: boolean; | ||
| public isPassword: boolean; | ||
| public deniedValue: string[]; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know why this is not plural here? |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ | |
| using System.IO; | ||
| using System.Linq; | ||
| using System.Reflection; | ||
| using System.Runtime.InteropServices; | ||
| using System.Threading; | ||
| using Moryx.Configuration; | ||
| using Moryx.Tools; | ||
|
|
@@ -73,6 +74,15 @@ public virtual EntryPrototype[] Prototypes(Type memberType, ICustomAttributeProv | |
| /// <see cref="ICustomSerialization"/> | ||
| public virtual string[] PossibleValues(Type memberType, ICustomAttributeProvider attributeProvider) | ||
| { | ||
| #if NET8_0 | ||
| var validationAttribute = attributeProvider.GetCustomAttribute<AllowedValuesAttribute>(); | ||
| if (validationAttribute != null) | ||
| { | ||
| var allowedValues = validationAttribute.Values.Select(o => o.ToString()); | ||
| return allowedValues?.Distinct().ToArray(); | ||
| } | ||
| #endif | ||
|
|
||
| // Element type for collections | ||
| var isCollection = EntryConvert.IsCollection(memberType); | ||
| if (isCollection) | ||
|
|
@@ -103,30 +113,47 @@ public virtual EntryValidation CreateValidation(Type memberType, ICustomAttribut | |
| // Iterate over attributes reading all validation rules | ||
| foreach (var attribute in validationAttributes) | ||
| { | ||
| if (attribute is MinLengthAttribute minAttribute) | ||
| { | ||
| validation.Minimum = minAttribute.Length; | ||
| } | ||
| else if (attribute is MaxLengthAttribute maxAttribute) | ||
| { | ||
| validation.Maximum = maxAttribute.Length; | ||
| } | ||
| else if (attribute is RangeAttribute rangeAttribute) | ||
| { | ||
| validation.Minimum = Convert.ToDouble(rangeAttribute.Minimum); | ||
| validation.Maximum = Convert.ToDouble(rangeAttribute.Maximum); | ||
| } | ||
| else if (attribute is RegularExpressionAttribute regexAttribute) | ||
| validation.Regex = regexAttribute.Pattern; | ||
| else if (attribute is StringLengthAttribute strLength) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Am I missing something or are the |
||
| switch (attribute) | ||
| { | ||
| validation.Minimum = strLength.MinimumLength; | ||
| validation.Maximum = strLength.MaximumLength; | ||
| case MinLengthAttribute minAttribute: | ||
| validation.Minimum = minAttribute.Length; | ||
| break; | ||
|
|
||
| case MaxLengthAttribute maxAttribute: | ||
| validation.Maximum = maxAttribute.Length; | ||
| break; | ||
|
|
||
| case RangeAttribute rangeAttribute: | ||
| validation.Minimum = Convert.ToDouble(rangeAttribute.Minimum); | ||
| validation.Maximum = Convert.ToDouble(rangeAttribute.Maximum); | ||
| break; | ||
|
|
||
| case RequiredAttribute requiredAttribute: | ||
| validation.IsRequired = true; | ||
| break; | ||
|
|
||
| case RegularExpressionAttribute regexAttribute: | ||
| validation.Regex = regexAttribute.Pattern; | ||
| break; | ||
|
|
||
| case StringLengthAttribute strLength: | ||
| validation.Minimum = strLength.MinimumLength; | ||
| validation.Maximum = strLength.MaximumLength; | ||
| break; | ||
|
|
||
| #if NET8_0 | ||
| case DeniedValuesAttribute deniedAttribute: | ||
| object[] denied = deniedAttribute.Values; | ||
| validation.DeniedValues = Array.ConvertAll(denied, item => item.ToString()); | ||
| break; | ||
|
|
||
| case LengthAttribute lengthAttribute: | ||
| validation.Minimum = lengthAttribute.MinimumLength; | ||
| validation.Maximum = lengthAttribute.MaximumLength; | ||
| break; | ||
| #endif | ||
| } | ||
| else if (attribute is RequiredAttribute) | ||
| validation.IsRequired = true; | ||
| } | ||
|
|
||
| return validation; | ||
| } | ||
|
|
||
|
|
@@ -221,7 +248,7 @@ public virtual object ConvertValue(Type memberType, ICustomAttributeProvider att | |
| return CollectionBuilder(memberType, currentValue, mappedEntry); | ||
| default: | ||
| var value = mappedEntry.Value.Current; | ||
| if (value is null) | ||
| if (value is null) | ||
| return null; | ||
|
|
||
| try | ||
|
|
@@ -251,9 +278,6 @@ public EntryUnitType GetUnitTypeByAttributes(ICustomAttributeProvider property) | |
| { | ||
| var unitType = EntryUnitType.None; | ||
|
|
||
| if (HasFlagsAttribute(property)) | ||
| unitType = EntryUnitType.Flags; | ||
|
|
||
| var passwordAttr = property.GetCustomAttribute<PasswordAttribute>(); | ||
| if (passwordAttr != null) | ||
| unitType = EntryUnitType.Password; | ||
|
|
@@ -321,17 +345,5 @@ protected static object CollectionBuilder(Type collectionType, object currentVal | |
| // Other collections are not supported | ||
| return null; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Checks if the given property is an enum and has the <see cref="System.FlagsAttribute"/>. | ||
| /// </summary> | ||
| /// <param name="property">The property to inspect for attributes.</param> | ||
| /// <returns>True if the property has the Flags attribute; otherwise, false.</returns> | ||
| private bool HasFlagsAttribute(ICustomAttributeProvider property) | ||
| { | ||
| return property is PropertyInfo propertyInfo && | ||
| propertyInfo.PropertyType.IsEnum && | ||
| propertyInfo.PropertyType.GetCustomAttributes(typeof(System.FlagsAttribute), false).Any(); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here - i would use an explict version here. In the past there were a lot of changes between the SDKs, also in minors.