Skip to content

Services

Serenity services follow a request handler based architecture. When a client calls a service endpoint (an MVC controller deriving from ServiceEndpoint), the endpoint delegates the actual work to a request handler — a class deriving from one of Serenity's handler base classes. The handlers encapsulate the standard CRUD operations:

Each handler type has a corresponding base class (ListRequestHandler, SaveRequestHandler, DeleteRequestHandler, UndeleteRequestHandler, RetrieveRequestHandler) and a marker interface (IListRequestHandler, ISaveRequestHandler, etc.) that behaviors use.

Request Handlers

Request handlers are auto-registered through the type source by AddServiceHandlers(). For each entity (row), Sergen generates a small handler class that derives from the relevant base class and implements the corresponding interface. For example, for a Language entity:

public interface ILanguageSaveHandler : ISaveHandler<MyRow> { }

public class LanguageSaveHandler(IRequestContext context)
    : SaveRequestHandler<MyRow>(context), ILanguageSaveHandler
{
}

The base classes provide all the default logic (validation, permission checks, audit logging, SQL generation, etc.), so an empty handler like the one above already gives you a working Create/Update/Delete service. You override virtual methods when you need custom behavior.

Behaviors

In addition to overriding methods, you can intercept request handlers through behaviors — classes implementing ISaveBehavior, IListBehavior, IDeleteBehavior, IUndeleteBehavior, or IRetrieveBehavior. Behaviors run for every handler of the matching type (they are discovered through the type source), making them ideal for cross-cutting concerns like audit logging, multi-tenancy, or master–detail handling.

See Service Behaviors for the full guide — the behavior interfaces, how they are discovered and attached, the handler lifecycle, and worked examples.

Service Endpoints

The MVC layer that exposes handlers to the client is covered in Service Endpoints.

See Also