public static bool FeatureEnabled <TFeature, TOptions>(this IServiceProvider serviceProvider, out TFeature feature) where TFeature : class, IFeatureToggle where TOptions : class, new() { var options = serviceProvider.GetService(typeof(IOptionsMonitor <TOptions>)); if (!(options is IOptionsMonitor <TOptions> o)) { feature = default; return(false); } var type = o.CurrentValue.GetType(); var members = AccessorMembers.Create(type, AccessorMemberTypes.Properties, AccessorMemberScope.Public); var featureType = members.SingleOrDefault(x => x.Type == typeof(TFeature)); if (featureType == null) { feature = default; return(false); } var accessor = ReadAccessor.Create(type); feature = accessor[o.CurrentValue, featureType.Name] as TFeature; return(feature != null && feature.Enabled); }
public Type GetTypeFor(object instance) { var baseType = instance.GetType(); var members = AccessorMembers.Create(baseType, AccessorMemberTypes.Properties, AccessorMemberScope.Public); if (!members.TryGetValue("Type", out _)) { return(baseType); // no type discriminator } if (!IsTypeDiscriminated(baseType, out var subTypes)) { return(baseType); // no matching subTypes } var read = ReadAccessor.Create(instance, AccessorMemberTypes.Properties, AccessorMemberScope.Public); var typeKey = read[instance, "Type"]?.ToString(); if (string.IsNullOrWhiteSpace(typeKey)) { return(baseType); // missing type discriminant } var subType = subTypes.SingleOrDefault(x => x.Name == typeKey) ?? subTypes.SingleOrDefault(x => x.Name == $"{typeKey}{baseType.Name}"); if (subType == null) { return(baseType); // sub-type error } return(subType); }
public static List <Error> MustExistOnType <T>(FuncEnumerable <T, string> fields) { var type = typeof(T); var list = new List <Error>(); foreach (var field in fields) { var valid = false; foreach (var member in AccessorMembers.Create(type)) { if (field.Equals(member.Name, StringComparison.OrdinalIgnoreCase)) { valid = true; } } if (!valid) { list.Add(new Error(ErrorEvents.FieldDoesNotMatch, string.Format(ErrorStrings.FieldToPropertyMismatch, field, type.Name), HttpStatusCode.BadRequest)); } } return(list); }
public static string GetHeaderText <TMetadata>(string separator) { return(Pooling.StringBuilderPool.Scoped(sb => { var members = AccessorMembers.Create(typeof(TMetadata), AccessorMemberTypes.Fields, AccessorMemberScope.Public); // FIXME: convert to zero-alloc var columns = members .Where(x => x.HasAttribute <ColumnAttribute>()) .OrderBy(x => x.TryGetAttribute(out ColumnAttribute column) ? -1 : column.Order) .ToArray(); var i = 0; foreach (var member in columns) { member.TryGetAttribute(out ColumnAttribute column); member.TryGetAttribute(out DisplayAttribute display); var name = display?.Name ?? column.Name ?? member.Name; sb.Append(name); i++; if (i < columns.Length) { sb.Append(separator); } } })); }
public override async Task OnValidRequestAsync(Type underlyingType, StringValues clauses, ActionExecutingContext context, ActionExecutionDelegate next) { var members = AccessorMembers.Create(underlyingType, AccessorMemberTypes.Fields | AccessorMemberTypes.Properties, AccessorMemberScope.Public); // FIXME: add attribute for model ID discriminator, or fail due to missing "Id" if (!members.TryGetValue("Id", out _)) { _logger.LogWarning(_localizer.GetString("Sorting operation was skipped, because the underlying resource does not have an 'Id' property.")); await next.Invoke(); return; } // FIXME: avoid allocation here? var sortMap = new List <(AccessorMember, SortDirection)>(clauses.Count); foreach (var value in clauses) { var tokens = value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (tokens.Length == 0) { continue; // (FIXME: add a validation error?) } var clause = tokens[0]; var name = clause[(clause.IndexOf('=', StringComparison.Ordinal) + 1)..];
public void Apply(OpenApiSchema schema, SchemaFilterContext context) { DocumentXmlSchemas(schema, context); if (!typeof(IResource).IsAssignableFrom(context.Type)) { return; } foreach (var member in AccessorMembers.Create(context.Type, AccessorMemberTypes.Properties, AccessorMemberScope.Public)) { if (!member.TryGetAttribute <ProtectedByPolicyAttribute>(out var attribute)) { continue; } var user = _http.ResolveCurrentPrincipal(); if (!user.Claims.Any() || !_authorization.AuthorizeAsync(user, null, attribute.PolicyName) .ConfigureAwait(false).GetAwaiter().GetResult().Succeeded) { var propertyName = char.ToLowerInvariant(member.Name[0]) + member.Name.Substring(1); schema.Properties.Remove(propertyName); } } if (_builder.TryGetResourceNameForType(context.Type, out var name)) { schema.Title = name; } }
public static bool FeatureEnabled <TFeature, TOptions>(this IServiceProvider serviceProvider, out TFeature feature) where TFeature : FeatureToggle where TOptions : class, new() { var options = serviceProvider.GetService(typeof(IOptions <TOptions>)); if (!(options is IOptions <TOptions> o)) { feature = default; return(false); } var featureType = AccessorMembers.Create(o.Value.GetType()).SingleOrDefault(x => x.Type == typeof(TFeature)); if (featureType == null) { feature = default; return(false); } var accessor = ReadAccessor.Create(featureType.Type); feature = accessor[o.Value, featureType.Name] as TFeature; return(feature != null && feature.Enabled); }
public async Task <Operation <ulong> > CountAsync(Type type, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); var members = AccessorMembers.Create(type, AccessorMemberTypes.Properties, AccessorMemberScope.Public); return(await members.CountAsync(_dialect, _connectionString, cancellationToken)); }
public Prototype(TInterface parent, object child) { _parent = parent; _child = child; _memberNames = AccessorMembers.Create(typeof(TInterface)).Select(x => x.Name) .Concat(typeof(TInterface).GetMethods().Select(x => x.Name)) .ToImmutableHashSet(); }
private static ResourceQuery DeserializeResourceQuery(byte[] buffer) { var query = new ResourceQuery(); var ms = new MemoryStream(buffer); var br = new BinaryReader(ms); query.PageOffset = br.ReadNullableInt32(); query.PageSize = br.ReadNullableInt32(); query.MaxPageSize = br.ReadNullableInt32(); query.CountTotalRows = br.ReadBoolean(); query.TotalRows = br.ReadNullableInt32(); if (br.ReadBoolean()) { var fields = br.ReadInt32(); query.Fields = new List <string>(fields); for (var i = 0; i < fields; i++) { query.Fields.Add(br.ReadString()); } } if (br.ReadBoolean()) { var sorts = br.ReadInt32(); query.Sorting = new List <(AccessorMember, SortDirection)>(sorts); for (var i = 0; i < sorts; i++) { var declaringTypeName = br.ReadNullableString(); if (declaringTypeName != null) { var declaringType = Type.GetType(declaringTypeName); var memberName = br.ReadString(); var direction = (SortDirection)br.ReadByte(); if (declaringType == null) { continue; } var members = AccessorMembers.Create(declaringType, AccessorMemberTypes.Properties, AccessorMemberScope.Public); if (members.TryGetValue(memberName, out var member)) { query.Sorting.Add((member, direction)); } } } } return(query); }
public static IEnumerable <T> StreamFrame <T>(string filePath, bool reuseRowObject = false) where T : class, new() { // We need to be explicit here because the CSV reader will guess at primitives like `float` when `double` is defined in the mode. var members = AccessorMembers.Create(typeof(T), AccessorMemberTypes.Fields | AccessorMemberTypes.Properties, AccessorMemberScope.Public); var inputFrame = DataFrame.ReadCsv(filePath, columnNames: members.Names.ToArray(), dataTypes: members.Select(x => x.Type).ToArray()); var context = new MLContext(); var enumerable = context.Data.CreateEnumerable <T>(inputFrame, reuseRowObject); return(enumerable); }
public PropertyAccessor(ITypeReadAccessor reads, ITypeWriteAccessor writes, string name) { var members = AccessorMembers.Create(reads.Type, AccessorMemberTypes.Properties); Info = members.PropertyInfo.Single(m => m.Name == name); Type = Info.PropertyType; Name = name; _reads = reads; _writes = writes; }
public static async Task <Operation <TShape> > QueryOneByExampleAsync <TShape>(this ISqlDialect dialect, object example, Func <ISqlDialect, string, IReadOnlyDictionary <string, object>, CancellationToken, Task <TShape> > queryFunc, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); var members = AccessorMembers.Create(example, AccessorMemberTypes.Properties, AccessorMemberScope.Public); var hash = members.ToHash(example); var sql = dialect.Select(members, hash); var parameters = hash.ToDictionary(k => $"{dialect.Parameter}{dialect.ResolveColumnName(k.Key)}", v => hash[v.Key]); var result = await queryFunc(dialect, sql, parameters, cancellationToken); return(new Operation <TShape> { Data = result }); }
static JsonDeltaConverter() { var delta = AccessorMembers.Create(typeof(DeltaAnnotated <T>), AccessorMemberTypes.Properties, AccessorMemberScope.Public) ?? throw new InvalidOperationException(); if (!delta.TryGetValue(nameof(DeltaAnnotated <T> .DeltaLink), out var deltaLink)) { throw new InvalidOperationException(); } if (!deltaLink.TryGetAttribute <JsonPropertyNameAttribute>(out var attribute)) { throw new InvalidOperationException(); } DeltaLinkName = attribute.Name; }
static JsonNextLinkConverter() { var page = AccessorMembers.Create(typeof(NextLinkAnnotated <T>), AccessorMemberTypes.Properties, AccessorMemberScope.Public) ?? throw new InvalidOperationException(); if (!page.TryGetValue(nameof(NextLinkAnnotated <T> .NextLink), out var nextLink)) { throw new InvalidOperationException(); } if (!nextLink.TryGetAttribute <JsonPropertyNameAttribute>(out var attribute)) { throw new InvalidOperationException(); } NextLinkName = attribute.Name; }
public IActionResult GetEmbedded(ApiVersion apiVersion, Guid id, string embeddedCollectionName, CancellationToken cancellationToken) { var members = AccessorMembers.Create(typeof(T), AccessorMemberTypes.Properties, AccessorMemberScope.Public); foreach (var member in members) { if (!member.Type.ImplementsGeneric(typeof(IEnumerable <>)) || !member.Type.IsGenericType) { continue; // not a collection } var arguments = member.Type.GetGenericArguments(); var embeddedCollectionType = arguments[0]; if (!typeof(IResource).IsAssignableFrom(embeddedCollectionType)) { continue; // not a resource collection } if (!_changeLog.TryGetResourceNameForType(embeddedCollectionType, out var name)) { name = embeddedCollectionType.Name; } if (!embeddedCollectionName.Equals(name.Pluralize(), StringComparison.OrdinalIgnoreCase)) { return(NotFound()); } var controllerType = typeof(ResourceController <>).MakeGenericType(embeddedCollectionType); if (!(HttpContext.RequestServices.GetService(controllerType) is IResourceController controller)) { return(NotFound()); } if (controller is Controller mvcController) { mvcController.ControllerContext = new ControllerContext(ControllerContext); } // FIXME: implement filters and add parent ID in the filter return(controller.Get(apiVersion, cancellationToken)); } // this is a generic 404, to avoid leaking mappings return(NotFound()); }
private void MaybeCacheObject(ActionExecutedContext context) { if (!(context.Result is OkObjectResult result)) { return; } var body = result.Value; var cacheKey = context.HttpContext.Request.GetDisplayUrl(); var json = JsonSerializer.Serialize(body, _options); var etag = _generator.GenerateFromBuffer(Encoding.UTF8.GetBytes(json)); context.HttpContext.Response.Headers.Add(HeaderNames.ETag, new[] { etag }); _cache.Save(cacheKey, etag); var members = AccessorMembers.Create(body, AccessorMemberTypes.Properties, AccessorMemberScope.Public); foreach (var member in members) { if (member.HasAttribute <CacheTimestampAttribute>()) { var accessor = ReadAccessor.Create(body); if (accessor.TryGetValue(body, member.Name, out var lastModifiedDate)) { switch (lastModifiedDate) { case DateTimeOffset timestamp: context.HttpContext.Response.Headers.Add(HeaderNames.LastModified, timestamp.ToString("R")); _cache.Save(cacheKey, timestamp); break; case DateTime timestamp: context.HttpContext.Response.Headers.Add(HeaderNames.LastModified, timestamp.ToString("R")); _cache.Save(cacheKey, timestamp); break; } } } } }
public async Task <Operation <IEnumerable <T> > > FetchAsync <T>(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); try { var members = AccessorMembers.Create(typeof(T), AccessorMemberTypes.Properties, AccessorMemberScope.Public); var result = await members.SelectAsync <T>(_dialect, _connectionString, cancellationToken : cancellationToken); return(Operation.FromResult(result)); } catch (StorageException e) { return(Operation.FromResult(Enumerable.Empty <T>(), new List <Error> { new Error(ErrorEvents.AggregateErrors, e.Message) })); } }
public async Task <Operation <ObjectAppend> > CreateAsync(object @object, CancellationToken cancellationToken = default, params string[] fields) { cancellationToken.ThrowIfCancellationRequested(); try { var members = AccessorMembers.Create(@object, AccessorMemberTypes.Properties, AccessorMemberScope.Public); var hash = members.ToHash(@object, fields, _provider, _transforms); await members.InsertAsync(_dialect, _connectionString, hash, cancellationToken); return(Operation.FromResult(ObjectAppend.Created)); } catch (StorageException e) { return(Operation.FromResult(ObjectAppend.Error, new List <Error> { new Error(ErrorEvents.AggregateErrors, e.Message) })); } }
public PropertyAccessor(ITypeReadAccessor reads, ITypeWriteAccessor writes, Type type, string name) { Type = type; Name = name; _reads = reads; _writes = writes; var members = AccessorMembers.Create(type); Info = members.PropertyInfo.SingleOrDefault(m => m.Name == name); var member = members.SingleOrDefault(p => p.Name == name); if (member == null) { return; } _member = member; }
internal static Type GetPropertyTypeFromPath(Type type, string path, IContractResolver contractResolver) { var currentType = type; var currentMembers = AccessorMembers.Create(type, AccessorMemberTypes.Fields | AccessorMemberTypes.Properties, AccessorMemberScope.Public); foreach (var propertyName in path.Split(pathSplitter, StringSplitOptions.RemoveEmptyEntries)) { var jsonContract = contractResolver.ResolveContract(currentType); if (jsonContract is JsonDictionaryContract jsonDictionaryContract) { currentType = jsonDictionaryContract.DictionaryValueType; continue; } if (currentMembers.TryGetValue(propertyName, out var member)) { currentType = member.Type; } } return(currentType); }
private void DocumentSchemas(OperationFilterContext context) { // This will run multiple times, so we store previously discovered types foreach (var(typeName, schema) in context.SchemaRepository.Schemas) { if (!_registry.GetOrRegisterByName(typeName, out var type) || type == default) { continue; } var members = AccessorMembers.Create(type, AccessorMemberTypes.Properties, AccessorMemberScope.Public); foreach (var(propertyName, property) in schema.Properties) { if (!members.TryGetValue(propertyName, out var member)) { continue; } if (!member.TryGetAttribute(out DisplayAttribute attribute)) { continue; } var description = attribute.GetDescription(); if (!string.IsNullOrWhiteSpace(description)) { property.Description = _localizer.GetString(description); } var prompt = attribute.GetPrompt(); if (!string.IsNullOrWhiteSpace(prompt)) { property.Example = new OpenApiString(_localizer.GetString(prompt)); } } } }
private void ValidateTypeExistsInChangeLog(string resourceName, ApiVersion version, Type type, IReadOnlySet <Type> typesToSearch, bool addMissingResources = true) { if (!typesToSearch.Contains(type)) { if (addMissingResources) { AddMissingResource(version, type); } else { // FIXME: localize var message = string.Format("Resource '{0}' binds type '{1}', but this type was not found in the change log. Did you forget to add it?", resourceName, type.Name); throw new ChangeLogException(message); } } var members = AccessorMembers.Create(type, AccessorMemberTypes.Properties, AccessorMemberScope.Public); foreach (var member in members) { if (typeof(IResource).IsAssignableFrom(member.Type)) { ValidateTypeExistsInChangeLog(resourceName, version, member.Type, typesToSearch, addMissingResources); } if (member.Type.ImplementsGeneric(typeof(IEnumerable <>)) && member.Type.IsGenericType) { var arguments = member.Type.GetGenericArguments(); var underlyingType = arguments[0]; if (typeof(IResource).IsAssignableFrom(underlyingType)) { ValidateTypeExistsInChangeLog(resourceName, version, underlyingType, typesToSearch, addMissingResources); } } } }
public bool CanConvertFrom(Type type) { var members = AccessorMembers.Create(type, AccessorMemberTypes.Properties, AccessorMemberScope.Public); return(members.TryGetValue("Type", out _)); }
public override ValueTask <RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values) { const string routeKey = "route"; if (!values.TryGetValue(routeKey, out var route) || !(route is string routeValue) || string.IsNullOrWhiteSpace(routeValue)) { return(new ValueTask <RouteValueDictionary>(values)); } values.Remove(routeKey); var components = httpContext.RequestServices.GetServices <IDynamicFeature>(); foreach (var component in components) { if (component.GetRouteTemplate == null) { continue; } var prefix = component.GetRouteTemplate(); if (prefix.StartsWith('/')) { prefix = prefix.Substring(1); } if (!routeValue.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { continue; } var action = prefix == string.Empty? routeValue : routeValue.Replace($"{prefix}/", string.Empty); foreach (var controllerType in component.ControllerTypes) { if (!IsValidForRequest(controllerType, httpContext)) { continue; } var methods = AccessorMembers.Create(controllerType, AccessorMemberTypes.Methods, AccessorMemberScope.Public); foreach (var method in methods) { foreach (var attribute in method.Attributes) { if (attribute is NonActionAttribute) { continue; } if (!(attribute is DynamicHttpMethodAttribute httpMethod)) { continue; } if (!httpMethod.HttpMethods.Contains(httpContext.Request.Method, StringComparer.OrdinalIgnoreCase)) { continue; } var template = GetHttpTemplate(httpMethod, method); if (template == string.Empty) { template = prefix; } if (!IsMatch(template, $"/{action}", httpContext, method, out var extraValues)) { continue; } values["controller"] = ResolveControllerName(controllerType); values["action"] = ResolveActionName(method); if (extraValues != null && extraValues.Count > 0) { foreach (var(k, v) in extraValues) { values[k] = v; } } return(new ValueTask <RouteValueDictionary>(values)); } } } } return(NotFound(values)); }
public override async Task OnValidRequestAsync(Type underlyingType, StringValues clauses, ActionExecutingContext context, ActionExecutionDelegate next) { var members = AccessorMembers.Create(underlyingType, AccessorMemberTypes.Properties, AccessorMemberScope.Public); var inclusions = new List <string>(); foreach (var value in clauses) { var fields = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (fields.Length == 0) { continue; // (FIXME: add a validation error?) } foreach (var field in fields) { if (!members.TryGetValue(field, out var member) || inclusions.Contains(member.Name)) { continue; } inclusions.Add(member.Name); } } if (inclusions.Count == 0) { await next.Invoke(); return; } context.HttpContext.Items.TryAdd(Constants.ShapingOperationContextKey, inclusions); var executed = await next.Invoke(); if (executed.HttpContext.Items.ContainsKey(Constants.ShapingOperationContextKey)) { executed.HttpContext.Items.Remove(Constants.ShapingOperationContextKey); _logger.LogWarning(_localizer.GetString("Shaping operation has fallen back to object-level shaping. " + "This means that shaping was not performed by the underlying data store, and is likely " + "performing excessive work to return discarded values.")); } if (executed.Result is ObjectResult result && !(result.Value is ProblemDetails)) { var body = executed.GetResultBody(result, out var settable); if (settable) { if (body.GetType().ImplementsGeneric(typeof(IEnumerable <>))) { underlyingType = typeof(IEnumerable <>).MakeGenericType(underlyingType); } var shapingType = typeof(ShapedData <>).MakeGenericType(underlyingType); var shaped = Activator.CreateInstance(shapingType, body, inclusions); result.Value = shaped; } } }
private static void TryMapType(Type type, IDictionary <Type, List <MemberInfo> > map) { if (type == null) { return; } if (type.IsArray) { TryMapType(type.GetElementType(), map); return; } if (Filtered(type)) { return; } if (!map.TryGetValue(type, out var list)) { map.Add(type, list = new List <MemberInfo>()); } foreach (var member in AccessorMembers.Create(type, AccessorMemberScope.Public)) { switch (member.MemberType) { case AccessorMemberType.Property: { if (!map.ContainsKey(member.Type)) { TryMapType(member.Type, map); } list.Add(member.MemberInfo); break; } case AccessorMemberType.Field: { if (!map.ContainsKey(member.Type)) { TryMapType(member.Type, map); } list.Add(member.MemberInfo); break; } case AccessorMemberType.Method: { list.Add(member.MemberInfo); if (member.MemberInfo is MethodInfo method) { foreach (var parameter in method.GetParameters()) { if (!map.ContainsKey(parameter.ParameterType)) { TryMapType(parameter.ParameterType, map); } } } break; } default: throw new ArgumentOutOfRangeException(); } } }
private static void ScanMembersForAttributes(Type callerType, IDictionary <string, List <string> > translations) { foreach (var member in AccessorMembers.Create(callerType, AccessorMemberTypes.Properties, AccessorMemberScope.Public)) { if (member.TryGetAttribute(out DisplayAttribute display)) { var scope = callerType.Name; if (!translations.TryGetValue(scope, out var list)) { translations.Add(scope, list = new List <string>()); } var description = display.Description; if (!string.IsNullOrWhiteSpace(description)) { list.Add(description); } var prompt = display.Prompt; if (!string.IsNullOrWhiteSpace(prompt)) { list.Add(prompt); } var name = display.Name; if (!string.IsNullOrWhiteSpace(name)) { list.Add(name); } var groupName = display.GroupName; if (!string.IsNullOrWhiteSpace(groupName)) { list.Add(groupName); } } if (member.TryGetAttribute(out OneOfAttribute oneOf)) { var scope = callerType.Name; if (!translations.TryGetValue(scope, out var list)) { translations.Add(scope, list = new List <string>()); } if (!string.IsNullOrWhiteSpace(oneOf.ErrorMessage)) { list.Add(oneOf.ErrorMessage); } foreach (var value in oneOf.OneOfStrings) { if (!string.IsNullOrWhiteSpace(value)) { list.Add(value); } } } } }
public IEnumerable <AccessorMembers> GetMigrationSubjects() { yield return(AccessorMembers.Create( typeof(LogEntry), AccessorMemberTypes.Properties, AccessorMemberScope.Public)); }
public static string ToTable <T>(this IEnumerable <T> values) { return(ToTable(values, AccessorMembers.Create(typeof(T), AccessorMemberTypes.Fields | AccessorMemberTypes.Properties, AccessorMemberScope.Public).Names.ToArray())); }