Skip to content

Undelete Request Handler

The UndeleteRequestHandlerAsync is the base class that handles Undelete service requests. It restores a record that was previously soft deleted.

From Serenity 10.5.0, Sergen generates asynchronous handlers (UndeleteRequestHandlerAsync) and endpoint actions by default. The synchronous UndeleteRequestHandler is kept for backward compatibility and is marked obsolete — it will be deprecated in a future version. New code — and code generated by Sergen — should use the async variants.

Sergen only generates an Undelete handler for rows that support soft delete, i.e. rows implementing IIsActiveDeletedRow or IIsDeletedRow. For a row without an IsActive/IsDeleted field (which is hard-deleted), there is nothing to undelete, so no handler is generated.

Generated Handler

For a row that supports soft delete, Sergen generates:

using MyRow = MyProject.Administration.UserRow;

namespace MyProject.Administration;

public interface IUserUndeleteHandler : IUndeleteHandlerAsync<MyRow> { }

public class UserUndeleteHandler(IRequestContext context)
    : UndeleteRequestHandlerAsync<MyRow>(context), IUserUndeleteHandler
{
}

The class derives from the generic UndeleteRequestHandlerAsync<TRow> and IUndeleteRequestHandler.

UndeleteRequestHandlerAsync<TRow> itself derives from the fully generic UndeleteRequestHandlerAsync<TRow, TUndeleteRequest, TUndeleteResponse> — the extra arguments let you customize the request and response types if you ever need an undelete handler with a custom request/response.

The Service Endpoint

The endpoint exposes a single Undelete action:

[Route("Services/Administration/User/[action]")]
[ConnectionKey(typeof(MyRow)), ServiceAuthorize(typeof(MyRow))]
public class UserEndpoint : ServiceEndpoint
{
    [HttpPost, AuthorizeDelete(typeof(MyRow))]
    public Task<UndeleteResponse> Undelete(IUnitOfWork uow, UndeleteRequest request,
        [FromServices] IUserUndeleteHandler handler, CancellationToken cancellationToken = default)
    {
        return handler.UndeleteAsync(uow, request, cancellationToken);
    }
}

The Request and Response

The request is an UndeleteRequest:

public class UndeleteRequest : ServiceRequest
{
    public object? EntityId { get; set; }
}

It only contains the ID of the record to restore. The response is an UndeleteResponse:

public class UndeleteResponse : ServiceResponse
{
    public bool WasNotDeleted { get; set; }
}

WasNotDeleted is true if the record was not actually soft-deleted (e.g. it was already restored, or its IsActive was not -1).

What Undelete Does

Depending on the row type:

  • For IIsActiveDeletedRow rows, the handler issues UPDATE ... SET IsActive = 1 where IsActive = -1, restoring the record to active.
  • For IIsDeletedRow rows, it sets IsDeleted = false.

If the row type doesn't implement one of these interfaces, the handler raises an error, because there is no way to undelete a hard-deleted record.

Lifecycle Methods

The main overridable methods on UndeleteRequestHandlerAsync are:

  • OnBeforeUndeleteAsync() — called before the undelete is executed.
  • OnAfterUndeleteAsync() — called after the undelete succeeds.
  • OnReturnAsync() — called just before the response is returned.

Each accepts a CancellationToken cancellationToken = default and returns Task. Call the base implementation first when overriding.

OnBeforeUndeleteAsync/OnAfterUndeleteAsync also invoke any registered IUndeleteBehavior.OnBeforeUndeleteAsync / OnAfterUndeleteAsync.

See Also