Skip to content

Global Filters

Global filters are repository-level filters that Suite applies automatically to queries. They are useful for cross-cutting rules such as hiding inactive records or restricting records by sharing level.

Global filters are enabled by default. Use IGlobalFilterContext when a query needs to opt out of one or more filters.

Disabling filters

Inject IGlobalFilterContext in application code, consumers, GraphQL middleware, or other orchestration code that needs to control filter behavior.

C#
public class MyConsumer : IConsumer<MyMessage>
{
    private readonly IGlobalFilterContext globalFilterContext;
    private readonly IReadOnlyRepository<Guid, Reason> repository;

    public MyConsumer(
        IGlobalFilterContext globalFilterContext,
        IReadOnlyRepository<Guid, Reason> repository)
    {
        this.globalFilterContext = globalFilterContext;
        this.repository = repository;
    }

    public async Task Consume(ConsumeContext<MyMessage> context)
    {
        var reasons = await this.globalFilterContext.WithGlobalFiltersDisabledAsync(
            GlobalFilters.Activation,
            () => this.repository.AllAsync(context.CancellationToken));
    }
}

The context exposes scoped disable operations. Once the returned scope is disposed, the previous filter state is restored.

C#
1
2
3
4
using var disabledFilters =
    this.globalFilterContext.DisableFilters(GlobalFilters.SharingLevels);

var entities = await this.repository.AllAsync(cancellationToken);

Disabling multiple filters

GlobalFilters is a flags enum, so filters can be combined.

C#
1
2
3
4
5
var filters = GlobalFilters.SharingLevels | GlobalFilters.Activation;

var entities = await this.globalFilterContext.WithGlobalFiltersDisabledAsync(
    filters,
    () => this.repository.AllAsync(cancellationToken));

To disable every global filter, omit the argument or pass GlobalFilters.All.

C#
var entities = await this.globalFilterContext.WithGlobalFiltersDisabledAsync(
    () => this.repository.AllAsync(cancellationToken));

GraphQL fields

GraphQL query fields can use DisableFiltersAttribute when the filter policy is static for that field. The attribute receives the filters that must be disabled while the field resolves.

Disable all global filters:

C#
1
2
3
4
5
6
[DisableFilters]
[UseSuiteList(typeof(User))]
public Task<IQueryable<User>> GetUsers([Service] IQueryableFactory factory)
{
    return factory.Execute<User>();
}

Disable only sharing-level filtering while keeping activation, tenant, and custom filters active:

C#
1
2
3
4
5
6
[DisableFilters(GlobalFilters.SharingLevels)]
[UseSuiteList(typeof(Ship))]
public Task<IQueryable<Ship>> GetShips([Service] IQueryableFactory factory)
{
    return factory.Execute<Ship>();
}

Disable more than one filter:

C#
1
2
3
4
5
6
[DisableFilters(GlobalFilters.SharingLevels | GlobalFilters.Activation)]
[UseSuiteList(typeof(Ship))]
public Task<IQueryable<Ship>> GetShipsIncludingInactiveEntities([Service] IQueryableFactory factory)
{
    return factory.Execute<Ship>();
}

Available filters

The current filter flags are:

Flag Description
GlobalFilters.SharingLevels Controls the sharing level query filter.
GlobalFilters.Activation Controls the activation query filter for deactivatable entities.
GlobalFilters.Tenant Reserved for tenant filtering.
GlobalFilters.Custom Default bucket for custom providers that do not declare a more specific flag.
GlobalFilters.All Disables every registered global filter.

Adding a filter provider

Global filter providers implement IGlobalFilterSpecificationProvider. Providers should declare which flag controls them by implementing the Filter property.

C#
public class MyGlobalFilterProvider : IGlobalFilterSpecificationProvider
{
    public GlobalFilters Filter => GlobalFilters.Custom;

    public bool Applies<TEntity>()
        where TEntity : class
    {
        return typeof(IMyFilteredEntity).IsAssignableFrom(typeof(TEntity));
    }

    public Task<IFilterSpecification<TEntity>> GetSpecification<TEntity>()
        where TEntity : class
    {
        var specification = new MyFilterSpecification<TEntity>();

        return Task.FromResult<IFilterSpecification<TEntity>>(specification);
    }
}

The repository infrastructure uses IGlobalFilterSpecificationManager internally to collect provider specifications. Application code should use IGlobalFilterContext instead; that keeps repository internals out of application services, consumers, and middleware.

Module-specific contexts

Some modules still expose a module-specific context because they do more than enable or disable a repository filter. For example, sharing code uses ISharingsContextManager for behavior outside query filtering, such as calculating destination sharing levels.

Use IGlobalFilterContext for query filter control. Use the module-specific context only when you need the module behavior it owns.