/// <summary> /// All types covered by RESTable are selected and validated here /// /// Resources /// entity /// regular /// wrapper /// terminal /// binary /// Views /// /// </summary> /// <returns></returns> private void ValidateAndBuildTypeLists(out List <Type> regularTypes, out List <Type> wrapperTypes, out List <Type> terminalTypes, out List <Type> binaryTypes, out List <Type> eventTypes) { var allTypes = typeof(object).GetSubclasses().ToList(); var resourceTypes = allTypes.Where(t => t.HasAttribute <RESTableAttribute>(out var a) && a is not RESTableProceduralAttribute).ToArray(); var viewTypes = allTypes.Where(t => t.HasAttribute <RESTableViewAttribute>()).ToArray(); if (resourceTypes.Union(viewTypes).ContainsDuplicates(t => t.GetRESTableTypeName()?.ToLower() ?? "unknown", out var dupe)) { throw new InvalidResourceDeclarationException("Types used by RESTable must have unique case insensitive names. Found " + $"multiple types with case insensitive name '{dupe}'."); } void ValidateViewTypes(ICollection <Type> _viewTypes) { foreach (var viewType in _viewTypes) { var resource = viewType.DeclaringType; if (!viewType.IsClass || !viewType.IsNestedPublic || resource == null) { throw new InvalidResourceViewDeclarationException(viewType, "Resource view types must be declared as public classes nested within the the " + "resource type they are views for"); } if (viewType.IsSubclassOf(resource)) { throw new InvalidResourceViewDeclarationException(viewType, "Views cannot inherit from their resource types"); } if (typeof(IResourceWrapper).IsAssignableFrom(resource)) { var wrapped = resource.GetWrappedType(); if (!viewType.ImplementsGenericInterface(typeof(ISelector <>), out var param) || param[0] != wrapped) { throw new InvalidResourceViewDeclarationException(viewType, $"Expected view type to implement ISelector<{wrapped.GetRESTableTypeName()}>"); } } else if (!viewType.ImplementsGenericInterface(typeof(ISelector <>), out var param) || param[0] != resource) { throw new InvalidResourceViewDeclarationException(viewType, $"Expected view type to implement ISelector<{resource.GetRESTableTypeName()}>"); } var resourceProperties = TypeCache.GetDeclaredProperties(resource); foreach (var property in TypeCache.FindAndParseDeclaredProperties(viewType).Where(prop => resourceProperties.ContainsKey(prop.Name))) { throw new InvalidResourceViewDeclarationException(viewType, $"Invalid property '{property.Name}'. Resource view types must not contain any public instance " + "properties with the same name (case insensitive) as a property of the corresponding resource. " + "All properties in the resource are automatically inherited for use in conditions with the view."); } } } (regularTypes, wrapperTypes, terminalTypes, binaryTypes, eventTypes) = ResourceValidator.Validate(resourceTypes); ValidateViewTypes(viewTypes); }
public ResourceFactory ( IEnumerable <IEntityResourceProvider> resourceProviders, TerminalResourceProvider terminalResourceProvider, BinaryResourceProvider binaryResourceProvider, VirtualResourceProvider virtualResourceProvider, TypeCache typeCache, ResourceValidator resourceValidator, ResourceCollection resourceCollection, RootAccess rootAccess ) { TerminalProvider = terminalResourceProvider; BinaryProvider = binaryResourceProvider; VrProvider = virtualResourceProvider; ExternalResourceProviders = resourceProviders.ToList(); TypeCache = typeCache; ResourceValidator = resourceValidator; ResourceCollection = resourceCollection; RootAccess = rootAccess; EntityResourceProviders = new Dictionary <string, IEntityResourceProviderInternal>(); }