.agents/skills/abp-mvc/SKILL.md
ABP MVC and Razor Pages UI - AbpPageModel, abp tag helpers (abp-card, abp-dynamic-form, abp-modal), JavaScript abp.ajax/abp.auth/abp.notify, DataTables integration, bundle/minification. Use when working on MVC or Razor Pages UI in ABP projects.
npx skillsauth add afonsoft/VideoChat abp-mvcInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Docs: https://abp.io/docs/latest/framework/ui/mvc-razor-pages/overall
public class IndexModel : AbpPageModel
{
private readonly IBookAppService _bookAppService;
public List<BookDto> Books { get; set; }
public IndexModel(IBookAppService bookAppService)
{
_bookAppService = bookAppService;
}
public async Task OnGetAsync()
{
var result = await _bookAppService.GetListAsync(
new PagedAndSortedResultRequestDto()
);
Books = result.Items.ToList();
}
}
@page
@model IndexModel
<abp-card>
<abp-card-header>
<abp-row>
<abp-column size-md="_6">
<h2>@L["Books"]</h2>
</abp-column>
<abp-column size-md="_6" class="text-end">
<abp-button button-type="Primary"
id="NewBookButton"
text="@L["NewBook"].Value" />
</abp-column>
</abp-row>
</abp-card-header>
<abp-card-body>
<abp-table striped-rows="true" id="BooksTable">
<thead>
<tr>
<th>@L["Name"]</th>
<th>@L["Price"]</th>
<th>@L["Actions"]</th>
</tr>
</thead>
<tbody>
@foreach (var book in Model.Books)
{
<tr>
<td>@book.Name</td>
<td>@book.Price</td>
<td>
<abp-button button-type="Primary" size="Small"
text="@L["Edit"].Value" />
</td>
</tr>
}
</tbody>
</abp-table>
</abp-card-body>
</abp-card>
<abp-card>
<abp-card-header>Header</abp-card-header>
<abp-card-body>Content</abp-card-body>
<abp-card-footer>Footer</abp-card-footer>
</abp-card>
<abp-button button-type="Primary" text="@L["Save"].Value" />
<abp-button button-type="Danger" icon="fa fa-trash" />
<abp-dynamic-form abp-model="Book" asp-page="/Books/CreateModal">
<abp-modal>
<abp-modal-header title="@L["NewBook"].Value" />
<abp-modal-body>
<abp-form-content />
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Save | AbpModalButtons.Cancel)" />
</abp-modal>
</abp-dynamic-form>
<abp-table striped-rows="true" hoverable-rows="true">
<!-- content -->
</abp-table>
@* In Razor views/pages *@
<h1>@L["Books"]</h1>
@* With parameters *@
<p>@L["WelcomeMessage", Model.UserName]</p>
// Localization
var text = abp.localization.getResource('BookStore')('Books');
// Authorization
if (abp.auth.isGranted('BookStore.Books.Create')) {
// Show create button
}
// Settings
var maxCount = abp.setting.get('BookStore.MaxItemCount');
// Ajax with automatic error handling
abp.ajax({
url: '/api/app/book',
type: 'POST',
data: JSON.stringify(bookData)
}).then(function(result) {
// Success
});
// Notifications
abp.notify.success('Book created successfully!');
abp.notify.error('An error occurred!');
// Confirmation
abp.message.confirm('Are you sure?').then(function(confirmed) {
if (confirmed) {
// User confirmed
}
});
var dataTable = $('#BooksTable').DataTable(
abp.libs.datatables.normalizeConfiguration({
serverSide: true,
paging: true,
ajax: abp.libs.datatables.createAjax(bookService.getList),
columnDefs: [
{
title: l('Name'),
data: 'name'
},
{
title: l('Price'),
data: 'price',
render: function(data) {
return data.toFixed(2);
}
},
{
title: l('Actions'),
rowAction: {
items: [
{
text: l('Edit'),
visible: abp.auth.isGranted('BookStore.Books.Edit'),
action: function(data) {
editModal.open({ id: data.record.id });
}
},
{
text: l('Delete'),
visible: abp.auth.isGranted('BookStore.Books.Delete'),
confirmMessage: function(data) {
return l('BookDeletionConfirmationMessage', data.record.name);
},
action: function(data) {
bookService.delete(data.record.id).then(function() {
abp.notify.success(l('SuccessfullyDeleted'));
dataTable.ajax.reload();
});
}
}
]
}
}
]
})
);
CreateModal.cshtml:
@page
@model CreateModalModel
<abp-dynamic-form abp-model="Book" asp-page="/Books/CreateModal">
<abp-modal>
<abp-modal-header title="@L["NewBook"].Value" />
<abp-modal-body>
<abp-form-content />
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Save | AbpModalButtons.Cancel)" />
</abp-modal>
</abp-dynamic-form>
CreateModal.cshtml.cs:
public class CreateModalModel : AbpPageModel
{
[BindProperty]
public CreateBookDto Book { get; set; }
private readonly IBookAppService _bookAppService;
public CreateModalModel(IBookAppService bookAppService)
{
_bookAppService = bookAppService;
}
public async Task<IActionResult> OnPostAsync()
{
await _bookAppService.CreateAsync(Book);
return NoContent();
}
}
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(
StandardBundles.Styles.Global,
bundle => bundle.AddFiles("/styles/my-styles.css")
);
});
development
This skill enables visual inspection of websites running locally or remotely to identify and fix design issues. Triggers on requests like "review website design", "check the UI", "fix the layout", "find design problems". Detects issues with responsive design, accessibility, visual consistency, and layout breakage, then performs fixes at the source code level.
testing
Comprehensive unit testing with xUnit, mocking, test patterns, and best practices for .NET applications
data-ai
Universal SQL performance optimization assistant for comprehensive query tuning, indexing strategies, and database performance analysis across all SQL databases (MySQL, PostgreSQL, SQL Server, Oracle). Provides execution plan analysis, pagination optimization, batch operations, and performance monitoring guidance.
development
Universal SQL code review assistant that performs comprehensive security, maintainability, and code quality analysis across all SQL databases (MySQL, PostgreSQL, SQL Server, Oracle). Focuses on SQL injection prevention, access control, code standards, and anti-pattern detection. Complements SQL optimization prompt for complete development coverage.