Beispiel #1
0
        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>();
 }
Beispiel #4
0
        /// <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));
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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));
        }
Beispiel #9
0
        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);
        }