diff --git a/src/Squidex.Infrastructure/Http/DumpFormatter.cs b/src/Squidex.Infrastructure/Http/DumpFormatter.cs index 4063f0105..5f0c0dff1 100644 --- a/src/Squidex.Infrastructure/Http/DumpFormatter.cs +++ b/src/Squidex.Infrastructure/Http/DumpFormatter.cs @@ -66,7 +66,7 @@ namespace Squidex.Infrastructure.Http writer.AppendLine(responseBody); } - if (response != null) + if (response != null && elapsed != TimeSpan.Zero) { writer.AppendLine(); writer.AppendLine($"Elapsed: {elapsed}"); diff --git a/src/Squidex/Areas/Api/Controllers/JsonInheritanceConverter.cs b/src/Squidex/Areas/Api/Controllers/JsonInheritanceConverter.cs index fe5f23cf3..af9b07000 100644 --- a/src/Squidex/Areas/Api/Controllers/JsonInheritanceConverter.cs +++ b/src/Squidex/Areas/Api/Controllers/JsonInheritanceConverter.cs @@ -6,9 +6,9 @@ // ========================================================================== using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Runtime.Serialization; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NJsonSchema.Annotations; @@ -20,6 +20,8 @@ namespace Squidex.Areas.Api.Controllers public sealed class JsonInheritanceConverter : JsonConverter { private readonly string discriminator; + private readonly Dictionary mapNameToType = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary mapTypeToName = new Dictionary(); [ThreadStatic] private static bool IsReading; @@ -53,9 +55,17 @@ namespace Squidex.Areas.Api.Controllers } } - public JsonInheritanceConverter(string discriminator) + public JsonInheritanceConverter(string discriminator, Type baseType) { this.discriminator = discriminator; + + foreach (var type in baseType.Assembly.GetTypes().Where(x => x != baseType && baseType.IsAssignableFrom(x))) + { + var name = type.GetTypeInfo().GetCustomAttribute()?.Name ?? type.Name; + + mapTypeToName[type] = name; + mapNameToType[name] = type; + } } public override bool CanConvert(Type objectType) @@ -70,7 +80,7 @@ namespace Squidex.Areas.Api.Controllers { var jsonObject = JObject.FromObject(value, serializer); - jsonObject.AddFirst(new JProperty(discriminator, GetSchemaName(value.GetType()))); + jsonObject.AddFirst(new JProperty(discriminator, mapTypeToName[value.GetType()])); writer.WriteToken(jsonObject.CreateReader()); } @@ -94,11 +104,9 @@ namespace Squidex.Areas.Api.Controllers return null; } - var subType = GetObjectSubtype(objectType, subName); - - if (subType == null) + if (subName == null || !mapNameToType.TryGetValue(subName, out var subType)) { - return null; + throw new InvalidOperationException($"Could not find subtype of '{objectType.Name}' with discriminator '{subName}'."); } return serializer.Deserialize(jsonObject.CreateReader(), subType); @@ -108,28 +116,5 @@ namespace Squidex.Areas.Api.Controllers IsReading = false; } } - - private static Type GetObjectSubtype(Type objectType, string discriminatorValue) - { - var knownTypeAttribute = - objectType.GetTypeInfo().GetCustomAttributes() - .FirstOrDefault(a => IsKnownType(a, discriminatorValue)); - - return knownTypeAttribute?.Type; - } - - private static bool IsKnownType(KnownTypeAttribute attribute, string discriminator) - { - var type = attribute.Type; - - return type != null && GetSchemaName(type) == discriminator; - } - - private static string GetSchemaName(Type type) - { - var schenaName = type.GetTypeInfo().GetCustomAttribute()?.Name; - - return schenaName ?? type.Name; - } } } \ No newline at end of file diff --git a/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleActionDto.cs b/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleActionDto.cs index c75fb39dd..ebf67c556 100644 --- a/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleActionDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleActionDto.cs @@ -5,21 +5,23 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Runtime.Serialization; +using System; +using System.Linq; using Newtonsoft.Json; -using Squidex.Areas.Api.Controllers.Rules.Models.Actions; using Squidex.Domain.Apps.Core.Rules; namespace Squidex.Areas.Api.Controllers.Rules.Models { - [JsonConverter(typeof(JsonInheritanceConverter), "actionType")] - [KnownType(typeof(AlgoliaActionDto))] - [KnownType(typeof(AzureQueueActionDto))] - [KnownType(typeof(FastlyActionDto))] - [KnownType(typeof(SlackActionDto))] - [KnownType(typeof(WebhookActionDto))] + [JsonConverter(typeof(JsonInheritanceConverter), "actionType", typeof(RuleActionDto))] public abstract class RuleActionDto { public abstract RuleAction ToAction(); + + public static Type[] Subtypes() + { + var type = typeof(RuleActionDto); + + return type.Assembly.GetTypes().Where(type.IsAssignableFrom).ToArray(); + } } } diff --git a/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleTriggerDto.cs b/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleTriggerDto.cs index 16a181e6c..4b1b9bbcf 100644 --- a/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleTriggerDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleTriggerDto.cs @@ -5,18 +5,25 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; +using System.Linq; using System.Runtime.Serialization; using Newtonsoft.Json; -using Squidex.Areas.Api.Controllers.Rules.Models.Triggers; using Squidex.Domain.Apps.Core.Rules; namespace Squidex.Areas.Api.Controllers.Rules.Models { - [JsonConverter(typeof(JsonInheritanceConverter), "triggerType")] - [KnownType(typeof(AssetChangedTriggerDto))] - [KnownType(typeof(ContentChangedTriggerDto))] + [JsonConverter(typeof(JsonInheritanceConverter), "triggerType", typeof(RuleTriggerDto))] + [KnownType("Subtypes")] public abstract class RuleTriggerDto { public abstract RuleTrigger ToTrigger(); + + public static Type[] Subtypes() + { + var type = typeof(RuleTriggerDto); + + return type.Assembly.GetTypes().Where(type.IsAssignableFrom).ToArray(); + } } } diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldPropertiesDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldPropertiesDto.cs index 4eff189b2..58f986535 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldPropertiesDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldPropertiesDto.cs @@ -5,24 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using System.ComponentModel.DataAnnotations; -using System.Runtime.Serialization; +using System.Linq; using Newtonsoft.Json; -using Squidex.Areas.Api.Controllers.Schemas.Models.Fields; using Squidex.Domain.Apps.Core.Schemas; namespace Squidex.Areas.Api.Controllers.Schemas.Models { - [JsonConverter(typeof(JsonInheritanceConverter), "fieldType")] - [KnownType(typeof(AssetsFieldPropertiesDto))] - [KnownType(typeof(BooleanFieldPropertiesDto))] - [KnownType(typeof(DateTimeFieldPropertiesDto))] - [KnownType(typeof(GeolocationFieldPropertiesDto))] - [KnownType(typeof(JsonFieldPropertiesDto))] - [KnownType(typeof(NumberFieldPropertiesDto))] - [KnownType(typeof(ReferencesFieldPropertiesDto))] - [KnownType(typeof(StringFieldPropertiesDto))] - [KnownType(typeof(TagsFieldPropertiesDto))] + [JsonConverter(typeof(JsonInheritanceConverter), "fieldType", typeof(FieldPropertiesDto))] public abstract class FieldPropertiesDto { /// @@ -59,5 +50,12 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models public string Partitioning { get; set; } public abstract FieldProperties ToProperties(); + + public static Type[] Subtypes() + { + var type = typeof(SchemaPropertiesDto); + + return type.Assembly.GetTypes().Where(type.IsAssignableFrom).ToArray(); + } } }