🎯

abp-infrastructure-patterns

🎯Skill

from thapaliyabikendra/ai-artifacts

VibeIndex|
What it does

abp-infrastructure-patterns skill from thapaliyabikendra/ai-artifacts

abp-infrastructure-patterns

Installation

Install skill:
npx skills add https://github.com/thapaliyabikendra/ai-artifacts --skill abp-infrastructure-patterns
2
AddedJan 27, 2026

Skill Details

SKILL.md

"ABP Framework cross-cutting patterns including authorization, background jobs, distributed events, multi-tenancy, and module configuration. Use when: (1) defining permissions, (2) creating background jobs, (3) publishing/handling distributed events, (4) configuring modules."

Overview

# ABP Infrastructure Patterns

Cross-cutting concerns and infrastructure patterns for ABP Framework.

Authorization & Permissions

Define Permissions

```csharp

// Domain.Shared/Permissions/ClinicPermissions.cs

public static class ClinicPermissions

{

public const string GroupName = "Clinic";

public static class Patients

{

public const string Default = GroupName + ".Patients";

public const string Create = Default + ".Create";

public const string Edit = Default + ".Edit";

public const string Delete = Default + ".Delete";

}

public static class Appointments

{

public const string Default = GroupName + ".Appointments";

public const string Create = Default + ".Create";

public const string Edit = Default + ".Edit";

public const string Delete = Default + ".Delete";

public const string ViewAll = Default + ".ViewAll"; // Admins only

}

}

```

Register Permissions

```csharp

// Application.Contracts/Permissions/ClinicPermissionDefinitionProvider.cs

public class ClinicPermissionDefinitionProvider : PermissionDefinitionProvider

{

public override void Define(IPermissionDefinitionContext context)

{

var clinicGroup = context.AddGroup(ClinicPermissions.GroupName);

var patients = clinicGroup.AddPermission(

ClinicPermissions.Patients.Default,

L("Permission:Patients"));

patients.AddChild(ClinicPermissions.Patients.Create, L("Permission:Patients.Create"));

patients.AddChild(ClinicPermissions.Patients.Edit, L("Permission:Patients.Edit"));

patients.AddChild(ClinicPermissions.Patients.Delete, L("Permission:Patients.Delete"));

var appointments = clinicGroup.AddPermission(

ClinicPermissions.Appointments.Default,

L("Permission:Appointments"));

appointments.AddChild(ClinicPermissions.Appointments.Create, L("Permission:Appointments.Create"));

appointments.AddChild(ClinicPermissions.Appointments.ViewAll, L("Permission:Appointments.ViewAll"));

}

private static LocalizableString L(string name)

=> LocalizableString.Create(name);

}

```

Use Permissions

```csharp

// Declarative

[Authorize(ClinicPermissions.Patients.Create)]

public async Task CreateAsync(CreatePatientDto input) { }

// Imperative

public async Task GetAsync(Guid id)

{

var appointment = await _appointmentRepository.GetAsync(id);

if (appointment.DoctorId != CurrentUser.Id)

{

await AuthorizationService.CheckAsync(ClinicPermissions.Appointments.ViewAll);

}

return _mapper.AppointmentToDto(appointment);

}

// Check without throwing

public async Task CanCreatePatientAsync()

=> await AuthorizationService.IsGrantedAsync(ClinicPermissions.Patients.Create);

```

Background Jobs

Define Job

```csharp

public class AppointmentReminderJob : AsyncBackgroundJob, ITransientDependency

{

private readonly IRepository _appointmentRepository;

private readonly IEmailSender _emailSender;

public AppointmentReminderJob(

IRepository appointmentRepository,

IEmailSender emailSender)

{

_appointmentRepository = appointmentRepository;

_emailSender = emailSender;

}

public override async Task ExecuteAsync(AppointmentReminderArgs args)

{

var appointment = await _appointmentRepository.GetAsync(args.AppointmentId);

await _emailSender.SendAsync(

appointment.Patient.Email,

"Appointment Reminder",

$"You have an appointment on {appointment.AppointmentDate}");

}

}

public class AppointmentReminderArgs

{

public Guid AppointmentId { get; set; }

}

```

Enqueue Job

```csharp

public async Task CreateAsync(CreateAppointmentDto input)

{

var appointment = await _appointmentManager.CreateAsync(/.../);

// Schedule reminder 24 hours before

var reminderTime = appointment.AppointmentDate.AddHours(-24);

await _backgroundJobManager.EnqueueAsync(

new AppointmentReminderArgs { AppointmentId = appointment.Id },

delay: reminderTime - DateTime.Now);

return _mapper.AppointmentToDto(appointment);

}

```

Distributed Events

Publish Event

```csharp

// From entity (recommended for domain events)

public class Patient : AggregateRoot

{

public void Activate()

{

IsActive = true;

AddDistributedEvent(new PatientActivatedEto

{

Id = Id,

Name = Name,

Email = Email

});

}

}

// From application service

public async Task ActivateAsync(Guid id)

{

var patient = await _patientRepository.GetAsync(id);

patient.Activate();

// Or manually publish:

await _distributedEventBus.PublishAsync(new PatientActivatedEto

{

Id = patient.Id,

Name = patient.Name,

Email = patient.Email

});

}

```

Handle Event

```csharp

public class PatientActivatedEventHandler :

IDistributedEventHandler,

ITransientDependency

{

private readonly IEmailSender _emailSender;

private readonly ILogger _logger;

public PatientActivatedEventHandler(

IEmailSender emailSender,

ILogger logger)

{

_emailSender = emailSender;

_logger = logger;

}

public async Task HandleEventAsync(PatientActivatedEto eventData)

{

_logger.LogInformation("Patient activated: {Name}", eventData.Name);

await _emailSender.SendAsync(

eventData.Email,

"Welcome",

"Your patient account has been activated");

}

}

```

Robust Event Handler (Idempotent + Multi-Tenant)

```csharp

public class EntitySyncEventHandler :

IDistributedEventHandler,

ITransientDependency

{

private readonly IRepository _repository;

private readonly IDataFilter _dataFilter;

private readonly ILogger _logger;

public async Task HandleEventAsync(EntityUpdatedEto eto)

{

// Disable tenant filter for cross-tenant sync

using (_dataFilter.Disable())

{

try

{

_logger.LogInformation("Processing entity sync: {Id}", eto.Id);

// Idempotency check

var existing = await _repository.FirstOrDefaultAsync(

x => x.ExternalId == eto.ExternalId);

if (existing != null)

{

ObjectMapper.Map(eto, existing);

await _repository.UpdateAsync(existing);

}

else

{

var entity = ObjectMapper.Map(eto);

await _repository.InsertAsync(entity);

}

_logger.LogInformation("Entity sync completed: {Id}", eto.Id);

}

catch (Exception ex)

{

_logger.LogError(ex, "Entity sync failed: {Id}", eto.Id);

throw new UserFriendlyException($"Failed to sync entity: {ex.Message}");

}

}

}

}

```

Multi-Tenancy

Cross-Tenant Operations

```csharp

public class CrossTenantService : ApplicationService

{

private readonly IDataFilter _dataFilter;

private readonly ICurrentTenant _currentTenant;

public async Task> GetAllTenantsPatients()

{

using (_dataFilter.Disable())

{

return await _patientRepository.GetListAsync();

}

}

public async Task OperateOnTenant(Guid tenantId)

{

using (_currentTenant.Change(tenantId))

{

await DoTenantSpecificOperation();

}

}

}

```

Tenant-Specific Seeding

```csharp

public async Task SeedAsync(DataSeedContext context)

{

if (context.TenantId.HasValue)

await SeedTenantDataAsync(context.TenantId.Value);

else

await SeedHostDataAsync();

}

```

Module Configuration

```csharp

[DependsOn(

typeof(ClinicDomainModule),

typeof(AbpIdentityDomainModule),

typeof(AbpPermissionManagementDomainModule))]

public class ClinicApplicationModule : AbpModule

{

public override void PreConfigureServices(ServiceConfigurationContext context)

{

PreConfigure(options =>

{

options.ExternalLoginProviders.Add();

});

}

public override void ConfigureServices(ServiceConfigurationContext context)

{

Configure(options =>

{

options.KeyPrefix = "Clinic:";

});

context.Services.AddTransient();

context.Services.AddSingleton();

}

public override void OnApplicationInitialization(ApplicationInitializationContext context)

{

var app = context.GetApplicationBuilder();

var env = context.GetEnvironment();

if (env.IsDevelopment())

app.UseDeveloperExceptionPage();

}

}

```

Object Extension

```csharp

public static class ClinicModuleExtensionConfigurator

{

public static void Configure()

{

ObjectExtensionManager.Instance.Modules()

.ConfigureIdentity(identity =>

{

identity.ConfigureUser(user =>

{

user.AddOrUpdateProperty(

"Title",

property =>

{

property.Attributes.Add(new StringLengthAttribute(64));

});

});

});

}

}

```

Best Practices

  1. Permissions - Define hierarchically (Parent.Child pattern)
  2. Background jobs - Use for long-running or delayed tasks
  3. Distributed events - Use for loose coupling between modules
  4. Idempotency - Check for existing before insert in event handlers
  5. Multi-tenancy - Use IDataFilter.Disable() sparingly
  6. Module deps - Declare all dependencies explicitly

Related Skills

  • abp-entity-patterns - Domain layer patterns
  • abp-service-patterns - Application layer patterns
  • openiddict-authorization - OAuth implementation
  • distributed-events-advanced - Advanced event patterns

More from this repository10

🎯
clean-code-dotnet🎯Skill

Provides clean code guidelines and refactoring techniques for C#/.NET, focusing on improving code readability, maintainability, and adherence to SOLID principles.

🎯
abp-entity-patterns🎯Skill

Implements domain layer patterns for ABP Framework, providing robust entity, aggregate, repository, and domain service implementations following DDD principles.

🎯
fluentvalidation-patterns🎯Skill

Validates input DTOs in ABP Framework using FluentValidation with async checks, conditional rules, custom validators, and localized error messages.

🎯
efcore-patterns🎯Skill

Configures and optimizes Entity Framework Core patterns for ABP Framework, focusing on entity configuration, migrations, and relationship design with PostgreSQL.

🎯
abp-api-implementation🎯Skill

Implements comprehensive REST APIs in ABP Framework with robust AppServices, DTOs, pagination, filtering, and authorization for .NET applications.

🎯
claude-artifact-creator🎯Skill

Generates Claude Code artifacts like skills, agents, and commands with best practices and quality standards.

🎯
content-retrieval🎯Skill

content-retrieval skill from thapaliyabikendra/ai-artifacts

🎯
system-design-patterns🎯Skill

Designs scalable, reliable distributed systems by applying proven architectural patterns and evaluating trade-offs across performance, consistency, and availability.

🎯
abp-contract-scaffolding🎯Skill

Generates ABP Application.Contracts layer scaffolding, enabling parallel development by creating standardized interfaces, DTOs, and permissions for .NET microservices.

🎯
openiddict-authorization🎯Skill

Implements permission-based OAuth 2.0 authorization for ABP Framework using OpenIddict, enabling fine-grained access control and multi-tenant security.