Generating Handler Interfaces

In Serene, every request handler class has a matching interface that is written by hand:

public interface IRoleSaveHandler : ISaveHandler<MyRow> { }

public class RoleSaveHandler(IRequestContext context)
    : SaveRequestHandler<MyRow>(context), IRoleSaveHandler
{
    // ...
}

In StartSharp you don't have to write the interface. Place the GenerateInterface attribute on the handler class, and the Serenity.Pro.Coder InterfaceSourceGenerator (a Roslyn source generator) creates the interface for you:

[GenerateInterface]
public class RoleSaveHandler(IRequestContext context) :
    SaveRequestHandler<MyRow>(context),
    IRoleSaveHandler
{
    // ...
}

[GenerateInterface] is a Serenity.Pro.Coder feature, so it is only available in StartSharp (or projects referencing Serenity.Pro.Coder).

Works for All Request Handler Types

This is not specific to save handlers. The generator recognizes every request handler base class and picks the matching base interface automatically:

Handler base class Generated interface
SaveRequestHandler<TRow> ISaveHandler<TRow>
ListRequestHandler<TRow> IListHandler<TRow>
RetrieveRequestHandler<TRow> IRetrieveHandler<TRow>
DeleteRequestHandler<TRow> IDeleteHandler<TRow>
UndeleteRequestHandler<TRow> IUndeleteHandler<TRow>

So a RoleListHandler, RoleDeleteHandler, or RoleUndeleteHandler marked with [GenerateInterface] gets its IRoleListHandler, IRoleDeleteHandler, IRoleUndeleteHandler, etc. generated the same way.

Naming and Namespace

The generated interface is named I + class name (e.g. IRoleSaveHandler).

It is placed in the same namespace as the handler class, but with a trailing .RequestHandlers suffix removed. So a handler in MyProject.Administration.RequestHandlers gets its interface generated into MyProject.Administration:

// generated by InterfaceSourceGenerator
namespace MyProject.Administration;

public interface IRoleSaveHandler : ISaveHandler<MyRow> { }

Interface Members

Public members of the class become interface members. Mark a member with NonInterfaceMember to exclude it from the generated interface.

For a class that is not a request handler (e.g. an action handler deriving from BaseRequestHandler), the generated interface derives from IRequestHandler and includes the public methods:

[GenerateInterface]
public class TestActionHandler : ITestActionHandler
{
    public TestResponse TestAction(TestRequest request) { ... }
}

// generated:
public interface ITestActionHandler : IRequestHandler
{
    TestResponse TestAction(TestRequest request);
}

See Also