This commit is contained in:
2025-10-25 09:28:34 +02:00
parent fd0bdced11
commit bc392f9d7c
7 changed files with 62 additions and 158 deletions

View File

@@ -0,0 +1,15 @@
using CertMgr.Core.Utils;
namespace CertMgr.Core;
public class ConsoleToolsException : Exception
{
internal ConsoleToolsException(string messageFormat, params object?[] messageArgs)
: base(StringFormatter.Format(messageFormat, messageArgs))
{
}
internal ConsoleToolsException(Exception? innerException, string messageFormat, params object?[] messageArgs)
: base(StringFormatter.Format(messageFormat, messageArgs), innerException)
{
}
}

View File

@@ -77,11 +77,11 @@ internal sealed class JobExecutor
} }
catch (Exception e) catch (Exception e)
{ {
throw new CertMgrException(e, "Failed to instantiate job '{0}'", descriptor.JobType.Name); throw new JobException(e, "Failed to instantiate job '{0}'", descriptor.JobType.Name);
} }
if (job == null) if (job == null)
{ {
throw new CertMgrException("Failed to instantiate job '{0}' (Possibly missing parameterless ctor?)", descriptor.JobType.Name); throw new JobException("Failed to instantiate job '{0}' (Possibly missing parameterless ctor?)", descriptor.JobType.Name);
} }
SettingsBuilder settingsBuilder = new SettingsBuilder(rawArgs, descriptor.SettingsType); SettingsBuilder settingsBuilder = new SettingsBuilder(rawArgs, descriptor.SettingsType);
@@ -103,7 +103,7 @@ internal sealed class JobExecutor
sb.AppendFormat("\t- {0}: {1}", vr.ValueName, vr.Justification); sb.AppendFormat("\t- {0}: {1}", vr.ValueName, vr.Justification);
sb.AppendLine(); sb.AppendLine();
} }
throw new CertMgrException(sb.ToString()); throw new JobException(sb.ToString());
} }
MethodInfo? settingsSetter = GetPropertyWithPrivateSetter(descriptor.JobType, "Settings"); MethodInfo? settingsSetter = GetPropertyWithPrivateSetter(descriptor.JobType, "Settings");
@@ -113,7 +113,7 @@ internal sealed class JobExecutor
} }
else else
{ {
throw new CertMgrException("Failed to initialize job '{0}'. Missing property 'Settings' (Possibly the job doesn't inherit from '{1}'?)", descriptor.JobType.Name, typeof(Job<>).Name); throw new JobException("Failed to initialize job '{0}'. Missing property 'Settings' (Possibly the job doesn't inherit from '{1}'?)", descriptor.JobType.Name, typeof(Job<>).Name);
} }
return job; return job;

View File

@@ -23,4 +23,9 @@ public abstract class JobSettings
{ {
return Task.CompletedTask; return Task.CompletedTask;
} }
public override string ToString()
{
return string.Format("type = '{0}'", GetType().ToString(false));
}
} }

View File

@@ -37,8 +37,6 @@ internal sealed class PropertyDescriptor
public Utils.TypeInfo PropertyTypeInfo { [DebuggerStepThrough] get; } public Utils.TypeInfo PropertyTypeInfo { [DebuggerStepThrough] get; }
public Type? ValidatorType => _settingAttribute.Validator;
public IValueValidator? CustomValidator public IValueValidator? CustomValidator
{ {
get get
@@ -52,7 +50,7 @@ internal sealed class PropertyDescriptor
if (validator == null) if (validator == null)
{ {
CLog.Error("Failed to create instance of value-validator of type '{0}' for property '{1}' in class '{2}'", _settingAttribute.Validator.ToString(false), PropertyName, _settingsType.ToString(false)); CLog.Error("Failed to create instance of value-validator of type '{0}' for property '{1}' in class '{2}'", _settingAttribute.Validator.ToString(false), PropertyName, _settingsType.ToString(false));
throw new CertMgrException("Failed to create instance of value-validator of type '{0}' for property '{1}' in class '{2}'", _settingAttribute.Validator.ToString(false), PropertyName, _settingsType.ToString(false)); throw new ConsoleToolsException("Failed to create instance of value-validator of type '{0}' for property '{1}' in class '{2}'", _settingAttribute.Validator.ToString(false), PropertyName, _settingsType.ToString(false));
} }
} }
@@ -73,6 +71,12 @@ internal sealed class PropertyDescriptor
if (typeof(IValueConverter).IsAssignableFrom(valueConverter)) if (typeof(IValueConverter).IsAssignableFrom(valueConverter))
{ {
converter = (IValueConverter?)Activator.CreateInstance(valueConverter); converter = (IValueConverter?)Activator.CreateInstance(valueConverter);
if (converter == null)
{
CLog.Error("Failed to create instance of value-conveter of type '{0}' for property '{1}' in class '{2}'", valueConverter.ToString(false), PropertyName, _settingsType.ToString(false));
throw new ConsoleToolsException("Failed to create instance of value-converter of type '{0}' for property '{1}' in class '{2}'", valueConverter.ToString(false), PropertyName, _settingsType.ToString(false));
}
} }
else else
{ {
@@ -111,36 +115,8 @@ internal sealed class PropertyDescriptor
return succeeded; return succeeded;
} }
/// <summary>Returns types that validator handles. Usually there is just one type, but class can inherit from multiple ISettingValidator&lt;T&gt; types.</summary> public override string ToString()
/// <param name="validatorType">Type used to create instance of a type</param>
/// <returns>List of types handled by validator.</returns>
private static IReadOnlyList<Type> GetValidatedTypes(Type validatorType)
{ {
if (validatorType == null) return string.Format("property '{0}', type = {1}, is-mandatory = {2}, validator = {3}, converter = {4}", PropertyName, PropertyTypeInfo.SourceType.ToString(false), IsMandatory ? "yes" : "no", CustomValidator?.GetType().ToString(false) ?? "<null>", CustomConverter?.GetType().ToString(false) ?? "<null>");
{
throw new ArgumentNullException(nameof(validatorType));
}
List<Type> validatedTypes = new List<Type>();
if (validatorType.IsInterface && validatorType.IsGenericType && validatorType.GetGenericTypeDefinition() == typeof(IValueValidator<>))
{
Type candidate = validatorType.GetGenericArguments()[0];
validatedTypes.Add(candidate);
}
foreach (Type iface in validatorType.GetInterfaces())
{
if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IValueValidator<>))
{
Type candidate = iface.GetGenericArguments()[0];
if (!validatedTypes.Contains(candidate))
{
validatedTypes.Add(candidate);
}
}
}
return validatedTypes;
} }
} }

View File

@@ -41,43 +41,12 @@ internal sealed class SettingsBuilder
{ {
IValidationResult valres = await validator.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false); IValidationResult valres = await validator.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false);
settings.ValidationResults.Add(valres); settings.ValidationResults.Add(valres);
// IReadOnlyList<Type> validatedTypes = GetValidatedTypes(descriptor.ValidatorType);
//
// if (descriptor.PropertyTypeInfo.IsCollection)
// {
// Utils.TypeInfo validatedTypeInfo = TypeUtils.UnwrapCollection(validatedTypes[0]);
// if (validatedTypeInfo.IsCollection)
// {
// // validator validates collection => send whole collection as argument to ValidateAsync(..)
// ValidationResult valres = await validator.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false);
// settings.ValidationResults.Add(valres);
// }
// else
// {
// // validator validates elements => send items one by one to ValidateAsync(..)
// if (setPropertyResult.Value is IList list)
// {
// foreach (object value in list)
// {
// ValidationResult valres = await validator.ValidateAsync(value, cancellationToken).ConfigureAwait(false);
// settings.ValidationResults.Add(valres);
// }
// }
// }
// }
// else
// {
// // setting is not a collection. lets assume the validator doesn't validate collection as well
// ValidationResult valres = await validator.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false);
// settings.ValidationResults.Add(valres);
// }
} }
} }
catch (Exception e) catch (Exception e)
{ {
CLog.Error(e, "Failed to validate property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); CLog.Error(e, "Failed to validate property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false));
throw new CertMgrException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); throw new ConsoleToolsException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false));
} }
} }
} }
@@ -85,36 +54,6 @@ internal sealed class SettingsBuilder
return settings; return settings;
} }
private static IReadOnlyList<Type> GetValidatedTypes(Type validatorType)
{
if (validatorType == null)
{
throw new ArgumentNullException(nameof(validatorType));
}
List<Type> hits = new List<Type>();
if (validatorType.IsInterface && validatorType.IsGenericType && validatorType.GetGenericTypeDefinition() == typeof(IValueValidator<>))
{
Type candidate = validatorType.GetGenericArguments()[0];
hits.Add(candidate);
}
foreach (Type iface in validatorType.GetInterfaces())
{
if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IValueValidator<>))
{
Type candidate = iface.GetGenericArguments()[0];
if (!hits.Contains(candidate))
{
hits.Add(candidate);
}
}
}
return hits;
}
private async Task<AsyncResult<object?>> SetPropertyValueAsync(JobSettings settings, PropertyDescriptor descriptor, CancellationToken cancellationToken) private async Task<AsyncResult<object?>> SetPropertyValueAsync(JobSettings settings, PropertyDescriptor descriptor, CancellationToken cancellationToken)
{ {
object? convertedValue = null; object? convertedValue = null;
@@ -135,7 +74,7 @@ internal sealed class SettingsBuilder
catch (Exception e) catch (Exception e)
{ {
CLog.Error(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); CLog.Error(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false));
throw new CertMgrException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); throw new ConsoleToolsException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false));
} }
} }
else if (descriptor.IsMandatory) else if (descriptor.IsMandatory)
@@ -195,17 +134,17 @@ internal sealed class SettingsBuilder
instance = Activator.CreateInstance(_settingsType); instance = Activator.CreateInstance(_settingsType);
if (instance == null) if (instance == null)
{ {
throw new CertMgrException("Failed to create instance for settings of type '{0}'", _settingsType.Name); throw new ConsoleToolsException("Failed to create instance for settings of type '{0}'", _settingsType.Name);
} }
} }
catch (Exception e) catch (Exception e)
{ {
throw new CertMgrException(e, "Failed to create instance for settings of type '{0}'", _settingsType.Name); throw new ConsoleToolsException(e, "Failed to create instance for settings of type '{0}'", _settingsType.Name);
} }
if (instance is not JobSettings settings) if (instance is not JobSettings settings)
{ {
throw new CertMgrException("Failed to create instance for settings of type '{0}'. The type is not of type '{1}'", _settingsType.Name, typeof(JobSettings).Name); throw new ConsoleToolsException("Failed to create instance for settings of type '{0}'. The type is not of type '{1}'", _settingsType.Name, typeof(JobSettings).Name);
} }
return settings; return settings;
@@ -268,59 +207,6 @@ internal sealed class SettingsBuilder
return new AsyncResult<object?>(success, convertedValue); return new AsyncResult<object?>(success, convertedValue);
} }
/*private static object BuildCollectionValue(Type collectionType, Type elementType, IReadOnlyList<object?> items)
{
// convert source collection with 'items' of type 'object?' to collection with items of requested type:
Type listType = typeof(List<>).MakeGenericType(elementType);
IList typedList = (IList)Activator.CreateInstance(listType)!;
foreach (object? item in items)
{
typedList.Add(item);
}
if (collectionType.IsArray)
{
Array array = Array.CreateInstance(elementType, typedList.Count);
typedList.CopyTo(array, 0);
return array;
}
// it is either IEnumerable<T> or ICollection<T> or IList<T> or List<T>
if (collectionType.IsAssignableFrom(listType))
{
return typedList;
}
// we do not know the type, but try to instantiate 'collectionType' and if it implements ICollection<>, then fill it
object? instance = Activator.CreateInstance(collectionType);
if (instance != null)
{
Type? iCollectionT = collectionType
.GetInterfaces()
.FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>));
if (iCollectionT != null)
{
MethodInfo? add = iCollectionT.GetMethod("Add");
if (add != null)
{
foreach (object? item in typedList)
{
add.Invoke(instance, new object?[] { item });
}
return instance;
}
}
}
// try it as array, we fail anyway
Array fallback = Array.CreateInstance(elementType, typedList.Count);
typedList.CopyTo(fallback, 0);
return fallback;
}*/
private bool TryConvertValue(string rawValue, Type targetType, out object? convertedValue) private bool TryConvertValue(string rawValue, Type targetType, out object? convertedValue)
{ {
convertedValue = null; convertedValue = null;

View File

@@ -0,0 +1,15 @@
using CertMgr.Core.Utils;
namespace CertMgr.Core.Validation;
public sealed class ValidationException : Exception
{
internal ValidationException(string messageFormat, params object?[] messageArgs)
: base(StringFormatter.Format(messageFormat, messageArgs))
{
}
internal ValidationException(Exception? innerException, string messageFormat, params object?[] messageArgs)
: base(StringFormatter.Format(messageFormat, messageArgs), innerException)
{
}
}

View File

@@ -24,9 +24,16 @@ public abstract class ValueValidator<T> : IValueValidator<T>
} }
catch (Exception e) catch (Exception e)
{ {
throw new CertMgrException(e, "'{0}': failed to convert value of type '{1}' to type '{2}' (value-name = '{3}')", GetType().ToString(false), value?.GetType().ToString(false) ?? "<null>", typeof(T).ToString(false), ValueName); throw new ValidationException(e, "'{0}': failed to convert value of type '{1}' to type '{2}' (value-name = '{3}')", GetType().ToString(false), value?.GetType().ToString(false) ?? "<null>", typeof(T).ToString(false), ValueName);
} }
try
{
return ValidateAsync(typedValue, cancellationToken); return ValidateAsync(typedValue, cancellationToken);
} }
catch (Exception e)
{
throw new ValidationException(e, "'{0}': failed to validate value of type '{1}' (value-name = '{2}')", GetType().ToString(false), value?.GetType().ToString(false) ?? "<null>", ValueName);
}
}
} }