/// <summary> /// Creates new instance of EndpointParameterDescriptor /// </summary> /// <param name="source">Source of Endpoint Parameter, Body, Route etc</param> /// <param name="parameterType">Parameter Object type</param> /// <param name="name">Name of parameter</param> /// <param name="isOptional">If Parameter is optional</param> public EndpointParameterDescriptor(EndpointParameterSource source, Type parameterType, string name, bool isOptional = false) { Source = source; ParameterType = parameterType; Name = name; IsOptional = isOptional; }
private static (SyncParameterFactory factory, EndpointParameterDescriptor[] info) GetParameterInfoForClassProperty(PropertyInfo propertyInfo, EndpointParameterSource source, EndpointDeclarationFactoryOptions options) { return(ParameterBinder.GetParameterDeclaration(propertyInfo.Name, propertyInfo.PropertyType, true, null, source, propertyInfo.PropertyType.IsArray, options)); }
public static (SyncParameterFactory factory, EndpointParameterDescriptor[] info) GetParameterDeclarationForClass(Type type, EndpointParameterSource source, EndpointDeclarationFactoryOptions options) { var constructor = type.GetConstructor(Array.Empty <Type>()); if (constructor is null) { throw new InvalidEndpointSetupException($"No parameterless constructor for {type}"); } var properties = type.GetProperties().Where(IsValidProperty).ToArray(); var parameterInfos = properties.Select(p => GetParameterInfoForClassProperty(p, source, options)).ToArray(); var stateVariable = Expression.Variable(typeof(byte), "ee_state"); var propertyStateVariable = Expression.Variable(typeof(byte), "ee_propetyState"); var resultVariable = Expression.Variable(type, "ee_result"); var propertyResultVariable = Expression.Variable(typeof(ParameterBindingResult), "ee_propertyResult"); var ctor = Expression.New(constructor); var blockExpressions = new List <Expression> { Expression.Assign(stateVariable, Expression.Constant(none)), Expression.Assign(resultVariable, ctor) }; for (var i = 0; i < properties.Length; i++) { blockExpressions.AddRange(BuildPropertyAssignment(properties[i], parameterInfos[i].factory, resultVariable, stateVariable, propertyResultVariable, propertyStateVariable)); } blockExpressions.Add(Expression.New(parameterBindingResultCtor, resultVariable, Expression.Convert(stateVariable, typeof(ParameterBindingIssues)))); var block = Expression.Block(typeof(ParameterBindingResult), new[] { stateVariable, resultVariable, propertyResultVariable, propertyStateVariable }, blockExpressions); var factory = Expression.Lambda <SyncParameterFactory>(block, ctxParameterExpr, optionsParameterExpr, errorCollectionParameterExpr); return(factory.Compile(), parameterInfos.SelectMany(s => s.info).ToArray()); }
private static SyncParameterFactory GetParameterFactory <T>(string parameterName, IParser <T> parsable, bool allowNull, bool isNullable, object?defaultValue, EndpointParameterSource parameterSource, bool isArray) { return((parameterSource, isArray) switch { (EndpointParameterSource.Query, false) => GetParameterFactoryForQuery <T>(parameterName, parsable, allowNull, isNullable, defaultValue), (EndpointParameterSource.Query, true) => GetParameterFactoryForQueryArray <T>(parameterName, parsable), (EndpointParameterSource.Header, false) => GetParameterFactoryForHeader <T>(parameterName, parsable, allowNull, isNullable, defaultValue), (EndpointParameterSource.Header, true) => GetParameterFactoryForHeaderArray <T>(parameterName, parsable), (EndpointParameterSource.Route, false) => GetParameterFactoryForRoute <T>(parameterName, parsable), _ => throw new InvalidEndpointSetupException($"Cannot bind for {parameterSource} and IsArray {isArray}") });
private static SyncParameterFactory GetParameterFactory(string parameterName, Type type, bool allowNull, bool isNullable, object?defaultValue, EndpointParameterSource parameterSource, bool isArray, EndpointDeclarationFactoryOptions options) { if (type == typeof(string)) { return(GetParameterFactoryForStringValue(parameterName, defaultValue, parameterSource, isArray)); } if (!options.Parsers.TryGetParser(type, out var parser)) { throw new InvalidEndpointSetupException($"Could not parse route ({parameterName}), cannot parse {type}"); } #pragma warning disable S3011 // Reflection should not be used to increase accessibility of classes, methods, or fields var method = typeof(ParameterBinder).GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) .Single(w => w.Name == nameof(GetParameterFactory) && w.ContainsGenericParameters) .MakeGenericMethod(type); #pragma warning restore S3011 // Reflection should not be used to increase accessibility of classes, methods, or fields var result = (SyncParameterFactory)method.Invoke(null, new[] { parameterName, parser, allowNull, isNullable, defaultValue, parameterSource, isArray }) !; return(result); }
public static (SyncParameterFactory factory, EndpointParameterDescriptor[] info) GetParameterDeclaration(string parameterName, Type type, bool hasDefaultValue, object?defaultValue, EndpointParameterSource paramterSource, bool isArray, EndpointDeclarationFactoryOptions options) { if (IsComplex(type, options)) { return(ComplexParameterBinder.GetParameterDeclarationForClass(type, paramterSource, options)); } var parameterType = type; var allowNull = hasDefaultValue; var isNullable = false; if (!isArray && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>)) { isNullable = true; allowNull = true; if (!hasDefaultValue) { defaultValue = null; } parameterType = type.GetGenericArguments()[0]; } if (isArray) { allowNull = false; parameterType = type.GetElementType() !; } var parameterFactory = GetParameterFactory(parameterName, parameterType, allowNull, isNullable, defaultValue, paramterSource, isArray, options); return(parameterFactory, new[] { new EndpointParameterDescriptor(paramterSource, type, parameterName, allowNull) }); }