Back to "HTMX 与 ASP.NET 核心部分@:服务器 @-Side复兴"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET Core HTMX HTMX.NET Web Development

HTMX 与 ASP.NET 核心部分@:服务器 @-Side复兴

Friday, 28 November 2025

一. 导言导言 导言 导言 导言

如果您已建立传统的 ASP.NET 核心 MVC 应用程序@, 你知道问题是什么吗? 当用户在页面之间浏览时, 感觉 现代的.

从服务器上返回部分 HTML 碎片并将其转换为 DOM 的方法解决了这个 - 。 自 jQuery days ,}(甚至在此之前)与 Vanilla JavaScript 和 XMLHttpRequest@. @ what' @% 改变的是如何 优雅 与HTMX和.成为一体

HTMX 给了我们一种宣示性的方式来做 我们一直做的 @:\Q returned HTML 并把它转换到页面@.}不再为每次互动量写自定义 JavaScript *#. 没有更多的选择

附录 条款 本篇文章的焦点是 ASP.NET 核心整合面@. 深入潜入 HTMX 事件\ , 生命周期 @, 和自定义扩展@MS K4 见我的配套文章_: HTMX扩展和以 ASP=.NET 核心使用HTMX.

在本篇文章中, , @ I'}会向您展示HTMX是如何与 ASP=.#NET Core parts@,}如何完美融合的。 HTMX.NET 库里让它变得更好 @,#和我的 多数是卢比多的.+#pangging帮手 NuGet 软件包使用 HTMX 提供极强的射程,最小配置@.

这个方法是一个框架 -QQAnostic too @-Jjango 在版本“6.0,铁路”中添加了模板碎片。 而更广泛的网络生态系统包含 HTML-Over}--MS K6Wirtimation_.}它是一个建造服务器的好时机 ~-Reed application@.}

什么是HTMX ??

HTMX 是一个允许您直接从 HTML\ @,}(而不是写入 JavaScript}.}) 访问现代浏览器功能的图书馆。 它扩展了 HTMl, 包含一些属性, 可以让 AAX 请求@ ,} 互换内容@ MPK3 并创建丰富的互动 {% -} 全部不离开您的标记=.}

您'}最常使用的密钥属性@ :}{

  • hx-get, hx-post, hx-put, hx-delete @- 满足 HTTP 请求
  • hx-target - 指定将回复放在何处
  • hx-swap -控制内容如何互换@(innerHTML,}外 HTML□,等
  • hx-trigger @ -_ 定义什么触发请求@ MS K1_ klick\ ,} change @ MPK3load @ MASK4 etc.
  • hx-push-url \ - 更新浏览器 URL, 不重新装入整页

这里的'是它的美景 您 @ ' 仍在寫入伺服器@ MS K3side code\ , returninged HTML.}沒有 JSON APIS, 沒有用戶{-s sideplatesuble}MS K9没有建管

象AJAX自己一样老的模式

在HTMX,}之前,我们取得了同样的效果 举行了更多的仪式...

// jQuery circa 2010
$('#load-more').click(function() {
    $.ajax({
        url: '/posts/page/' + currentPage,
        success: function(html) {
            $('#posts-container').append(html);
            currentPage++;
        }
    });
});

更早的,和香草 JavaScript ]:

// Vanilla JS circa 2005
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        document.getElementById('content').innerHTML = xhr.responseText;
    }
};
xhr.open('GET', '/partial-content', true);
xhr.send();

服务器“-”的侧边图案是相同的 @-}返回 HTML 片段@,} 将它们转换为 DOMQ.HTMX 只是把这个逻辑从 JavaScript 移动到 HTMl 属性, 使它成为声明性=, 发现#, 和远小错误 <-}.} 这个创新就是"'}Technology_; it{'}作为界面=MS K12}

ASP.NET 开发商已经这样做多年了 在WebForms & (2005),}网络格式中更新的平台 PartialView() 从第一天起,在MVC , Html.RenderAction() 我们所缺少的是一种优雅的, 标准的方式 在客户端连接它\ .\ HTMX填补了这个空白

更广大的产业正在重新发现这些图案, 例如 @"@SSRQZK2}(Server-}♪SideRendering}),{"Hybrid Maturation",}和MS K8岛架构"基本上描述了服务器 <,> -边框一直做了些什么? 但有新鲜的眼睛*. ItMSG13}验证 服务器=-Reed 方法“,}用正确的工具‘-}提供出色的用户经验<.〞

在 ASP=.NET 核心中设置 HTMX

第一个, 包含 HTMX 到您的布局@ . 您可以使用 CDN 或者在本地端服务\ MS K2

<script src="https://unpkg.com/[email protected]"></script>

{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你只要放下一个脚本标签 {\fn方正准圆简体\fs12\1cHC9ECC4}然后你就跑到赛马场去

AlpineMS.js:客户端MS K2Side 组件

客户端@- @side reactivity *%sK1_sshowing /}元素\ , 以切换状态,}本地的 UI stateQ, 阿尔卑斯山 提供Vue @/React@-}类似声明性反应,没有上下浮Q.

<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>

这里:'}他们是如何合作的?

<div x-data="{ open: false }">
    <button x-on:click="open = !open">Toggle</button>
    <div x-show="open" x-transition>
        <button hx-get="/api/data" hx-target="#results">Load Data</button>
    </div>
</div>

Alpine 处理本地 JUI @ ( @ tgggle),} HTMX 处理服务器呼叫@ MS K2} 数据抓取\ ). {

HTMX.NET 库

哈立德·阿布哈克梅# '# HTMX.NET 库中提供第一个“-”类 ASP.“NET 核心集成@.” Htmx 和 Htmx.TagHelpers NuGet 套件@, @ @ it feel native to @ .NET, 让HTMX的工作非常令人愉快: @._ You'}你能找到更多Khalid{'}[哈立德】MSK4#s 优秀的开放=-}来源工作 吉特胡布.

安装装置

dotnet add package Htmx
dotnet add package Htmx.TagHelpers

在你的 _ViewImports.cshtml:

@addTagHelper *, Htmx.TagHelpers

IsHtmx @ ()}扩展方法

最有用的特征是: Request.IsHtmx() 扩展方法@, 用于告知您请求是否来自 HTMX.}这样可以让您返回一个完整的视图或仅部分@ :

[HttpGet]
public async Task<IActionResult> Index(int page = 1, int pageSize = 20)
{
    var posts = await blogViewService.GetPagedPosts(page, pageSize);

    if (Request.IsHtmx())
        return PartialView("_BlogSummaryList", posts);

    return View("Index", posts);
}

此模式绝对辉煌 @ . 单一个控制器操作可同时为@ :服务

  • 当用户直接导航或刷新时,全页加载@ ( @% 1}
  • 当HTMX提出要求时, 部分更新@( @% 1}

没有单独的 API 端点@, @没有重复的逻辑\ ,}无 JSON 序列连接管理 *.

一种常见的误解 : 许多 ASP.NET 开发者认为您需要 _ 前缀 @ (@ like _BlogSummaryList.cshtml{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080} PartialView() 方法本身告诉 ASP.NET 核心跳过布局@ - itMS K2s saying @ "}♪ forget the 布局 , 仅仅让这个位数=".可以使用 return PartialView("SearchResults", model) 校对:Portnoy 预定 占部分@ . @

HTMX.NET 标签辅助工具

HTMX.NET 提供标签助手,与控制器一起工作\ . 而不是写入路线字符串@, 您可以使用强烈的 @-}%styped review_:

<button
    hx-controller="Comment"
    hx-action="GetCommentForm"
    hx-post
    hx-target="#commentform">
    Reply
</button>

如果您重命名您的控制器或动作“,” 您的 IDE 将会抓住它 .\ 大大胜过魔法字符串@!+#

@'_@service system=:}在此,

<button
    class="btn btn-outline btn-sm mb-4"
    hx-action="Comment"
    hx-controller="Comment"
    hx-post
    hx-vals
    x-on:click.prevent="window.mostlylucid.comments.setValues($event)"
    hx-on="htmx:afterSwap: window.scrollTo({top: 0, behavior: 'smooth'})"
    hx-swap="outerHTML"
    hx-target="#commentform">
    Comment
</button>

注意HTMX如何与阿尔卑斯山发挥优雅,x-on:click.prevent) 用于客户端的偶发位数 @-}侧面互动@.

其他 HTMX.NET 助手

图书馆也提供@: @

  • Request.IsHtmxNonBoosted() - 检查它是否为 HTMX 请求, 但并未提升
  • Request.IsHtmxRefresh() - 检查它是否为历史恢复请求
  • HTMX 信头的响应帮助 @ ( @ triggers@ MS K1 @ refreeds @ I, @ etc_ .)}

使用部分搜索@ label

这里'%s 是来自此博客的搜索控制器 {,} 显示三MS K2\tier return status@ :}

[HttpGet]
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request", "pagerequest" })]
public async Task<IActionResult> Search(
    string? query,
    int page = 1,
    int pageSize = 10,
    [FromHeader] bool pagerequest = false)
{
    var searchModel = await BuildSearchModel(query, page, pageSize);

    if (pagerequest && Request.IsHtmx())
        return PartialView("_SearchResultsPartial", searchModel.SearchResults);

    if (Request.IsHtmx())
        return PartialView("SearchResults", searchModel);

    return View("SearchResults", searchModel);
}

三种假想的三个返回路径@: @%

  1. 微小部分 ( 仅列出结果列表 @)
  2. 过滤器更改 #% - @ 区域部分 # MS K1 导致过滤器@ )}
  3. 直接导航@- @全页 @(_布置#+}所有东西 @MS K3

部分视图 @( @%_SearchResultsPartial.cshtml@)# 使用传呼标签帮助器@:}

@model Mostlylucid.Models.Blog.PostListViewModel
<div class="pt-2" id="content">
    @if (Model.Data?.Any() is true)
    {
        <div class="inline-flex w-full items-center justify-center pb-4">
            @if (Model.TotalItems > Model.PageSize)
            {
                <pager
                    x-ref="pager"
                    link-url="@Model.LinkUrl"
                    hx-boost="true"
                    hx-target="#content"
                    hx-swap="show:none"
                    page="@Model.Page"
                    page-size="@Model.PageSize"
                    total-items="@Model.TotalItems"
                    hx-headers='{"pagerequest": "true"}'>
                </pager>
            }
        </div>
        @foreach (var post in Model.Data)
        {
            <partial name="_ListPost" model="post"/>
        }
    }
</div>

正在拆分呼叫器标签帮助@ : @

  • hx-boost="true" - 截取链接@, 转换为 AJAX
  • hx-target="#content" - 填入回复的方位
  • hx-headers='{"pagerequest": "true"}' - 自定义信头告诉控制器 it's pagenation
  • 控制器检查 Request.IsHtmx() && pagerequest 仅返回最小部分

多数为lucid @ .}paggingtag帮手套件

我写过 多数是卢比多的.+#pangging帮手 避免重复页码@. @ it'}HTMX#-}首先但工作没有 JavaScript too_.}

安装装置

dotnet add package mostlylucid.pagingtaghelper

添加到 _ViewImports.cshtml:

@addTagHelper *, mostlylucid.pagingtaghelper

密钥特征

执行 IPagingModel<T> {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}而你又完成了

public class BasePagingModel<T> : IPagingModel<T> where T : class
{
    public int Page { get; set; }
    public int TotalItems { get; set; }
    public int PageSize { get; set; }
    public string LinkUrl { get; set; }
    public List<T> Data { get; set; }
}

你得到了什么? :

  • 需要零配置
  • 多个 UI 框架 @ (TailwindCSCS @ MPK1 DisiUí,Bootsstrap {5,自定义视图@)}
  • 暗模式支持
  • @8 @ 语言已建立@-_in
  • 可排序标题@, @}页面大小选择器
  • 没有 JavaScript\ ) 的渐进增强@ ( @ work
  • 继续给 NoSQL 数据库的象征性支持

标签助手生成链接, 以保存查询字符串@ , @ 支持自定义信头 @ MS K1} 并且与 HTMX {(} 无缝融合。 请参见上例).}

HTMX 流程图

这里#' @_%s 整个系统是如何搭配起来的 200)}:}@MSK1

graph TB
    A[Browser] -->|"Initial page load"| B[Controller Action]
    B -->|"Request.IsHtmx() = false"| C[Return Full View]
    C --> D[Render Layout + Partial]

    A -->|"User clicks pagination/filter"| E[HTMX Request]
    E -->|"hx-get with headers"| F[Same Controller Action]
    F -->|"Request.IsHtmx() = true"| G{Check Headers}
    G -->|"pagerequest header"| H[Return Minimal Partial]
    G -->|"No special header"| I[Return Section Partial]

    H --> J[Swap Content in Target]
    I --> J

    J -->|"User clicks another link"| E

    style B stroke:#333,stroke-width:2px
    style F stroke:#333,stroke-width:2px
    style C stroke:#0066cc,stroke-width:2px
    style H stroke:#00cc66,stroke-width:2px
    style I stroke:#00cc66,stroke-width:2px

与其他框架的比较

Django 模板碎片

Django 添加了适当的部分模板, 在版本中提供 @6.0 @ @ ( @ 12 @ I2024)} 并配有模板片段@ ._ 强哥开发商之前通常使用包含标签或第三方@-}政党套件, 如 Django- render-block @ MPK8} ASP=.NET Core PartialView() 不同的框架 @,}不同的时间轴@,}但同一目的地 HTMX=.}的HTMX#MSK6*

涡轮框架

Ruby on Rails有Turbo框架@(部分的热电路 @),}这在精神上是相似的_:

<%= turbo_frame_tag "posts" do %>
  <%= render @posts %>
<% end %>

不同之处在于,涡轮在请求和响应时都需要具体的框架标记@.HTMX更灵活 @-任何终点都可以返回 HTML,。 hx-target.

凤凰实况影视

Elixir 'Phoenix Life LiveView采取不同的方法,使用持续的网络软盘连接和服务器@-side state @:#

def handle_event("load_more", _params, socket) do
  {:noreply, assign(socket, posts: load_more_posts())}
end

LiveView 对真实的 @-#time application@,}来说是辉煌的实况,但是它需要网络软盘基础设施和服务器内存来连接 .HTMX使用普通的旧 HTTP {-Natistrial_,}%,}缩放}.}(对于一个博客 ,}这“'’s perfect=.〞

业绩考量

输出缓存# :# OutputCache 属性因 hx-request 标题@ , @ cacheing full page and parts 分开的整页和部分@ I:} @

[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request", "pagerequest" })]

网络效率:Server-sended HTML通常小于 Jsonon @+}客户端@-sides studiple{,}需要较少的往返旅行}%,}和适当的缓存=.}

套装大小:+HTMX @(14QKBK2+++可选的 [email protected] @MS K5KB#)}++呼叫标记助手 @(0+KB,}伺服器 @MSC10QSideZ)+=+在「30KB 总计=.+和典型的反应应用<(200>相比

高级模式

乐观的用户界面更新 -集HTMX和阿尔卑斯山为即时反馈}:

<div x-data="{ count: @Model.CommentCount }">
    <button hx-post="/comment/like" x-on:click="count++" hx-on::after-request="count = $event.detail.xhr.response">
        Likes: <span x-text="count"></span>
    </button>
</div>

立即更新计数@ ( @ optimetic=),}然后与服务器响应@ MPK2同步

外边的-of-Band Swaps @- 更新一份回复的多页部分@:

<div id="main-content"><!-- Main response --></div>
<div id="notification-count" hx-swap-oob="true"><span>5 new</span></div>

符合通知徽章的完美标准@,马车计数 @,}等等#.我深入覆盖了这个图案 使用 HTMX 显示通吐和互换.

使用 WebAPI 的客户端-Side模板 ,}但来自WebAPI的JSON 用于特定动态内容*.HTMX's 客户端-side-templates 扩展 让您来做这个:吧

<script src="https://unpkg.com/[email protected]/client-side-templates.js"></script>
<script src="https://unpkg.com/mustache@latest"></script>

<div hx-ext="client-side-templates">
    <template id="post-template" type="text/mustache">
        {{#posts}}
        <div class="post">
            <h3>{{title}}</h3>
            <p>{{excerpt}}</p>
        </div>
        {{/posts}}
    </template>

    <button hx-get="/api/posts"
            hx-target="#post-list"
            mustache-template="post-template">
        Load Posts
    </button>
    <div id="post-list"></div>
</div>

此方法与 Mustache @ , @ handlebars@ ,} 或 Nunjucks 模板@ MS K2} 您的 WebAPI 返回 JSON, 但 HTMX 处理着客户端“ - @ sideMSKO5” It{'} 当您已有 API 或者需要与移动应用程序共享数据时特别有用, 请查看 HTM X 扩展的更多细节, 包括客戶端@ MPK8sideMSSK9_ templates@,} 随带的物品,.

加起来的“ &” 提示

调试工具@: @% 安装 HTMX 调试器扩展 @- @ it show every request ,}回应@, @ and sywitch in real @MS K3_time. @

CSRF 代号

ASP=.NET Core'需要使用 AAX}.HTMX.Net 提供几种干净的选项@.}推荐方式的使用 HtmxAntiforgeryScriptEndpoint:

// In Program.cs
app.MapHtmxAntiforgeryScript();
<!-- In your layout head -->
<script src="@HtmxAntiforgeryScriptEndpoints.Path" defer></script>

或使用标签助手@: @% <meta name="htmx-config" includeAspNetAntiforgeryToken="true" />. 见 Khalidó' @s 有关HTMX Anti-@reggery Tokens的文章 完整详细信息@. @%

在 Razor 的 AlpineMSMK0js @ @短手

阿尔卑斯山 @click 与 Razor' @%s 的短手冲突 @ syntax@ . @ 使用明确的表单代替\ :}

<button x-on:click="doSomething()">Click me</button>  <!-- Instead of @click -->
<div x-bind:class="isOpen ? 'block' : 'hidden'"></div>  <!-- Instead of :class -->

或与 @@click@,}但明确的语法更清晰 ∮.∮

历史管理

控制历史条目@: @% 默认情况下, , HTMX 将每个请求都推向历史@ MS K1 用于 pagenation @ /{ filter 您不想要历史污染@ MPK4}

<paging model="@Model" hx-push-url="false">  <!-- Don't add history entries -->

或使用 hx-replace-url="true" 更新 URL 不添加条目@. @%

幻影部分问题 返回浏览器后端@ / @ forward 只显示一个部分碎片, 没有布局@ .} fix with hx-history-elt 容器内容上的“:”

<div class="container mx-auto" id="contentcontainer" hx-history-elt>
    @RenderBody()
</div>

这告诉 HTMX 恢复历史时要保存周围布局的哪个元素

CDN Caching @(_Cloudflare@,}等等 .)

症状: : HTMX 在本地工作, 但是在 CDN -\ 错误内容后面被打破时会缓存@.\ @

根原因@: @% CDN 忽略 HX-Request 您的服务器返回基于此信头的不同内容, 但 CDN 以相同的方式缓存@ .}

ASP.NET 核心固定@: 使用 VaryByHeaderNames:

[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request" })]

CDN 修正@: @% 要包含的配置缓存规则 HX-Request 在缓存密钥“% . ” 中,您可以使用 Cloudflare @: Dashboard *→ 抓取 # MS K3 缓存规则@→ 自定义快取密钥 “→ headers @→}包含 HX-Request.

hx=-}启动辩论

hx-boost 将正则链接转换为 AJAX 请求@. @The HTMX 奇格页面 一些核心团队成员建议避免, @(discard <head> @, 影响行为发生地点@),,

<div hx-boost="true" hx-target="#contentcontainer">
    <a asp-action="Show" asp-route-slug="@post.Slug">Read More</a>
</div>

这个博客广泛使用@.当瞄准特定容器时 @,明确 hx-get 更清晰的“,”但 hx-boost 如果您在 & ' @ re concolance *.% 禁用有选择的 hx-boost="false" 关于儿童元素的.

结论结论

带有 ASP.NET 核心部分的 HTMX 代表着返回服务器\ -}=side simple

  • 动态,SPA-类似互动
  • Server - @side 翻譯@(_great 表示 sEO)}
  • 正确的 HTTP缓存
  • 最小化 JavaScript
  • 逐步加强
  • 使用 HTMX#.NET 类型@-}安全路由
  • Zero- config passiation 与 mostlucidMS K1pangtag helper

服务器“-”的发送方式经受了时间的考验。 HTMX@,}它终于有了优雅的客户端“MS K3”的辅助工具,值得您使用 “.”来建立坚固的网络应用程序。

本博客上的相关文章

随带条款

此篇文章是 HTMX 与 ASP @.}NET Core: 的两集中的一部分。

  1. 本条本条 @- 聚焦于 ASP.NET核心整合@,部分观点 @MS K3}HTMX.NetMSKO5和页码
  2. HTMX 扩展的口哨服务 - 深潜到 HTMX 事件@, 寿命周期 @, 扩展架构_, 和自定义延伸

更多HTMX文章

继续阅读

正式文件_:

圖書館&工具MS K1

社区资源@:

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.