Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -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.*" />
Copy link
Member

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.

<PackageReference Update="Moq" Version="4.*" />
Copy link
Member

Choose a reason for hiding this comment

The 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" >
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.4.0
10.0.0
116 changes: 96 additions & 20 deletions docs/articles/Core/Serialization/EntryFormat.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,33 +54,109 @@ The recursive `SubEntries` structure represents properties of a `EntryValueType.
Example class:

````cs
public class Root
public class PackagingResource
Copy link
Member

Choose a reason for hiding this comment

The 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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isnt it RequiredAttribute?

public Product Product_1 { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The 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
Expand Down
25 changes: 13 additions & 12 deletions src/Moryx.CommandCenter.Web/src/modules/models/EntryValidation.ts
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[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know why this is not plural here? deniedValues

}
15 changes: 9 additions & 6 deletions src/Moryx/Configuration/PossibleValuesSerialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using Moryx.Communication.Endpoints;
using Moryx.Container;
using Moryx.Serialization;
using Moryx.Tools;
using Newtonsoft.Json.Linq;

namespace Moryx.Configuration
{
Expand Down Expand Up @@ -65,21 +68,21 @@ public override EntryPrototype[] Prototypes(Type memberType, ICustomAttributePro
list.Add(new EntryPrototype(value, prototype));
}
return list.ToArray();
}

}
/// <see cref="T:Moryx.Serialization.ICustomSerialization"/>
public override string[] PossibleValues(Type memberType, ICustomAttributeProvider attributeProvider)
{
var valuesAttribute = attributeProvider.GetCustomAttribute<PossibleValuesAttribute>();
// Possible values for primitive collections only apply to members
if (valuesAttribute == null || IsPrimitiveCollection(memberType))
return base.PossibleValues(memberType, attributeProvider);

// Use attribute
// Use attribute
var values = valuesAttribute.GetValues(Container, ServiceProvider);
return values?.Distinct().ToArray();
}

}
/// <summary>
/// Check if a property is a collection of primitives
/// </summary>
Expand Down
86 changes: 49 additions & 37 deletions src/Moryx/Serialization/DefaultSerialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I missing something or are the RegularExpressionAttribute and the StringLengthAttribute missing? 🤔

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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}
}
17 changes: 13 additions & 4 deletions src/Moryx/Serialization/EntryConvert/EntryValidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0

using System;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;

namespace Moryx.Serialization
Expand Down Expand Up @@ -37,10 +38,17 @@ public class EntryValidation : ICloneable
public bool IsRequired { get; set; }

/// <summary>
/// Creates a new <see cref="EntryValidation"/> instance initializing <see cref="EntryValidation.Maximum"/>
/// and <see cref="EntryValidation.Minimum"/> validation to the largest possible range.
/// List of denied values
/// </summary>
public EntryValidation()
[DataMember]
public string[] DeniedValues { get; set; }


/// <summary>
/// Creates a new <see cref="EntryValidation"/> instance initializing <see cref="EntryValidation.Maximum"/>
/// and <see cref="EntryValidation.Minimum"/> validation to the largest possible range.
/// </summary>
public EntryValidation()
{
Minimum = double.MinValue;
Maximum = double.MaxValue;
Expand All @@ -63,7 +71,8 @@ public EntryValidation Clone(bool deep)
Minimum = Minimum,
Maximum = Maximum,
Regex = Regex,
IsRequired = IsRequired
IsRequired = IsRequired,
DeniedValues = DeniedValues,
};
return copy;
}
Expand Down
Loading