Skip to main content

use-interceptors-and-dynamic-proxy

ABP cross-cutting behavior via Castle dynamic proxies and IAbpInterceptor. USE FOR: how validation, unit of work, authorization, auditing, feature interceptors are selected; interceptor not running; custom interceptor via Services.OnRegistered. DO NOT USE FOR: module lifecycle (define-application-modules); audit-log persistence (configure-audit-logging); feature values (manage-settings-and-features); services without interception (register-and-replace-services).

الانتقال إلى التثبيت

معلومات المصدر

المستودع
abpframework/abp-skills
آخر نشاط في المصدر
٢٠ يوليو ٢٠٢٦ في ٠٣:٢٤
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١٨
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
use-interceptors-and-dynamic-proxy
description
ABP cross-cutting behavior via Castle dynamic proxies and IAbpInterceptor. USE FOR: how validation, unit of work, authorization, auditing, feature interceptors are selected; interceptor not running; custom interceptor via Services.OnRegistered. DO NOT USE FOR: module lifecycle (define-application-modules); audit-log persistence (configure-audit-logging); feature values (manage-settings-and-features); services without interception (register-and-replace-services).
license
MIT
# Using Interceptors and Dynamic Proxies ABP attaches `IAbpInterceptor` implementations while services are registered, then the Autofac/Castle integration creates either an interface proxy or a class proxy. The call must cross that proxy for an interceptor to run. ## When to Use - Diagnose why validation, `[UnitOfWork]`, `[Authorize]`, `[Audited]`, or `[RequiresFeature]` is not taking effect on a service call. - Add reusable before/after behavior around application or domain services. - Select services for interception through `IServiceCollection.OnRegistered`. - Inspect the invoked method, arguments, target, or return value through `IAbpMethodInvocation`. ## When Not to Use - **Module lifecycle and ordinary registrations** — use define-application-modules. - **Audit-log storage, contributors, and entity history** — use configure-audit-logging. - **Feature definitions and values** — use manage-settings-and-features. - **Service exposure, replacement, keyed services, or decoration** — use register-and-replace-services. ## How it works ### The invocation contract Implement `IAbpInterceptor.InterceptAsync(IAbpMethodInvocation)` directly or derive from `AbpInterceptor`. Call `ProceedAsync()` exactly once to continue the chain. The invocation also exposes `Arguments`, `ArgumentsDictionary`, `GenericArguments`, `TargetObject`, `Method`, and `ReturnValue`. ```csharp using System.Diagnostics; using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; public class ExecutionTimeInterceptor : AbpInterceptor, ITransientDependency { private readonly ILogger<ExecutionTimeInterceptor> _logger; public ExecutionTimeInterceptor(ILogger<ExecutionTimeInterceptor> logger) { _logger = logger; } public override async Task InterceptAsync(IAbpMethodInvocation invocation) { var stopwatch = Stopwatch.StartNew(); try { await invocation.ProceedAsync(); } finally { _logger.LogInformation( "{MethodName} completed in {ElapsedMilliseconds} ms", invocation.Method.Name, stopwatch.ElapsedMilliseconds); } } } ``` Omitting `ProceedAsync()` intentionally short-circuits the target and all later interceptors. Use `try/finally` when after-logic must run for both success and failure. ### Register a custom interceptor Choose an explicit marker or attribute. A marker interface keeps the selector simple and avoids intercepting unrelated services. ```csharp using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Collections; using Volo.Abp.DependencyInjection; public interface IExecutionTimeEnabled { } public static class ExecutionTimeInterceptorRegistrar { public static void RegisterIfNeeded(IOnServiceRegistredContext context) { if (typeof(IExecutionTimeEnabled).IsAssignableFrom(context.ImplementationType)) { context.Interceptors.TryAdd<ExecutionTimeInterceptor>(); } } } public override void PreConfigureServices(ServiceConfigurationContext context) { context.Services.OnRegistered(ExecutionTimeInterceptorRegistrar.RegisterIfNeeded); } ``` `ExecutionTimeInterceptor` is conventionally registered because it implements `ITransientDependency`. Register the `OnRegistered` callback early enough to observe the target services; `PreConfigureServices` is the safe module-level location. ### How the built-in interceptors are selected Each built-in module installs an `OnRegistered` callback. Its registrar tests the implementation type and adds an interceptor only when needed: | Concern | Registrar trigger | | --- | --- | | Validation | Type implements `IValidationEnabled` and is not in `DynamicProxyIgnoreTypes`. | | Unit of work | `UnitOfWorkHelper.IsUnitOfWorkType(...)` returns true and the type is not ignored. | | Authorization | Type or any method has `[Authorize]` and the type is not ignored. | | Auditing | The type is auditable by default, has `[Audited]`, implements `IAuditingEnabled`, or has an audited method, subject to ignore rules. | | Features | Type or any method has `[RequiresFeature]` and the type is not ignored. | The registrar decision only attaches the interceptor to the service registration. The interceptor itself performs the runtime check and behavior. ### Hard conditions for interception All of these must hold: 1. The implementation is registered through ABP DI while the relevant `OnRegistered` callback is active. 2. The service is resolved from DI and invoked through the resolved proxy; `new` bypasses the proxy. 3. The registrar selects the implementation and adds the interceptor type. 4. The call uses an exposed interface, **or** the class-proxy target method is overridable (`virtual`, non-sealed class). 5. Class interception has not been disabled with `DisableAbpClassInterceptors`, a selector, or `DisableAbpFeaturesAttribute.DisableInterceptors`. 6. The Autofac integration is present. `AbpAutofacModule` depends on `AbpCastleCoreModule`; the latter registers the async interceptor adapter. For an interface proxy, inject and call the interface. For a class proxy, make the intercepted public/protected method `virtual`. A non-virtual class method executes normally but Castle cannot override it. ## Validation - Resolve the target from an `IServiceScope`; do not instantiate it directly. - Test both the selected interface path and, if supported, the concrete class path. - Add a deterministic signal in the custom interceptor and verify it occurs before/after the target once. - Verify exception behavior: the target exception still propagates and `finally` logic runs. - For a missing built-in behavior, confirm the module installed its registrar, the type matches the registrar trigger, and the method call crosses a proxy. ## Common Pitfalls - **A class method is not `virtual`** — class proxies cannot intercept it. Inject an exposed interface or make the method overridable. - **The object was created with `new`** — only the container-resolved proxy carries interceptors. - **The service was registered before the callback** — register selector callbacks in `PreConfigureServices`. - **The selector checks the service interface instead of `ImplementationType`** — `IOnServiceRegistredContext.ImplementationType` is what built-in registrars inspect. - **`ProceedAsync()` is called zero or multiple times** — zero short-circuits execution; multiple calls execute the downstream chain repeatedly. - **The type is deliberately ignored** — check `DynamicProxyIgnoreTypes`, `DisableAbpClassInterceptors`, and `DisableAbpFeaturesAttribute` before changing business code.
عرض على GitHub