Service Startup

Service Startup executes logic when the application starts. Service Startup classes are automatically discovered and executed by the framework.

Create Service Startup

Create a new file in the project in the Logic or Startup folder.

Project / Startup / RoleStartup.cs

[ServiceStartup(StartupOperation.Post)]
public class RoleStartup : IServiceStartup
{
public async Task<Response<object?>> Execute(StartupContext context)
{
// Your startup logic here
return ServiceResult.Success();
}
}

The ServiceStartup attribute takes the following parameters:

  • StartupOperation: Pre executes before system records are created, Post executes after (use Post unless you need Pre)
  • Order (optional): Execution order when multiple startup services run at the same stage (lower executes first, default: 0)

Initialize Roles, Permissions and Options

Use the SecurityBuilder to initialize roles and assign permissions. Roles are created if they don't exist. Permissions must already exist (automatically created by the framework for entities, actions, jobs and hubs).

Project / Startup / RoleStartup.cs

[ServiceStartup(StartupOperation.Post)]
public class RoleStartup : IServiceStartup
{
public async Task<Response<object?>> Execute(StartupContext context)
{
await context.SecurityBuilder
.Role("Public User")
.Permission("TABLE_Account_UPDATE_TEAM")
.Permission("TABLE_Account_READ_SYSTEM")
.Permission("HUB_ChatHub")
.Permission("ACTION_SendNotification")
.Role("Platform Admin")
.Permission("TABLE_Account_CREATE_SYSTEM")
.Permission("TABLE_Account_UPDATE_SYSTEM")
.Permission("TABLE_Account_DELETE_SYSTEM")
.Permission("TABLE_Account_READ_SYSTEM")
.Permission("TABLE_Offer_READ_SYSTEM")
.Permission("TABLE_Offer_CREATE_SYSTEM")
.Permission("TABLE_Offer_UPDATE_SYSTEM")
.Permission("TABLE_Offer_DELETE_SYSTEM")
.Permission("HUB_AdminHub")
.Permission("ACTION_ExportData")
.Permission("ACTION_ImportData")
.Permission("JOB_DataCleanup")
.Execute();
await CreateOptions(context);
return ServiceResult.Success();
}
private async Task CreateOptions(StartupContext context)
{
var db = context.GetDbContext<DataContext>();
await CreateOptionIfNotExists(db, "Status", "Active", 1);
await CreateOptionIfNotExists(db, "Status", "Pending", 2);
await CreateOptionIfNotExists(db, "Priority", "Low", 1);
await CreateOptionIfNotExists(db, "Priority", "High", 2);
await db.SaveChangesAsync();
}
private async Task CreateOptionIfNotExists(DataContext db, string name, string label, int order)
{
var exists = await db.Options.AnyAsync(o => o.Name == name && o.Label == label);
if (!exists)
{
db.Options.Add(new Option
{
OptionId = Guid.NewGuid(),
Name = name,
Label = label,
Order = order,
Tag = ""
});
}
}
}

Permissions follow these naming conventions:

  • Table: TABLE_(TableName)_(Operation)_(Level) - Example: TABLE_Widget_READ_SYSTEM, TABLE_Account_UPDATE_TEAM
  • Action: ACTION_(ActionName) - Example: ACTION_SendNotification, ACTION_ExportData
  • Hub: HUB_(HubName) - Example: HUB_ChatHub, HUB_AdminHub
  • Job: JOB_(JobName) - Example: JOB_DataCleanup

See the Security documentation for more details.

Dependency Injection

Service Startup classes support constructor-based dependency injection:

Project / Startup / MyStartup.cs

[ServiceStartup(StartupOperation.Post)]
public class MyStartup : IServiceStartup
{
private readonly IEmailService _emailService;
public MyStartup(IEmailService emailService)
{
_emailService = emailService;
}
public async Task<Response<object?>> Execute(StartupContext context)
{
await _emailService.SendAdminNotification("Application started");
return ServiceResult.Success();
}
}

Was this page helpful?