| | | 1 | | using Elsa.Workflows.Models; |
| | | 2 | | |
| | | 3 | | namespace Elsa.Workflows; |
| | | 4 | | |
| | | 5 | | /// <inheritdoc /> |
| | | 6 | | public class OutputConverterRegistry : IOutputConverterRegistry |
| | | 7 | | { |
| | | 8 | | private readonly IReadOnlyDictionary<string, OutputConverterRegistration> _registrations; |
| | | 9 | | |
| | 155 | 10 | | public OutputConverterRegistry(IEnumerable<OutputConverterRegistration> registrations) |
| | | 11 | | { |
| | 155 | 12 | | var registrationList = registrations.ToList(); |
| | 155 | 13 | | ValidateRegistrations(registrationList); |
| | 179 | 14 | | _registrations = registrationList.ToDictionary(x => x.Descriptor.Id, StringComparer.Ordinal); |
| | 149 | 15 | | } |
| | | 16 | | |
| | | 17 | | /// <inheritdoc /> |
| | 17 | 18 | | public IEnumerable<OutputConverterDescriptor> ListAll() => _registrations.Values.Select(x => x.Descriptor); |
| | | 19 | | |
| | | 20 | | /// <inheritdoc /> |
| | | 21 | | public OutputConverterDescriptor? Find(string id) => |
| | 19 | 22 | | _registrations.TryGetValue(id, out var registration) ? registration.Descriptor : null; |
| | | 23 | | |
| | | 24 | | /// <summary> |
| | | 25 | | /// Finds the internal keyed-service registration associated with the specified converter ID. |
| | | 26 | | /// </summary> |
| | | 27 | | public OutputConverterRegistration? FindRegistration(string id) => |
| | 3 | 28 | | _registrations.TryGetValue(id, out var registration) ? registration : null; |
| | | 29 | | |
| | | 30 | | /// <inheritdoc /> |
| | | 31 | | public IEnumerable<OutputConverterDescriptor> FindCompatible(Type sourceType, Type destinationType) => |
| | 5 | 32 | | ListAll().Where(x => |
| | 14 | 33 | | x.SourceType.IsAssignableFrom(sourceType) && |
| | 14 | 34 | | IsAssignableToDestination(x.ResultType, destinationType)); |
| | | 35 | | |
| | | 36 | | internal static bool IsAssignableToDestination(Type valueType, Type destinationType) |
| | | 37 | | { |
| | 21 | 38 | | if (destinationType.IsAssignableFrom(valueType)) |
| | 17 | 39 | | return true; |
| | | 40 | | |
| | 4 | 41 | | var underlyingDestinationType = Nullable.GetUnderlyingType(destinationType); |
| | 4 | 42 | | return underlyingDestinationType?.IsAssignableFrom(valueType) == true; |
| | | 43 | | } |
| | | 44 | | |
| | | 45 | | private static void ValidateRegistrations(IReadOnlyCollection<OutputConverterRegistration> registrations) |
| | | 46 | | { |
| | 382 | 47 | | foreach (var registration in registrations) |
| | | 48 | | { |
| | 38 | 49 | | ValidateDescriptor(registration.Descriptor); |
| | 36 | 50 | | var id = registration.Descriptor.Id; |
| | | 51 | | |
| | 36 | 52 | | if (!string.Equals(id, registration.ServiceKey, StringComparison.Ordinal)) |
| | 2 | 53 | | throw new InvalidOperationException($"Output converter registration '{id}' must use the Converter ID as |
| | | 54 | | } |
| | | 55 | | |
| | 151 | 56 | | var duplicate = registrations |
| | 34 | 57 | | .GroupBy(x => x.Descriptor.Id, StringComparer.OrdinalIgnoreCase) |
| | 183 | 58 | | .FirstOrDefault(x => x.Count() > 1); |
| | | 59 | | |
| | 151 | 60 | | if (duplicate != null) |
| | 2 | 61 | | throw new InvalidOperationException($"Output converter ID '{duplicate.Key}' is registered more than once or |
| | 149 | 62 | | } |
| | | 63 | | |
| | | 64 | | internal static void ValidateDescriptor(OutputConverterDescriptor descriptor) |
| | | 65 | | { |
| | 46 | 66 | | if (string.IsNullOrWhiteSpace(descriptor.Id)) |
| | 0 | 67 | | throw new InvalidOperationException("Output converter IDs cannot be empty."); |
| | | 68 | | |
| | 46 | 69 | | if (descriptor.SourceType.ContainsGenericParameters || descriptor.ResultType.ContainsGenericParameters) |
| | 2 | 70 | | throw new InvalidOperationException($"Output converter '{descriptor.Id}' cannot use open-generic source or r |
| | 44 | 71 | | } |
| | | 72 | | } |