Silky Microservice FrameworkSilky Microservice Framework
Home
Docs
Config
Source
github
gitee
  • 简体中文
  • English
Home
Docs
Config
Source
github
gitee
  • 简体中文
  • English
  • Startup

    • Silky Framework Source Code Analysis
    • Host Construction
    • Service Engine
    • Module System
    • Service & Service Entry Resolution
    • Service Registration
    • Dependency Injection Conventions
    • RPC Service Proxy
  • Runtime

    • Endpoints & Routing
    • Executor Dispatch System
    • Local Executor & Server-Side Filters
    • Remote Executor & RPC Call Chain
    • RPC Server Message Handling
    • Service Governance
    • Cache Interceptor
    • Distributed Transactions (TCC)
    • HTTP Gateway Pipeline
    • Filter Pipeline
    • Polly Resilience Pipeline
    • Endpoint Health Monitor

Overview

Silky's RPC filter pipeline is modeled after ASP.NET Core MVC's filter system, driving different filter types through a state machine in a fixed execution order. The framework maintains separate filter pipelines on the server side (LocalInvoker) and the client side (RemoteInvoker).


Filter Type Hierarchy

Server-Side Filters

InterfaceExecution TimingDescription
IServerAuthorizationFilter / IAsyncServerAuthorizationFilterEarliest — before Action executionAuthorization filters; set Result to short-circuit the pipeline
IServerExceptionFilter / IAsyncServerExceptionFilterAfter exceptions occurCatch and handle exceptions from Action or Result filters
IServerFilter / IAsyncServerFilterBefore and after Action executionGeneral Action filters; can short-circuit by not calling next()
IServerResultFilter / IAsyncServerResultFilterBefore and after result is writtenCan modify or replace the execution result
IAlwaysRunServerResultFilter / IAsyncAlwaysRunServerResultFilterAlways runs regardless of short-circuitingFor cleanup operations that must execute

Client-Side Filters

Symmetric to server-side, with Client prefix:

InterfaceDescription
IClientFilter / IAsyncClientFilterClient-side Action filter
IClientExceptionFilter / IAsyncClientExceptionFilterClient-side exception filter
IClientResultFilter / IAsyncClientResultFilterClient-side result filter
IAlwaysRunClientResultFilterAlways-run client-side result filter

Creating Custom Filters

Extend ServerFilterAttribute (or ClientFilterAttribute) and override the needed methods:

[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method,
    AllowMultiple = true, Inherited = true)]
public class TimingServerFilter : ServerFilterAttribute
{
    private Stopwatch _sw;

    public override void OnActionExecuting(ServerInvokeExecutingContext context)
    {
        _sw = Stopwatch.StartNew();
    }

    public override void OnActionExecuted(ServerInvokeExecutedContext context)
    {
        _sw.Stop();
        var serviceEntryId = context.ServiceEntry.Id;
        Console.WriteLine($"[{serviceEntryId}] Elapsed: {_sw.ElapsedMilliseconds}ms");
    }
}

// Apply to interface or method:
[ServiceRoute]
[TimingServerFilter]
public interface IOrderAppService
{
    Task<OrderDto> GetByIdAsync(long id);
}

Filter Order

IOrderedFilter.Order (lower value = executes first):

public class TimingServerFilter : ServerFilterAttribute
{
    public override int Order => -100; // runs before default filters
}

Filter Discovery & Resolution

At Service Entry Construction Time

The framework collects all IFilterMetadata attributes from the interface and method:

  • Interface-level filters: FilterScope.Global (applied to all methods)
  • Method-level filters: FilterScope.Action
  • Ordered by IOrderedFilter.Order within each type

At Runtime (DefaultFilterProvider)

DefaultFilterProvider instantiates FilterDescriptor into executable FilterItem objects for each call. Filter instances are either:

  • Attribute-based: Created fresh per call (Transient)
  • Service-based: Resolved from the DI container (respects registered lifetime)

State Machine Execution

The LocalInvoker drives execution through states:

State: ActionBegin
    │
    ├── Run all Authorization filters (IServerAuthorizationFilter)
    │       If any sets Result → skip to ResultBegin
    │
    ▼
State: AuthorizationBegin
    │
    ├── Run Action filter OnActionExecuting() for each filter
    │       If any short-circuits (sets Result without calling next) → skip to ResultBegin
    │
    ▼
State: ActionInside
    │
    ├── ObjectMethodExecutor invokes the business method
    │       Exception → ExceptionFilter handling
    │
    ▼
State: ResultBegin
    │
    ├── Run Result filter OnResultExecuting() for each filter
    ├── Write result
    └── Run Result filter OnResultExecuted() for each filter
    │
    ▼
State: InvokeEnd
    │  Result available in LocalInvoker.Result

Short-Circuiting Rules

  • Authorization filter: Setting context.Result short-circuits directly to ResultBegin (skips all Action filters and the business method)
  • Action filter (OnActionExecuting): Not calling next() short-circuits to ResultBegin
  • Exception filter: Setting context.ExceptionHandled = true prevents the exception from propagating
  • AlwaysRun filters: Execute regardless of any short-circuiting — suitable for guaranteed cleanup

Built-in Filters

FilterDescription
AuthorizationServerFilterValidates [Authorize] attribute and JWT claims from RpcContext
CachingInterceptFilterImplements cache read/update/remove interception (delegates to CachingInterceptor)
ValidationFilterValidates method parameters using IValidator (FluentValidation or DataAnnotations)
MaxConcurrentHandlingFilterServer-side: enforces MaxConcurrentHandlingCount concurrency limit
Edit this page
Prev
HTTP Gateway Pipeline
Next
Polly Resilience Pipeline