public DocumentDbRepository(string slot, IOptionsMonitor <DocumentDbOptions> options, ISafeLogger <DocumentDbRepository <T> > logger) { _reads = ReadAccessor.Create(typeof(T)); _writes = WriteAccessor.Create(typeof(T)); _slot = slot; _options = options; _logger = logger; var defaultSettings = new JsonSerializerSettings(); var documentDbOptions = options.Get(_slot); _client = new DocumentClient(EndpointUri, documentDbOptions.AccountKey, defaultSettings); _client2 = new CosmosClient(EndpointUri.ToString(), documentDbOptions.AccountKey, new CosmosClientOptions { AllowBulkExecution = true, ConnectionMode = ConnectionMode.Gateway, MaxRetryAttemptsOnRateLimitedRequests = 100 }); CreateDatabaseIfNotExistsAsync().Wait(); CreateCollectionIfNotExistsAsync().Wait(); }
public JsonNextLinkConverter() { var collectionType = typeof(T); _reader = ReadAccessor.Create(collectionType, AccessorMemberTypes.Properties, AccessorMemberScope.Public, out _members); _writer = WriteAccessor.Create(collectionType, AccessorMemberTypes.Properties, AccessorMemberScope.Public); }
public JsonMergePatch(Type type) { _reads = ReadAccessor.Create(type, AccessorMemberTypes.Properties, AccessorMemberScope.Public, out _members); _writes = WriteAccessor.Create(type); _data = Activator.CreateInstance <T>(); _changed = new HashSet <string>(); }
/// <summary> /// Provides an <see cref="IdentityResult" /> in a failed state, with errors. /// This prevents an allocation by forcing the error collection to an array. /// </summary> /// <param name="errors"></param> /// <returns></returns> public static IdentityResult Failed(ICollection <IdentityError> errors) { var read = ReadAccessor.Create(typeof(IdentityResult)); var write = WriteAccessor.Create(typeof(IdentityResult)); var result = new IdentityResult(); var list = read[result, "_errors"] as List <IdentityError>; list?.AddRange(errors); write[result, "Succeeded"] = false; return(result); }
public void Fill <T>(T instance) { var writer = WriteAccessor.Create(instance, AccessorMemberScope.Public, out var members); foreach (var member in members) { if (!IsNumber(member)) { continue; } var value = _random.Next(int.MaxValue); writer.TrySetValue(instance, member.Name, value); } }
public bool TryUpdate(T previous, T next, out bool error, CancellationToken cancellationToken) { var accessor = WriteAccessor.Create(next, AccessorMemberTypes.Properties, AccessorMemberScope.Public, out var members); if (members == null || !members.TryGetValue(nameof(IResource.Id), out var idMember) || idMember.Type != typeof(Guid)) { throw new NotSupportedException(_localizer.GetString("Currently, the data store only accepts entries that have a Guid 'Id' property")); } if (!accessor.TrySetValue(next, nameof(IResource.Id), previous.Id)) { throw new NotSupportedException(_localizer.GetString("Could not set the resource's Guid 'Id' property")); } return(TryAdd(next, out error, cancellationToken)); }
public static object ToAnonymousObject(IDictionary <string, object> hash) { var anonymousType = TypeFactory.BuildAnonymousType(hash); var instance = Instancing.CreateInstance(anonymousType); var accessor = WriteAccessor.Create(anonymousType, AccessorMemberTypes.Properties, AccessorMemberScope.Public, out var members); foreach (var member in members) { if (!member.CanWrite) { continue; // should be accessible by design } if (!hash.TryGetValue(member.Name, out var value)) { continue; // should be mapped one-to-one } accessor.TrySetValue(instance, member.Name, value); } return(instance); }
public IActionResult Create([FromBody] T model, CancellationToken cancellationToken) { if (!TryValidateModel(model)) { return(BadRequest(ModelState)); } var uninitialized = model.Id.Equals(Guid.Empty); if (uninitialized) { if (_options.Value.Resources.RequireExplicitIds) { return(BadRequestWithDetails("The resource's ID was uninitialized.")); } else { var accessor = WriteAccessor.Create(model, AccessorMemberTypes.Properties, AccessorMemberScope.Public); if (!accessor.TrySetValue(model, nameof(IResource.Id), Guid.NewGuid())) { return(BadRequestWithDetails("The resource's ID was uninitialized, and the resource does not permit setting it.")); } } } // Save a database call if the server set the ID if (!uninitialized && _service.TryGetById(model.Id, out var other, out _, null, false, cancellationToken)) { if (other != null) { // FIXME: replace with a ValueHash var equivalent = true; var reads = ReadAccessor.Create(typeof(T), AccessorMemberTypes.Properties, AccessorMemberScope.Public, out var members); foreach (var member in members) { if (!member.CanRead) { continue; } if (!reads.TryGetValue(model, member.Name, out var left) || !reads.TryGetValue(other, member.Name, out var right) || !left.Equals(right)) { equivalent = false; break; } } if (equivalent) { // See: https://tools.ietf.org/html/rfc7231#section-4.3.3 // // If the result of processing a POST would be equivalent to a // representation of an existing resource, an origin server MAY redirect // the user agent to that resource by sending a 303 (See Other) response // with the existing resource's identifier in the Location field. This // has the benefits of providing the user agent a resource identifier // and transferring the representation via a method more amenable to // shared caching, though at the cost of an extra request if the user // agent does not already have the representation cached. // Response.Headers.TryAdd(HeaderNames.Location, $"{Request.Path}/{model.Id}"); return(SeeOtherWithDetails("This resource already exists. Did you mean to update it?")); } } Response.Headers.TryAdd(HeaderNames.Location, $"{Request.Path}/{model.Id}"); return(BadRequestWithDetails("This resource already exists. Did you mean to update it?")); } if (!BeforeSave(model, out var error)) { return(error ?? InternalServerErrorWithDetails("Internal error on BeforeSave")); } // // FIXME: The corner-case where we're creating but also have a pre-condition which should block this create operation. // It is unlikely to occur in real life, but technically we should know what the ETag is before we attempt this, // but the LastModifiedDate would always be 'now' since we're not expecting anything to exist. if (!_service.TryAdd(model, out _, cancellationToken)) { Logger.LogError(ErrorEvents.ErrorSavingResource, _localizer.GetString("Adding resource {Model} failed to save to the underlying data store."), model); return(InternalServerErrorWithDetails("An unexpected error occurred saving this resource. An error was logged. Please try again later.")); } _resourceEvents.Created(model); return(Created($"{Request.Path}/{model.Id}", model)); }
protected SimpleDataDescriptor(Type type) { Types = new[] { type }; ResolveTableInfo(this, type); All = new List <PropertyToColumn>(); Keys = new List <PropertyToColumn>(); Inserted = new List <PropertyToColumn>(); Updated = new List <PropertyToColumn>(); Computed = new List <PropertyToColumn>(); var reads = ReadAccessor.Create(type); var writes = WriteAccessor.Create(type); var descriptors = TypeDescriptor.GetProperties(type).Cast <PropertyDescriptor>(); var accessors = descriptors .Select(property => new PropertyAccessor(reads, writes, property.Name)) .ToList(); foreach (var property in accessors) { if (Exists(property) || property.HasAttribute <NotMappedAttribute>()) { continue; } var column = new PropertyToColumn(property); All.Add(column); if (property.HasAttribute <KeyAttribute>()) { column.IsKey = true; Keys.Add(column); } if (property.HasAttribute <OneToManyAttribute>()) { column.IsComputed = true; Computed.Add(column); } if (property.GetAttribute <DatabaseGeneratedAttribute>() is DatabaseGeneratedAttribute generated) { switch (generated.DatabaseGeneratedOption) { case DatabaseGeneratedOption.Computed: { column.IsComputed = true; Computed.Add(column); break; } case DatabaseGeneratedOption.Identity: { column.IsComputed = true; column.IsIdentity = true; Computed.Add(column); break; } case DatabaseGeneratedOption.None: { Inserted.Add(column); Updated.Add(column); break; } default: throw new ArgumentOutOfRangeException(); } } else { Inserted.Add(column); Updated.Add(column); } } if (Keys.Count == 0) { // try to add an exact match key var defaultKey = All.FirstOrDefault(x => x.ColumnName.Equals("Id", StringComparison.OrdinalIgnoreCase)); if (defaultKey != null) { Keys.Add(defaultKey); } } }
public JsonDeltaConverter() { _reader = ReadAccessor.Create(typeof(T), AccessorMemberTypes.Properties, AccessorMemberScope.Public, out _members); _writer = WriteAccessor.Create(typeof(T), AccessorMemberTypes.Properties, AccessorMemberScope.Public); }
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var writer = WriteAccessor.Create(typeToConvert, AccessorMemberTypes.Properties, AccessorMemberScope.Public, out var members); if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(); } var data = Activator.CreateInstance <T>(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) { return(data); // success: end of object } if (reader.TokenType != JsonTokenType.PropertyName) { throw new JsonException(); // fail: did not pass through previous property value } var key = reader.GetString(); if (string.IsNullOrWhiteSpace(key)) { continue; } var propertyName = options.PropertyNamingPolicy?.ConvertName(key); if (string.IsNullOrWhiteSpace(propertyName) || !members.TryGetValue(propertyName, out var member) || !member.CanWrite) { reader.Skip(); continue; } if (member.TryGetAttribute <ProtectedByPolicyAttribute>(out var attribute)) { var user = _http.ResolveCurrentPrincipal(); if (!user.Claims.Any()) { reader.Skip(); continue; } // resource is set to null here, because we don't want to deserialize the protected property unless we need to var result = _authorization.AuthorizeAsync(user, null, attribute.PolicyName).ConfigureAwait(false).GetAwaiter().GetResult(); if (!result.Succeeded) { reader.Skip(); continue; } } var value = JsonSerializer.Deserialize(ref reader, member.Type, options); if (!writer.TrySetValue(data, member.Name, value !)) { throw new JsonException(); } } // fail: passed through JsonTokenType.EndObject throw new JsonException(); }
public void ReadEntity(IDictionary <string, EntityProperty> properties, OperationContext operationContext) { var accessor = WriteAccessor.Create(_entity, AccessorMemberTypes.Properties, AccessorMemberScope.Public, out var members); foreach (var member in members) { if (ShouldSkipProperty(member, operationContext)) { continue; } if (!properties.ContainsKey(member.Name)) { _logger.LogInformation(FormatLine(operationContext, "Omitting property '{0}' from de-serialization because there is no corresponding entry in the dictionary provided.", member.Name)); continue; } var property = properties[member.Name]; if (property.PropertyAsObject == default) { accessor[_entity, member.Name] = default; } else { switch (property.PropertyType) { case EdmType.String: if (member.Type == typeof(double) || member.Type == typeof(double?)) { accessor[_entity, member.Name] = property.DoubleValue; } else if (member.Type != typeof(string)) { continue; } accessor[_entity, member.Name] = property.StringValue; continue; case EdmType.Binary: if (member.Type == typeof(byte[])) { accessor[_entity, member.Name] = property.BinaryValue; } continue; case EdmType.Boolean: if (member.Type == typeof(bool) || member.Type == typeof(bool?)) { accessor[_entity, member.Name] = property.BooleanValue; } continue; case EdmType.DateTime: if (member.Type == typeof(DateTime)) { accessor[_entity, member.Name] = property.DateTimeOffsetValue.GetValueOrDefault().UtcDateTime; continue; } if (member.Type == typeof(DateTime?)) { accessor[_entity, member.Name] = property.DateTimeOffsetValue?.UtcDateTime; continue; } if (member.Type == typeof(DateTimeOffset)) { accessor[_entity, member.Name] = property.DateTimeOffsetValue.GetValueOrDefault(); continue; } if (member.Type == typeof(DateTimeOffset?)) { accessor[_entity, member.Name] = property.DateTimeOffsetValue; } continue; case EdmType.Double: if (member.Type == typeof(double) || member.Type == typeof(double?)) { accessor[_entity, member.Name] = property.DoubleValue; } continue; case EdmType.Guid: if (member.Type == typeof(Guid) || member.Type == typeof(Guid?)) { accessor[_entity, member.Name] = property.GuidValue; } continue; case EdmType.Int32: if (member.Type == typeof(int) || member.Type == typeof(int?)) { accessor[_entity, member.Name] = property.Int32Value; } continue; case EdmType.Int64: if (member.Type == typeof(long) || member.Type == typeof(long?)) { accessor[_entity, member.Name] = property.Int64Value; } continue; default: continue; } } } }
private static void BindNonScalar(this IConfiguration configuration, ref object instance, BinderOptions options, IEnumerable <ICustomConfigurationBinder> customBinders) { if (instance == null) { return; } var scope = AccessorMemberScope.Public; if (options.BindNonPublicProperties) { scope |= AccessorMemberScope.Private; } var type = instance.GetType(); var read = ReadAccessor.Create(type, AccessorMemberTypes.Properties, scope, out var members); var write = WriteAccessor.Create(type, AccessorMemberTypes.Properties, scope); if (IsTypeDiscriminated(type, out _)) { // Set base properties so the converter has the right values to work with SetMembers(configuration, instance, options, members, read, write, customBinders); // Give a custom converter a chance to change what is bound var converter = TypeDescriptor.GetConverter(type); if (converter.CanConvertFrom(type)) { instance = converter.ConvertFrom(instance); if (instance != null) { type = instance.GetType(); read = ReadAccessor.Create(type, AccessorMemberTypes.Properties, scope, out members); write = WriteAccessor.Create(type, AccessorMemberTypes.Properties, scope); } } else { foreach (var binder in customBinders ?? Enumerable.Empty <ICustomConfigurationBinder>()) { if (!binder.CanConvertFrom(type)) { continue; } var subType = binder.GetTypeFor(instance); if (subType == null) { continue; } type = subType; instance = Instancing.CreateInstance(type); read = ReadAccessor.Create(type, AccessorMemberTypes.Properties, scope, out members); write = WriteAccessor.Create(type, AccessorMemberTypes.Properties, scope); goto setMembers; } } } setMembers: SetMembers(configuration, instance, options, members, read, write, customBinders); }