private async ValueTask HandleDeleteAsync(
            AuthorizationHandlerContext context,
            IQueryCollection query,
            CreatedByRequirement <T, TId, TCreatedBy> requirement)
        {
            var ids = query.Where(x => x.Key.StartsWith("ids[", InvariantCultureIgnoreCase) &&
                                  x.Key.EndsWith("]", InvariantCultureIgnoreCase));
            var converter     = GetConverter(typeof(TId));
            var keyValuePairs = ids.Select(id => (TId)converter.ConvertFromString(id.Value)).ToDictionary(id => id, id => default(T?));

            await HandleKeyValuePairsAsync(context, keyValuePairs, requirement).ConfigureAwait(false);
        }
        protected override Task HandleRequirementAsync(
            AuthorizationHandlerContext context,
            CreatedByRequirement <T, TId, TCreatedBy> requirement)
        {
            if (context == default)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (requirement == default)
            {
                throw new ArgumentNullException(nameof(requirement));
            }

            if (context.User.Identity?.IsAuthenticated != true)
            {
                return(CompletedTask);
            }

            if (requirement.AllowedRoles.Any(role => context.User.IsInRole(role)))
            {
                context.Succeed(requirement);
                return(CompletedTask);
            }

            if (!(context.Resource is ActionContext actionContext))
            {
                return(CompletedTask);
            }

            if (actionContext.RouteData.Values.ContainsKey("id"))
            {
                return(HandleByIdAsync(context, actionContext.RouteData.Values, requirement).AsTask());
            }

            if (IsPut(actionContext.HttpContext.Request.Method))
            {
                return(HandlePutAsync(context, actionContext.HttpContext.Request, requirement).AsTask());
            }

            if (IsDelete(actionContext.HttpContext.Request.Method))
            {
                return(HandleDeleteAsync(context, actionContext.HttpContext.Request.Query, requirement).AsTask());
            }

            return(CompletedTask);
        }
        private async ValueTask HandlePutAsync(
            AuthorizationHandlerContext context,
            HttpRequest request,
            CreatedByRequirement <T, TId, TCreatedBy> requirement)
        {
            ICollection <T> models;

            request.EnableBuffering();
            using (var reader = new StreamReader(request.Body, leaveOpen: true))
            {
                var body = await reader.ReadToEndAsync().ConfigureAwait(false);

                models = Deserialize <ICollection <T> >(body, _jsonSerializerOptions);
                request.Body.Position = 0;
            }

            var keyValuePairs = models.ToDictionary(model => model.Key, model => default(T?));

            await HandleKeyValuePairsAsync(context, keyValuePairs, requirement).ConfigureAwait(false);
        }
        private async ValueTask HandleKeyValuePairsAsync(
            AuthorizationHandlerContext context,
            IDictionary <TId, T?> keyValuePairs,
            CreatedByRequirement <T, TId, TCreatedBy> requirement)
        {
            var userId  = context.User.FindFirstValue(Sub);
            var allowed = await GetCachedModels(keyValuePairs, userId).ConfigureAwait(false);

            if (!allowed)
            {
                return;
            }

            allowed = await GetNonCachedModels(keyValuePairs, userId, requirement.Name).ConfigureAwait(false);

            if (!allowed)
            {
                return;
            }

            context.Succeed(requirement);
        }
        private async ValueTask HandleByIdAsync(
            AuthorizationHandlerContext context,
            RouteValueDictionary routeValues,
            CreatedByRequirement <T, TId, TCreatedBy> requirement)
        {
            var key = (TId)routeValues["id"];

            if (!_cache.TryGetValue(key, out T value))
            {
                var redisValue = await _database.StringGetAsync(key.ToString()).ConfigureAwait(false);

                if (redisValue.IsNullOrEmpty)
                {
                    var request = new GetRequest <T>(requirement.Name, new object[] { key }, _logger);
                    value = await _mediator.Send(request).ConfigureAwait(false);

                    if (value != default)
                    {
                        await _database.StringSetAsync(key.ToString(), Serialize(value), flags : FireAndForget).ConfigureAwait(false);
                    }
                }
                else
                {
                    value = Deserialize <T>(redisValue, _jsonSerializerOptions);
                }

                if (value != default)
                {
                    _cache.SetCacheEntry(key, value, _memoryCacheEntryOptions);
                }
            }

            var userId = context.User.FindFirstValue(Sub);

            if (value == default || string.Equals(value.CreatedBy.ToString(), userId, InvariantCultureIgnoreCase))
            {
                context.Succeed(requirement);
            }
        }