示例#1
0
        protected (ClassViewModel ServedType, ClassViewModel DeclaredFor) GetStrategyTypes(
            ModelBindingContext bindingContext,
            Type strategyInterface
            )
        {
            // Grab the type information about what we need to inject.
            var parameterTypeViewModel = new ReflectionTypeViewModel(bindingContext.ModelType);

            // Figure out what type is satisfying the generic parameter of our strategy interface.
            // This is the type that our datasource/Behaviors needs to serve.
            var servedType = parameterTypeViewModel.GenericArgumentsFor(strategyInterface).Single().ClassViewModel;

            // Examine the parameter for any attributes.
            var parameterDescriptor = bindingContext.ActionContext.ActionDescriptor.Parameters
                                      .Single(p => p.Name == bindingContext.FieldName)
                                      as Microsoft.AspNetCore.Mvc.Controllers.ControllerParameterDescriptor;
            var parameterInfo        = parameterDescriptor.ParameterInfo;
            var declaredForAttribute = parameterInfo.GetAttribute <DeclaredForAttribute>();

            // See if there is an override for the type that we want to find declared data sources for.
            ClassViewModel declaredFor = servedType;

            if (declaredForAttribute != null)
            {
                declaredFor = ReflectionRepository.Global.GetClassViewModel(declaredForAttribute.DeclaredFor);
            }

            return(servedType, declaredFor);
        }
示例#2
0
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var typeViewModel = new ReflectionTypeViewModel(context.Metadata.ModelType);

            if (!typeViewModel.IsA(typeof(IBehaviors <>)))
            {
                return(null);
            }

            return(new BinderTypeModelBinder(typeof(BehaviorsModelBinder)));
        }
示例#3
0
        private static void Configure <T>(ClassMap map)
        {
            map.ReferenceMaps.Clear();

            //http://stackoverflow.com/questions/1571022/how-would-i-know-if-a-property-is-a-generic-collection
            var membersToRemove = map.MemberMaps
                                  .Where(p => {
                // Remove non-properties. Coalesce only exposes properties.
                if (p.Data.Member.MemberType != System.Reflection.MemberTypes.Property)
                {
                    return(true);
                }

                var memberType = new ReflectionTypeViewModel(p.Data.Member.MemberType());
                return(memberType.IsA(typeof(ICollection <>)));
            })
                                  .ToArray();

            foreach (var pm in membersToRemove)
            {
                map.MemberMaps.Remove(pm);
            }
        }
示例#4
0
        private void SetupProps()
        {
            if (ViewModelType == typeof(ReflectionClassViewModel))
            {
                ClassViewModel = ReflectionRepositoryFactory.Reflection.GetClassViewModel(TargetType);
            }
            else if (ViewModelType == typeof(SymbolClassViewModel))
            {
                var fqn          = new ReflectionTypeViewModel(TargetType).VerboseFullyQualifiedName;
                var symbolFormat = SymbolTypeViewModel.VerboseDisplayFormat;

                var locatedSymbol = ReflectionRepositoryFactory.Symbols
                                    .Where(symbol => symbol.ToDisplayString(symbolFormat) == fqn)
                                    .FirstOrDefault();

                if (locatedSymbol == null)
                {
                    throw new ArgumentException($"Class {TargetType} ({fqn}) not found in any C# embedded resources.");
                }

                ClassViewModel = ReflectionRepositoryFactory.Symbol.GetClassViewModel(locatedSymbol);
            }
        }
示例#5
0
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            // Specify a default argument name if none is set by ModelBinderAttribute
            // This is the name of the query parameter on the URL.
            if (string.IsNullOrEmpty(bindingContext.BinderModelName))
            {
                bindingContext.BinderModelName = bindingContext.ModelName;
            }

            var valueProviderResult =
                bindingContext.ValueProvider.GetValue(bindingContext.BinderModelName);

            // This is the name of the dataSource that has been requested.
            var requestedDataSource = valueProviderResult.FirstValue;

            var(servedType, declaredFor) = GetStrategyTypes(bindingContext, typeof(IDataSource <>));

            object dataSource;

            try
            {
                dataSource = dataSourceFactory.GetDataSource(servedType, declaredFor, requestedDataSource);
            }
            catch (DataSourceNotFoundException ex)
            {
                // A data-source that doesn't exist was requested. Add a binding error and quit.
                // The ApiController's IActionFilter (or individual actions) are responsible for handling the response for this error condition.
                bindingContext.ModelState.TryAddModelError(bindingContext.BinderModelName, ex.Message);
                return;
            }

            // We now have an IDataSource<> instance. Get its actual type so we can reflect on it.
            var dataSourceType = dataSource.GetType();


            // From our concrete dataSource, figure out which properties on it are injectable parameters.
            var desiredPropertyViewModels =
                new ReflectionTypeViewModel(dataSourceType).ClassViewModel.DataSourceParameters;

            // Get the ASP.NET MVC metadata objects for these properties.
            var desiredPropertiesMetadata = desiredPropertyViewModels
                                            .Select(propViewModel => bindingContext.ModelMetadata.GetMetadataForProperty(dataSourceType, propViewModel.Name))
                                            .ToList();

            // Tell the validation stage that it should only perform validation
            // on the specific properties which we are binding to (and not ALL properties on the dataSource).
            bindingContext.ValidationState[dataSource] = new ValidationStateEntry()
            {
                Strategy = new SelectivePropertyComplexObjectValidationStrategy(desiredPropertiesMetadata)
            };

            // Hijack ComplexTypeModelBinder to do our binding for us on the properties we care about.
            var childBinder = new ComplexTypeModelBinder(desiredPropertiesMetadata.ToDictionary(
                                                             property => property,
                                                             property => modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
            {
                BindingInfo = new BindingInfo()
                {
                    BinderModelName        = property.BinderModelName,
                    BinderType             = property.BinderType,
                    BindingSource          = property.BindingSource,
                    PropertyFilterProvider = property.PropertyFilterProvider,
                },
                Metadata   = property,
                CacheToken = property,
            })
                                                             ), new LoggerFactory());

            // Enter a nested scope for binding the properties on our dataSource
            // (we're now 1 level deep instead of 0 levels deep).
            using (bindingContext.EnterNestedScope(
                       bindingContext.ModelMetadata.GetMetadataForType(dataSourceType),
                       bindingContext.FieldName,
                       bindingContext.ModelName,
                       dataSource))
            {
                bindingContext.PropertyFilter = p => desiredPropertiesMetadata.Contains(p);

                // We call the private method "BindModelCoreAsync" here because
                // "BindModelAsync" performs a check to see if we should bother instantiating the root model (our dataSource).
                // We already instantiated our dataSource, so this check is meaningless. The consequence of this frivolous check is that
                // it causeses validation of client parameter properties
                // to not occurr if the client didn't provide any values for those parameters.

                // The alternative to do this would be to make a full copy of ComplexTypeModelBinder.cs and
                // change out the desired pieces.
                await(childBinder
                      .GetType()
                      .GetMethod("BindModelCoreAsync", BindingFlags.NonPublic | BindingFlags.Instance)
                      .Invoke(childBinder, new[] { bindingContext }) as Task);
                // await childBinder.BindModelAsync(bindingContext);
            }

            // Everything worked out; we have a dataSource!
            // Hand back our resulting object, and we're done.
            bindingContext.Result = ModelBindingResult.Success(dataSource);
        }