Skip to main content

mvc-razor-ui

Build and debug ABP MVC / Razor Pages UI — pages on AbpPageModel, abp-* tag helpers, the modal system, the bundling system, and per-page CSS/JS. USE FOR: writing pages on AbpPageModel, using abp-* tag helpers (abp-button, abp-modal, abp-dynamic-form, abp-input/select, …), the modal system (abp-modal + abp.ModalManager JS), bundling with AbpBundlingOptions / abp-script(-bundle) / abp-style(-bundle), co-locating page-specific CSS/JS. DO NOT USE FOR: Blazor UI (use blazor-ui), Angular UI (use angular-ui), the IMenuContributor menu pattern and translating localization json (use menus-and-localization), backend permission definitions (use permissions-and-authorization).

跳到安装

来源信息

仓库
abpframework/abp-skills
最近来源活动
2026年7月20日 03:24
检测到的 SKILL.md 语言
英语
星标
18
分支
0

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
mvc-razor-ui
description
Build and debug ABP MVC / Razor Pages UI — pages on AbpPageModel, abp-* tag helpers, the modal system, the bundling system, and per-page CSS/JS. USE FOR: writing pages on AbpPageModel, using abp-* tag helpers (abp-button, abp-modal, abp-dynamic-form, abp-input/select, …), the modal system (abp-modal + abp.ModalManager JS), bundling with AbpBundlingOptions / abp-script(-bundle) / abp-style(-bundle), co-locating page-specific CSS/JS. DO NOT USE FOR: Blazor UI (use blazor-ui), Angular UI (use angular-ui), the IMenuContributor menu pattern and translating localization json (use menus-and-localization), backend permission definitions (use permissions-and-authorization).
license
MIT
# ABP MVC / Razor Pages UI Guidance for building UI on ABP's ASP.NET Core MVC / Razor Pages stack. Framework code lives under `Volo.Abp.AspNetCore.Mvc*` and the `Volo.Abp.AspNetCore.Mvc.UI.*` packages (tag helpers, bundling, theming). ## When to Use - Writing Razor Page models on `AbpPageModel`. - Rendering UI with `abp-*` tag helpers instead of raw Bootstrap markup. - Building modals (a Razor Page wrapped in `abp-modal`, opened via `abp.ModalManager`). - Configuring bundles with `AbpBundlingOptions` and emitting them with the bundle tag helpers. - Co-locating and registering page-specific CSS/JS with `abp-script` / `abp-style`. ## When Not to Use - **Blazor UI** — use the **blazor-ui** skill. - **Angular UI** — use the **angular-ui** skill. - **Contributing menu items or translating localization json** — use the **menus-and-localization** skill (the menu section below only points there). - **Defining backend permissions** — use the **permissions-and-authorization** skill. ## Page base class Derive Razor Page models from `AbpPageModel` (namespace `Volo.Abp.AspNetCore.Mvc.UI.RazorPages`). It extends ASP.NET Core's `PageModel` and gives you framework services (resolved lazily through `LazyServiceProvider`) instead of re-injecting them: - `L` — an `IStringLocalizer`; set `LocalizationResourceType` to bind it to your module's resource. - `CurrentUser`, `CurrentTenant`, `AuthorizationService`, `SettingProvider` - `ObjectMapper` (set `ObjectMapperContext` to pick a profile), `GuidGenerator`, `Clock`, `Logger` - `Alerts` / `AlertManager`, `UnitOfWorkManager` / `CurrentUnitOfWork` - `CheckPolicyAsync(policyName)`, `ValidateModel()`, `RedirectSafelyAsync(returnUrl)` ```csharp public class CreateModalModel : AbpPageModel { public CreateModalModel() { LocalizationResourceType = typeof(MyProjectResource); } public async Task OnGetAsync() { /* L["Key"], CurrentUser, ... */ } } ``` ## Where pages live Razor Pages live under `Pages/` in the web project, grouped by feature (e.g. `Pages/Books/Index.cshtml` + `Index.cshtml.cs`, `CreateModal.cshtml` + `.cs`). Module UIs ship their own `Pages/` inside their `*.Web` packages. Each page pairs a `.cshtml` view with a `.cshtml.cs` model deriving from `AbpPageModel`. ## Tag helpers ABP ships `abp-*` tag helpers (namespace `Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers`) that render Bootstrap markup and honor the active theme. Verified examples: ```html <abp-button button-type="Primary" text="@L["Save"]" icon="check" /> <abp-dynamic-form abp-model="@Model.Book" /> <!-- builds a form from a model + data annotations --> ``` - `<abp-button>` — attrs include `button-type` (`AbpButtonType`), `size`, `text`, `icon`, `icon-type`, `busy-text`, `disabled`. - `<abp-dynamic-form>` — renders a full form from a bound model; skip properties with `[DynamicFormIgnore]`. - Layout/form helpers also exist: `<abp-card>`, `<abp-row>`/`<abp-column>`, `<abp-input>`, `<abp-select>`, `<abp-modal>` (below). Match the tag helpers already used in the project rather than reaching for raw Bootstrap HTML. ## Modal system A modal is a normal Razor Page (its own `.cshtml` + `AbpPageModel`) whose body is wrapped in the `abp-modal` tag helpers. The submit happens by posting a form, so wrap the **entire** `<abp-modal>` in a single `<form>` (matching modules like TenantManagement's `CreateModal.cshtml`) and put the fields in the body with `<abp-input>` / `<abp-select>` — the footer's Save button then submits that form: ```html <form method="post" asp-page="/Books/CreateModal"> <abp-modal size="Large"> <abp-modal-header title="@L["NewBook"]" /> <abp-modal-body> <abp-input asp-for="Book.Name" /> <abp-input asp-for="Book.Price" /> </abp-modal-body> <abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)" /> </abp-modal> </form> ``` To build the whole form from a model instead of listing inputs, use `<abp-dynamic-form>` — it **renders as the `<form>` itself**, so make it the outermost element wrapping the modal and place the fields with `<abp-form-content />` (see the Docs module's `Create.cshtml`). Never nest an `<abp-dynamic-form>` inside another `<form>`. (It only emits its own submit button when `submit-button="true"`; the default does not, so it won't duplicate a footer Save.) `<abp-modal>` attrs: `size` (`AbpModalSize`), `centered`, `scrollable`, `static`. On the calling page, open it from JS with the `abp.ModalManager` global (defined in `.../Theme.Shared/.../bootstrap/modal-manager.js`): ```js var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal'); createModal.open(); // loads the page's HTML into a Bootstrap modal createModal.onResult(function () { dataTable.ajax.reload(); }); ``` `new abp.ModalManager(viewUrl)` (or an options object) returns a manager with `open`, `close`, `reopen`, `onOpen`, `onResult`. It posts the modal form and raises the result callback on success. ## Bundling ABP has its own bundling system configured via `AbpBundlingOptions` (namespace `Volo.Abp.AspNetCore.Mvc.UI.Bundling`) in your module's `ConfigureServices`: ```csharp Configure<AbpBundlingOptions>(options => { options.ScriptBundles .Configure(StandardBundles.Scripts.Global, bundle => { bundle.AddFiles("/global-scripts.js"); }); }); ``` `AbpBundlingOptions` exposes `ScriptBundles` / `StyleBundles`, plus `Mode` (`BundlingMode`), `DeferScriptsByDefault`, `PreloadStylesByDefault`. Reusable bundle content is added via an `IBundleContributor` / `BundleContributor`. Bundles are emitted with the bundle tag helpers `<abp-script-bundle name="...">` and `<abp-style-bundle name="...">`. ## Page-specific CSS/JS Convention: co-locate a page's assets next to the `.cshtml` (e.g. `Index.cshtml` + `Index.cshtml.js` + `Index.cshtml.css`) and register them per page inside `@section scripts` / `@section styles` using the single-file tag helpers `<abp-script>` / `<abp-style>` (verified `[HtmlTargetElement("abp-script")]`): ```cshtml @section scripts { <abp-script src="/Pages/Books/Index.cshtml.js" /> } @section styles { <abp-style src="/Pages/Books/Index.cshtml.css" /> } ``` These minify/version the file and slot it into the right bundle. Prefer them over raw `<script>`/`<link>` so ABP's minification and cache-busting apply. ## Menu contribution MVC/Razor navigation uses the same `IMenuContributor` mechanism as the rest of ABP (`context.Menu.AddItem(new ApplicationMenuItem(...))`, gated on `StandardMenus.Main`), registered through `AbpNavigationOptions`. See the menus-and-localization skill for the full pattern and the rule about translating any new localization keys into every culture's json. ## Validation - The web project builds and the page renders; a model deriving from `AbpPageModel` compiles and its lazily-resolved services (`L`, `CurrentUser`, `Alerts`, …) are available without manual injection. - `abp-*` tag helpers emit themed Bootstrap markup; a modal opened via `abp.ModalManager` loads the page's HTML and fires `onResult` after a successful post. - `abp-script` / `abp-style` and the bundle tag helpers produce versioned (cache-busted) output rather than raw asset tags — the output is minified only when minification is enabled (`BundleAndMinify`, or `Auto` outside Development). ## Common Pitfalls - **Inventing tag helper names** — verify a tag helper exists first (`Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/**`). A tag helper maps to its element via an explicit `[HtmlTargetElement("abp-…")]` or, absent that, via Razor's class-name naming convention (e.g. `AbpModalTagHelper` has no `[HtmlTargetElement]` yet still binds to `<abp-modal>`). - **Nesting `<abp-dynamic-form>` inside another `<form>`** — it renders as the `<form>` itself; make it the outermost element wrapping the modal and place fields with `<abp-form-content />`. - **Wrapping only part of the modal in the form** — wrap the *entire* `<abp-modal>` in a single `<form>` so the footer Save button submits it. - **Using raw `<script>` / `<link>` / raw Bootstrap HTML** — prefer `abp-script` / `abp-style` and `abp-*` tag helpers so cache-busting and theming apply (and minification when it's enabled, i.e. `BundleAndMinify` or `Auto` outside Development); match the tag helpers already used in the project.
在 GitHub 查看