Using Serenity Service Behaviors

    Serenity provides service behavior system, which allows you to intercept Create, Update, Retrieve, List, Delete handlers and add custom code to them.

    Some operations in these handlers, like capture log, unique constraint validation etc. are already implemented as service behaviors.

    Behaviors might be activated for all rows, or based on some rule, like having a specific attribute or interface. For example, CaptureLogBehavior activates for rows with [CaptureLog] attribute.

    We’ll first define an interface IMultiTenantRow that will trigger our new behavior. Place this class in file IMultiTenantRow.cs, next to TenantRow.cs:

    Than add this behavior in file MultiTenantBehavior.cs next to it:

    They do this by implementing ActivateFor method, which is called by request handlers.

    In this method, we check if row type implements IMultiTenantRow interface. If not it simply returns false.

    Then we get a private reference to TenantIdField to reuse it later in other methods.

    ActivateFor is only called once per every handler type and row. If this method returns true, behavior instance is cached aggresively for performance reasons, and reused for any request for this row and handler type.

    Thus, everything you write in other methods must be thread-safe, as one instance is shared by all requests.

    Here, we need to intercept all of these service calls, so we implement all interfaces.

    We only fill in methods we are interested in, and leave others empty.

    The methods we implement here, corresponds to methods we override in RoleRepository.cs in previous section. The code they contain is almost same, except here we need to be more generic, as this behavior will work for any row type implementing IMultiTenantRow.

    Now revert every change we made in RoleRepository.cs:

    And add IMultiTenantRow interface to RoleRow: