示例#1
0
        public void ShouldCallImplementedInterfaceMethod()
        {
            var random = new Random();

            for (int i = 0; i < 100; i++)
            {
                var interceptor1 = new Interceptor1();
                var interceptor2 = new Interceptor2();
                var interceptor3 = new Interceptor3();
                var interceptor4 = new Interceptor4();

                var interceptors = new IResponseCachingInterceptor[] { interceptor1, interceptor2, interceptor3, interceptor4 };

                //随机组合进行测试
                interceptors = interceptors.OrderBy(_ => random.Next()).ToArray();

                Console.WriteLine($"time: {i:D3} - order:{string.Join(" -> ", interceptors.Select(m => m.GetType().Name))}");

                var interceptorAggregator = new InterceptorAggregator(interceptors);

                interceptorAggregator.OnCacheStoringAsync(null, null, null, (_, _, _) => Task.FromResult <ResponseCacheEntry>(null));
                interceptorAggregator.OnResponseWritingAsync(null, null, (_, _) => Task.FromResult(true));

                NormalCheck(interceptors);
            }
        }
示例#2
0
                // Local function that creates and assigns the compiled setter
                static void SetInterceptorsSetter(InterceptorAggregator <TInterceptor> theAggregator)
                {
                    lock (Lock)
                    {
                        if (InterceptorsSetter != null)
                        {
                            return;
                        }

                        try
                        {
                            var aggregatorBaseType = theAggregator.GetType().BaseType !;

                            // Null out the field, which AggregateInterceptors() does not handle for us (because it does not expect reinitialization)
                            var interceptorField = aggregatorBaseType.GetField("_interceptor", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) ??
                                                   throw new Exception($"Field {aggregatorBaseType.Name}._interceptor does not exist.");

                            var resolvedField = aggregatorBaseType.GetField("_resolved", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) ??
                                                throw new Exception($"Field {aggregatorBaseType.Name}._resolved does not exist.");

                            // Compile a fast expression tree
                            // Omit the checks, trusting that things will be the same in the future
                            {
                                var aggregateInterceptorsMethod = typeof(IInterceptorAggregator).GetMethod(nameof(IInterceptorAggregator.AggregateInterceptors)) ??
                                                                  throw new Exception($"Type {nameof(IInterceptorAggregator)} does not have a single public method named {nameof(IInterceptorAggregator.AggregateInterceptors)}.");

                                // InterceptorAggregator<TInterceptor> aggregator;
                                var aggregatorParam = Expression.Parameter(typeof(InterceptorAggregator <TInterceptor>), "aggregator");
                                // TInterceptor[] interceptors;
                                var interceptorsParam = Expression.Parameter(typeof(TInterceptor[]), "interceptors");
                                // SomeCustomAggregator theAggregator;
                                var convertedAggregatorVariable = Expression.Variable(aggregatorBaseType, "theAggregator");
                                // theAggregator = (SomeCustomAggregator)aggregator;
                                var aggregatorVariableAssignment = Expression.Assign(convertedAggregatorVariable, Expression.Convert(aggregatorParam, aggregatorBaseType));
                                // theAggregator._interceptor = null;
                                var interceptorFieldExpression = Expression.Field(convertedAggregatorVariable, interceptorField);
                                var setInterceptors            = Expression.Assign(interceptorFieldExpression, Expression.Constant(null, interceptorField.FieldType));
                                // theAggregator._resolved = false;
                                var resolvedFieldExpression = Expression.Field(convertedAggregatorVariable, resolvedField);
                                var setResolved             = Expression.Assign(resolvedFieldExpression, Expression.Constant(false));
                                // theAggregator.AggregateInterceptors(interceptors);
                                var callAggregateInterceptors = Expression.Call(convertedAggregatorVariable, aggregateInterceptorsMethod, interceptorsParam);
                                // Block(theAggregator):
                                // theAggregator = (SomeCustomAggregator)aggregator;
                                // theAggregator._interceptor = null;
                                // theAggregator._resolved = false;
                                // theAggregator.AggregateInterceptors(interceptors);
                                var blockExpression = Expression.Block(variables: new[] { convertedAggregatorVariable }, aggregatorVariableAssignment,
                                                                       setInterceptors, setResolved, callAggregateInterceptors);

                                var lambda = Expression.Lambda <Action <InterceptorAggregator <TInterceptor>, TInterceptor[]> >(blockExpression, aggregatorParam, interceptorsParam);
                                InterceptorsSetter = lambda.Compile();
                            }
                        }
                        catch (Exception e)
                        {
                            throw ThrowHelper.ThrowIncompatibleWithEfVersion(e);
                        }
                    }
                }
示例#3
0
            public static void SetInterceptors(InterceptorAggregator <TInterceptor> aggregator, TInterceptor[] interceptors)
            {
                System.Diagnostics.Debug.Assert(aggregator != null);

                if (InterceptorsSetter is null)
                {
                    SetInterceptorsSetter(aggregator);
                }

                System.Diagnostics.Debug.Assert(InterceptorsSetter != null);

                InterceptorsSetter(aggregator, interceptors);
示例#4
0
        public void ShouldShortCircuits()
        {
            var random = new Random();

            for (int i = 0; i < 100; i++)
            {
                var interceptor1             = new Interceptor1();
                var interceptor2             = new Interceptor2();
                var interceptor3             = new Interceptor3();
                var interceptor4             = new Interceptor4();
                var shortCircuitsInterceptor = new ShortCircuitsInterceptor();

                var interceptors = new IResponseCachingInterceptor[] { interceptor1, interceptor2, interceptor3, interceptor4, shortCircuitsInterceptor };

                //随机组合进行测试
                interceptors = interceptors.OrderBy(_ => random.Next()).ToArray();

                Console.WriteLine($"time: {i:D3} - order:{string.Join(" -> ", interceptors.Select(m => m.GetType().Name))}");

                var interceptorAggregator = new InterceptorAggregator(interceptors);

                interceptorAggregator.OnCacheStoringAsync(null, null, null, (_, _, _) => Task.FromResult <ResponseCacheEntry>(null));
                interceptorAggregator.OnResponseWritingAsync(null, null, (_, _) => Task.FromResult(true));

                bool shortCircuited = false;
                foreach (var interceptor in interceptors)
                {
                    if (shortCircuited)
                    {
                        ShouldNoAnyCalled(interceptor);
                    }
                    else
                    {
                        NormalCheck(interceptor);
                        shortCircuited = interceptor is ShortCircuitsInterceptor;
                    }
                }
            }
        }
        /// <summary>
        /// <inheritdoc cref="ResponseCachingContext"/>
        /// </summary>
        /// <param name="metadatas">Action端点的 <see cref="EndpointMetadataCollection"/></param>
        /// <param name="cacheKeyGenerator"></param>
        /// <param name="responseCache"></param>
        /// <param name="cacheDeterminer"></param>
        /// <param name="options"></param>
        /// <param name="interceptorAggregator"></param>
        /// <param name="dumpStreamCapacity"></param>
        public ResponseCachingContext(EndpointMetadataCollection metadatas,
                                      ICacheKeyGenerator cacheKeyGenerator,
                                      IResponseCache responseCache,
                                      IResponseCacheDeterminer cacheDeterminer,
                                      ResponseCachingOptions options,
                                      InterceptorAggregator interceptorAggregator,
                                      int dumpStreamCapacity)
        {
            if (metadatas is null)
            {
                throw new ArgumentNullException(nameof(metadatas));
            }

            MaxCacheableResponseLength = Checks.ThrowIfMaxCacheableResponseLengthTooSmall(Metadata <IMaxCacheableResponseLengthMetadata>()?.MaxCacheableResponseLength ?? options.MaxCacheableResponseLength);

            MaxCacheKeyLength = options.MaxCacheKeyLength;

            KeyGenerator         = cacheKeyGenerator ?? throw new ArgumentNullException(nameof(cacheKeyGenerator));
            ResponseCache        = responseCache ?? throw new ArgumentNullException(nameof(responseCache));
            CacheDeterminer      = cacheDeterminer ?? throw new ArgumentNullException(nameof(cacheDeterminer));
            Duration             = Checks.ThrowIfDurationTooSmall(RequiredMetadata <IResponseDurationMetadata>().Duration);
            DurationMilliseconds = Duration * 1000;

            var executingLockMetadata = Metadata <IExecutingLockMetadata>();

            LockMillisecondsTimeout = Checks.ThrowIfLockMillisecondsTimeoutInvalid(executingLockMetadata?.LockMillisecondsTimeout ?? options.DefaultLockMillisecondsTimeout).Value;

            Interceptors       = interceptorAggregator;
            DumpStreamCapacity = Checks.ThrowIfDumpStreamInitialCapacityTooSmall(dumpStreamCapacity, nameof(dumpStreamCapacity));

            OnCannotExecutionThroughLock = options.OnCannotExecutionThroughLock ?? DefaultExecutionLockTimeoutFallback.SetStatus429;
            OnExecutionLockTimeout       = executingLockMetadata?.OnExecutionLockTimeout
                                           ?? options.OnExecutionLockTimeoutFallback
                                           ?? DefaultExecutionLockTimeoutFallback.SetStatus429;

            TMetadata?Metadata <TMetadata>() where TMetadata : class => metadatas.GetMetadata <TMetadata>();
        /// <inheritdoc/>
        public IFilterMetadata CreateFilter(IServiceProvider serviceProvider)
        {
            if (serviceProvider is null)
            {
                throw new ArgumentNullException(nameof(serviceProvider));
            }

            var endpointAccessor = serviceProvider.GetRequiredService <IEndpointAccessor>();

            var buildContext = new FilterBuildContext(serviceProvider, endpointAccessor);

            if (!buildContext.Options.Enable)
            {
                return(EmptyFilterMetadata.Instance);
            }

            IResponseCache responseCache = GetResponseCache(buildContext);

            ICacheKeyGenerator cacheKeyGenerator = TryGetCustomCacheKeyGenerator(buildContext, out FilterType filterType)
                                                   ?? CreateCacheKeyGenerator(buildContext, out filterType);

            var cacheDeterminer = serviceProvider.GetRequiredService <IResponseCacheDeterminer>();

            var cachingDiagnosticsAccessor = serviceProvider.GetRequiredService <CachingDiagnosticsAccessor>();

            var interceptorAggregator = new InterceptorAggregator(GetCachingProcessInterceptor(buildContext));

            var lockMode = buildContext.GetMetadata <IExecutingLockMetadata>()?.LockMode ?? buildContext.Options.DefaultExecutingLockMode;

            lockMode = Checks.ThrowIfExecutingLockModeIsNone(lockMode);

            var dumpStreamCapacity = buildContext.GetMetadata <IDumpStreamInitialCapacityMetadata>()?.Capacity
                                     ?? ResponseCachingConstants.DefaultDumpCapacity;

            Checks.ThrowIfDumpStreamInitialCapacityTooSmall(dumpStreamCapacity, nameof(dumpStreamCapacity));

            Debug.WriteLine("FilterType {0} for endpoint {1}", filterType, endpointAccessor);

            var executingLockPool = lockMode switch
            {
                ExecutingLockMode.ActionSingle => CreateSharedExecutingLockPool(serviceProvider),
                ExecutingLockMode.CacheKeySingle => CreateExclusiveExecutingLock(serviceProvider),
                _ => null,
            };

            var responseCachingContext = new ResponseCachingContext(metadatas: endpointAccessor.Metadatas,
                                                                    cacheKeyGenerator: cacheKeyGenerator,
                                                                    responseCache: responseCache,
                                                                    cacheDeterminer: cacheDeterminer,
                                                                    options: buildContext.Options,
                                                                    interceptorAggregator: interceptorAggregator,
                                                                    dumpStreamCapacity: dumpStreamCapacity);

            return(filterType switch
            {
                FilterType.Resource => executingLockPool is null
                                        ? new DefaultResourceCacheFilter(responseCachingContext, cachingDiagnosticsAccessor)
                                        : new DefaultLockedResourceCacheFilter(responseCachingContext, executingLockPool, cachingDiagnosticsAccessor),
                FilterType.Action => executingLockPool is null
                                        ? new DefaultActionCacheFilter(responseCachingContext, cachingDiagnosticsAccessor)
                                        : new DefaultLockedActionCacheFilter(responseCachingContext, executingLockPool, cachingDiagnosticsAccessor),
                _ => throw new NotImplementedException($"Not ready to support FilterType: {filterType}"),
            });
示例#7
0
 /// <summary>
 /// Force re-evaluates the given aggregator with the given interceptors.
 /// </summary>
 private void PopulateAggregator(InterceptorAggregator <TInterceptor> aggregator, TInterceptor[] interceptors)
 {
     ReflectionCache.SetInterceptors(aggregator, interceptors);
 }