Sample: Copying an Activity Between Tenants
In multi-tenant applications, it is often necessary to move or copy data between tenants. Bloqs supports this through the IDataServiceCreator, which lets you create DataService instances for different tenants and perform cross-tenant operations.
Operation: Copy Activity
The Copy Activity operation demonstrates how to copy an Activity entity from a source tenant to a destination tenant.
Operation Model
The operation is fueled by an input model that specifies the tenant and activity to copy:
public class CopyActivityInput : Entity
{
public required Guid TenantId { get; set; }
public required Guid ActivityId { get; set; }
}TenantId: The target tenant where the activity should be copied.
ActivityId: The source activity to copy.
Operation Handler (API)
[OperationCommandHandler(AppConstants.Operations.CopyActivityName)]
public class CopyActivity(IDataServiceCreator dataServiceCreator)
: ICommandHandler<OperationCommand, OperationCommandResult>
{
public async Task<OperationCommandResult> HandleAsync(
OperationCommand command,
CancellationToken cancellationToken = default
)
{
try
{
var input =
command.InputEntity as CopyActivityInput
?? throw new Exception("Invalid input entity for CopyActivity operation");
// Get the destination tenant
var destinationTenant = await dataServiceCreator
.GetDataService<Tenant>(DataServiceCreatorArgs.Create<Tenant>(command.AppName))
.GetAsync(input.TenantId);
// Source data service (current tenant)
var sourceDataService = dataServiceCreator.GetDataService<Activity>(
DataServiceCreatorArgs.FromCommand<Activity>(command)
);
// Destination data service (target tenant)
var destinationDataService = dataServiceCreator.GetDataService<Activity>(
DataServiceCreatorArgs.Create<Activity>(command.AppName, destinationTenant.Name)
);
// Fetch the source activity
var sourceActivity = await sourceDataService.GetAsync(input.ActivityId);
// Assign a new ID for the destination copy
sourceActivity.Id = Guid.CreateVersion7();
// Save the copied activity into the destination tenant
await destinationDataService.SaveAsync([sourceActivity], true);
return OperationCommandResult.CreateSuccess(null);
}
catch (Exception ex)
{
Console.WriteLine($"Error copying activity: {ex.Message}");
return OperationCommandResult.CreateFailure();
}
}
}Page Definition
To expose the Copy Activity operation to end users, a page is defined in the app model. The page contains an OperationStartComponent that references the operation and allows the user to select both the Activity and the Tenant.
appBuilder.AddPage(
new Page
{
Id = AppConstants.Pages.CopyActivityOperationPage,
Title = "Copy Activity",
Name = "copy-activity",
Area = ContainerComponent.Create(
new OperationStartComponent
{
OperationId = IdGen.GetOperationId("CopyActivity"),
EntityClassId = IdGen.GetEntityClassId<CopyActivityInput>(),
Area = PageBuilderExtensions.VerticalContainer(
new EntityRelationInputComponent
{
EntityClassId = IdGen.GetEntityClassId<Activity>(),
PropertyId = IdGen.GetPropertyId<CopyActivityInput>(
nameof(CopyActivityInput.ActivityId)
),
IsRequired = true,
},
new EntityRelationInputComponent
{
EntityClassId = IdGen.GetEntityClassId<Tenant>(),
PropertyId = IdGen.GetPropertyId<CopyActivityInput>(
nameof(CopyActivityInput.TenantId)
),
IsRequired = true,
}
),
AfterCancelPageId = AppConstants.Pages.HomePage,
AfterExecutePageId = AppConstants.Pages.HomePage,
}
),
}
)
.AddOperation(
new Operation
{
Id = IdGen.GetOperationId("CopyActivity"),
Name = "CopyActivity",
}
);OperationId links the page to the
CopyActivityoperation.EntityClassId references the
CopyActivityInputmodel.EntityRelationInputComponent lets the user pick an
Activityand aTenant.AfterCancelPageId / AfterExecutePageId define navigation flow after the operation.
Key Concepts
Operation Input Model
Defines what data is required for the operation (
TenantId,ActivityId).
Operation Handler
Performs the actual logic of fetching the entity from one tenant and saving it into another.
Page Modeling
Defines how the operation is exposed to the end user.
Uses Bloqs components (
OperationStartComponent,EntityRelationInputComponent) to build the UI.
Summary
Multi-tenant data exchange is modeled as an Operation in Bloqs.
An input model (
CopyActivityInput) defines the required parameters.An operation handler performs the cross-tenant copy logic.
A page definition exposes the operation to users, allowing them to select an activity and a destination tenant.
Last updated