Beispiel #1
0
 public ReflectionPropertyViewModel(ClassViewModel effectiveParent, ClassViewModel declaringParent, PropertyInfo propetyInfo)
 {
     Parent          = declaringParent;
     EffectiveParent = effectiveParent;
     Info            = propetyInfo;
     Type            = new ReflectionTypeViewModel(Info.PropertyType);
 }
 public SymbolPropertyViewModel(ClassViewModel effectiveParent, ClassViewModel declaringParent, IPropertySymbol symbol)
 {
     Parent          = declaringParent;
     EffectiveParent = effectiveParent;
     Symbol          = symbol;
     Type            = new SymbolTypeViewModel(Symbol.Type);
 }
Beispiel #3
0
        public static List <ClassViewModel> AddContext(INamedTypeSymbol contextSymbol, string area = "") // where T: AppDbContext
        {
            var context = new ClassViewModel(contextSymbol, null, null, false);

            // Reflect on the AppDbContext
            return(AddContext(context, area));
        }
Beispiel #4
0
        public static List <ClassViewModel> AddContext(ClassViewModel context, string area = "")
        {
            _contextNamespace = context.Namespace;
            // Lock so that parallel execution only uses this once at a time.
            lock (_lock)
            {
                var models = new List <ClassViewModel>();
                foreach (var prop in context.Properties)
                {
                    if ((prop.Type.IsCollection || prop.IsDbSet) &&
                        IsValidViewModelClass(prop.PureType.Name) &&
                        !prop.IsInternalUse)
                    {
                        var model = ReflectionRepository.GetClassViewModel(classType: prop.PureType, hasDbSet: prop.IsDbSet);
                        if (model != null)
                        {
                            model.ContextPropertyName = prop.Name;
                            model.OnContext           = true;
                            model.ContextPropertyName = prop.Name;
                            models.Add(model);
                        }
                    }
                }
                // Check for other associated types that are not dbsets
                foreach (var model in models.ToList())
                {
                    AddChildModels(models, model);
                }

                return(models);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Gets a list of properties that should be searched for text.
        /// It will first look for any properties that are decorated with the Search attribute.
        /// If it doesn't find those, it will look for a property called Name or {Class}Name.
        /// If none of those are found, it will result in returning the property that is the primary key for the object
        /// </summary>
        public IEnumerable <SearchableProperty> SearchProperties(ClassViewModel rootModel = null, int depth = 0, int maxDepth = 2)
        {
            // Only go down three levels.
            if (depth == 3)
            {
                yield break;
            }

            var searchProperties = Properties.Where(f => f.IsSearchable(rootModel)).ToList();

            if (searchProperties.Count > 0)
            {
                // Process these items to make sure we have things we can search on.
                foreach (var property in searchProperties)
                {
                    // Get all the child items
                    foreach (var searchProperty in property.SearchProperties(rootModel, depth, maxDepth))
                    {
                        yield return(searchProperty);
                    }
                }
                yield break;
            }

            yield return(new[]
            {
                PropertyByName("Name"),
                Properties.FirstOrDefault(p => p.Name == $"{p.Parent.Name}Name"),
                PrimaryKey
            }
                         .Where(p => p != null && p.IsClientProperty && p.HasNotMapped == false)
                         .Select(p => new SearchableValueProperty(p))
                         .FirstOrDefault());
        }
        /// <summary>
        /// Returns true if this property is marked with the Search attribute.
        /// </summary>
        public bool IsSearchable(ClassViewModel rootModel)
        {
            if (!HasAttribute <SearchAttribute>())
            {
                return(false);
            }

            var rootModelName = rootModel?.Name;

            if (rootModelName == null)
            {
                return(true);
            }

            var whitelist = this.GetAttributeValue <SearchAttribute>(a => a.RootWhitelist);

            if (!string.IsNullOrWhiteSpace(whitelist))
            {
                return(whitelist.Split(',').Contains(rootModelName));
            }

            var blacklist = this.GetAttributeValue <SearchAttribute>(a => a.RootBlacklist);

            if (!string.IsNullOrWhiteSpace(blacklist))
            {
                return(!blacklist.Split(',').Contains(rootModelName));
            }

            return(true);
        }
        /// <summary>
        /// Returns the fields to search for this object. This could be just the field itself
        /// or a number of child fields if this is an object or collection.
        /// </summary>
        public IEnumerable <SearchableProperty> SearchProperties(ClassViewModel rootModel, int depth = 0, int maxDepth = 2, bool force = false)
        {
            if (!force && !IsSearchable(rootModel))
            {
                yield break;
            }

            if (this.PureType.HasClassViewModel)
            {
                // If we will exceed the depth don't try to query on an object.
                if (depth < maxDepth)
                {
                    // Remove this item and add the child's search items with a prepended property name
                    var childProperties = this.Type.PureType.ClassViewModel.SearchProperties(rootModel, depth + 1, maxDepth);

                    if (this.Type.IsCollection)
                    {
                        yield return(new SearchableCollectionProperty(this, childProperties));
                    }
                    else
                    {
                        yield return(new SearchableObjectProperty(this, childProperties));
                    }
                }
            }
            else
            {
                yield return(new SearchableValueProperty(this));
            }
        }
 protected override IReadOnlyCollection <PropertyViewModel> RawProperties(ClassViewModel effectiveParent) => Info
 .GetProperties()
 .Select((p, i) => new ReflectionPropertyViewModel(effectiveParent, new ReflectionTypeViewModel(p.DeclaringType).ClassViewModel, p)
 {
     ClassFieldOrder = i
 })
 .Cast <PropertyViewModel>()
 .ToList().AsReadOnly();
Beispiel #9
0
 private void DiscoverNestedCrudStrategiesOn(ClassViewModel model)
 {
     foreach (var nestedType in model.ClientNestedTypes)
     {
         AddCrudStrategy(typeof(IDataSource <>), nestedType, _dataSources, model);
         AddCrudStrategy(typeof(IBehaviors <>), nestedType, _behaviors, model);
     }
 }
Beispiel #10
0
 private void DiscoverExternalPropertyTypesOn(ClassViewModel model)
 {
     foreach (var type in model
              .ClientProperties
              .Select(p => p.PureType)
              .Where(t => t.HasClassViewModel))
     {
         ConditionallyAddAndDiscoverExternalPropertyTypesOn(type.ClassViewModel);
     }
 }
Beispiel #11
0
        /// <summary>
        /// Cache the given model so it can be reused when an instance representing its underlying type is requested.
        /// </summary>
        /// <param name="classViewModel">The ClassViewModel to cache.</param>
        /// <param name="force">
        /// True to override any existing object for the underlying type.
        /// False to preserve any existing object.
        /// </param>
        /// <returns>The ClassViewModel that was passed in, for convenience.</returns>
        private ClassViewModel Cache(ClassViewModel classViewModel, bool force = false)
        {
            object key = GetCacheKey(classViewModel);

            if (force)
            {
                _allClassViewModels[key] = classViewModel;
            }
            else
            {
                _allClassViewModels.GetOrAdd(key, classViewModel);
            }

            return(classViewModel);
        }
Beispiel #12
0
        private void DiscoverExternalMethodTypesOn(ClassViewModel model)
        {
            foreach (var method in model.ClientMethods)
            {
                var returnType = method.ResultType.PureType;
                if (returnType.HasClassViewModel)
                {
                    // Return type looks like an external type.
                    ConditionallyAddAndDiscoverExternalPropertyTypesOn(returnType.ClassViewModel);
                }

                foreach (var arg in method.Parameters.Where(p => !p.IsDI && p.Type.HasClassViewModel))
                {
                    // Parameter looks like an external type.
                    ConditionallyAddAndDiscoverExternalPropertyTypesOn(arg.Type.ClassViewModel);
                }
            }
        }
Beispiel #13
0
 /// <summary>
 /// Attempt to add the given ClassViewModel as an ExternalType if it isn't already known.
 /// If its a newly discovered type, recurse into that type's properties as well.
 /// </summary>
 /// <param name="externalType"></param>
 private void ConditionallyAddAndDiscoverExternalPropertyTypesOn(ClassViewModel externalType)
 {
     // Don't dig in if:
     //  - This is a known entity type (its not external)
     //  - This is a known custom DTO type (again, not external)
     //  - This is already a known external type (don't infinitely recurse).
     if (
         !Entities.Contains(externalType) &&
         !CustomDtos.Contains(externalType) &&
         !ExternalTypes.Contains(externalType)
         )
     {
         if (_externalTypes.Add(Cache(externalType)))
         {
             DiscoverExternalPropertyTypesOn(externalType);
         }
     }
 }
Beispiel #14
0
        private bool AddCrudStrategy(
            Type iface,
            TypeViewModel strategyType,
            HashSet <CrudStrategyTypeUsage> set,
            ClassViewModel declaredFor = null
            )
        {
            if (!strategyType.IsA(iface))
            {
                return(false);
            }

            var servedType = strategyType.GenericArgumentsFor(iface).Single();

            if (!servedType.HasClassViewModel)
            {
                throw new InvalidOperationException($"{servedType} is not a valid type argument for a {iface}.");
            }
            var servedClass = Cache(servedType.ClassViewModel);

            // See if we were expecting that the strategy be declared for a particular type
            // by virtue of its nesting. If this type has been overridden to something else by an attribute, then that's wrong.
            var explicitlyDeclaredFor = strategyType.GetAttributeValue <DeclaredForAttribute>(a => a.DeclaredFor)?.ClassViewModel;

            if (explicitlyDeclaredFor != null && declaredFor != null && !explicitlyDeclaredFor.Equals(declaredFor))
            {
                throw new InvalidOperationException(
                          $"Expected that {strategyType} is declared for {declaredFor}, but it was explicitly declared for {explicitlyDeclaredFor} instead.");
            }

            // Any explicit declaration is OK. Use that,
            // or the passed in value if no explicit value is given via attribute,
            // or just the type that is served if neither are present.
            declaredFor = explicitlyDeclaredFor ?? declaredFor ?? servedClass;

            if (declaredFor.IsDto && !servedClass.Equals(declaredFor.DtoBaseViewModel))
            {
                throw new InvalidOperationException($"{strategyType} is not a valid {iface} for {declaredFor} - " +
                                                    $"{strategyType} must satisfy {iface} with type parameter <{declaredFor.DtoBaseViewModel}>.");
            }

            set.Add(new CrudStrategyTypeUsage(Cache(strategyType.ClassViewModel), servedClass, declaredFor));
            return(true);
        }
Beispiel #15
0
        protected override IReadOnlyCollection <PropertyViewModel> RawProperties(ClassViewModel effectiveParent)
        {
            var result = Symbol.GetMembers()
                         .Where(s => s.Kind == SymbolKind.Property)
                         .Cast <IPropertySymbol>()
                         .Select((s, i) => new SymbolPropertyViewModel(effectiveParent, this, s)
            {
                ClassFieldOrder = i
            })
                         .Cast <PropertyViewModel>()
                         .ToList();

            // Add properties from the base class
            if (Symbol.BaseType != null && Symbol.BaseType.Name != "Object")
            {
                var parentSymbol = new SymbolClassViewModel(Symbol.BaseType);
                result.AddRange(parentSymbol.RawProperties(effectiveParent));
            }
            return(result.AsReadOnly());
        }
Beispiel #16
0
 private static void AddChildModels(List <ClassViewModel> models, ClassViewModel model)
 {
     foreach (var prop in model.Properties.Where(p => !p.IsInternalUse && p.PureType.IsPOCO && IsValidViewModelClass(p.PureType.Name)))
     {
         var propModel = prop.PureType.ClassViewModel;
         if (propModel != null && !propModel.HasDbSet && !models.Contains(propModel))
         {
             models.Add(propModel);
             AddChildModels(models, propModel);
         }
     }
     foreach (var method in model.Methods.Where(p => !p.IsInternalUse && !p.ReturnType.IsVoid && p.ReturnType.PureType.IsPOCO))
     {
         // Get a unique key
         string key = GetKey(method.ReturnType.PureType);
         lock (models)
         {
             if (!models.Any(f => f.Name == method.ReturnType.PureType.Name))
             {
                 var methodModel = new ClassViewModel(method.ReturnType.PureType, "", "", false);
                 models.Add(methodModel);
                 AddChildModels(models, methodModel);
             }
         }
         // Iterate each of the incoming arguments and check them
         foreach (var arg in method.Parameters.Where(p => !p.IsDI && p.Type.IsPOCO))
         {
             string argKey = GetKey(arg.Type);
             lock (models)
             {
                 if (!models.Any(f => f.Name == arg.Type.Name))
                 {
                     var argModel = new ClassViewModel(arg.Type, "", "", false);
                     models.Add(argModel);
                     AddChildModels(models, argModel);
                 }
             }
         }
     }
 }
Beispiel #17
0
 internal MethodViewModel(MethodWrapper wrapper, ClassViewModel parent, int classMethodOrder)
 {
     Wrapper          = wrapper;
     Parent           = parent;
     ClassMethodOrder = classMethodOrder;
 }
Beispiel #18
0
 internal MethodViewModel(ClassViewModel parent)
 {
     Parent = parent;
 }
Beispiel #19
0
 protected abstract IReadOnlyCollection <PropertyViewModel> RawProperties(ClassViewModel effectiveParent);
Beispiel #20
0
 private object GetCacheKey(ClassViewModel classViewModel) =>
 (classViewModel.Type as ReflectionTypeViewModel)?.Info as object
 ?? (classViewModel.Type as SymbolTypeViewModel)?.Symbol as object
 ?? throw new NotSupportedException("Unknown subtype of TypeViewModel");
Beispiel #21
0
        /// <summary>
        /// Adds a context to the reflection repository. Do this on startup with all the contexts.
        /// </summary>
        /// <typeparam name="t">Type of DbContext to add.</typeparam>
        /// <returns></returns>
        public static List <ClassViewModel> AddContext(Type t, string area = "")
        {
            var context = new ClassViewModel(t, null, null, false);

            return(AddContext(context, area));
        }
Beispiel #22
0
 public SymbolMethodViewModel(IMethodSymbol symbol, ClassViewModel parent) : base(parent)
 {
     Symbol = symbol;
 }
Beispiel #23
0
 public ReflectionMethodViewModel(ClassViewModel parent, MethodInfo methodInfo) : base(parent)
 {
     Info = methodInfo;
 }