.NET 8 Web开发入门(六):Blazor 全栈开发——告别 JavaScript 焦虑

大家好,我是码农刚子。最近好几天没更了,刷课时、考试、兼职,搞得我眼睛的睁不开了,今天终于有时间更新一篇。也不知道有没有朋友在期待?

一、前言:后端开发的"前端痛"

在传统开发中,全栈往往意味着你要精通 C# 还要精通 JavaScript、HTML、CSS,甚至还要学 React 或 Vue 的一大堆生命周期和状态管理库。这对很多专注于业务逻辑的后端同学来说,简直是噩梦。

微软也意识到了这个痛点,于是 Blazor 诞生了。

Blazor 的核心理念很简单:用 C# 替代 JavaScript。你可以在 Razor 页面里写 C# 代码,处理点击事件,甚至直接操作 DOM(虽然不推荐)。这让 .NET 开发者拥有了无缝的全栈开发能力。

二、Blazor Server:实时交互的黑魔法

Blazor 主要有两种托管模型,新手最容易搞混,刚子先帮你理一理:

  1. Blazor WebAssembly (客户端):应用被编译成 WebAssembly,直接在浏览器里运行。这就像 React 一样,部署在静态服务器上,不依赖服务器实时计算。
  2. Blazor Server (服务端) :应用在服务器上运行,通过 SignalR(一种 WebSocket 技术)与浏览器实时通信。

刚子敲黑板 : 本教程选择 Blazor Server 作为入门。为什么?

  • 调试简单:你可以直接在 Visual Studio 里打断点,断点会停在后端的 C# 代码上,就像调试普通后台代码一样。
  • 加载快:浏览器不需要下载整个 .NET 运行时,首屏加载速度极快。
  • 适合后台管理系统:非常适合企业内部使用的后台管理界面开发。

三、动手实战:创建第一个 Blazor 项目

我们重新创建一个项目,为了方便演示,这次建立一个独立的 Blazor Server 项目。

3.1 创建项目

在终端执行:

bash 复制代码
dotnet new blazorserver -n MyTodoUI
cd MyTodoUI
dotnet run

可视化界面创建项目: 打开vs2022→点击创建新项目→选择Blazor Web 应用,点击下一步→依次输入项目名称、解决方案及项目文件路径,点击下一步→选择.NET 8 ,点击创建即可

启动后,浏览器访问 https://localhost:xxxx,你会看到一个漂亮的官方模板页面。

注意:这里创建应用时要选择 Blazor Web 应用 而不是 Blazor Server 应用从.NET 8开始,经典的"Blazor Server"模板已被全新的"Blazor Web App"模板所取代,这一点在微软的官方文档和技术社区中都有提及。新的模板统一了Blazor Server和Blazor WebAssembly的开发体验,并引入了更灵活的"交互渲染模式"(Interactive Render Modes),因此VS不再直接提供名为"Blazor Server"的.NET 8项目选项。创建Blazor Server 应用不支持.NET 8。

3.2 项目结构解析

打开项目,重点关注以下几个文件夹:

  • Layout/ :存放公共布局组件,如 MainLayout.razor(布局模板)和 NavMenu.razor(导航菜单)。
  • Pages/ :存放 .razor 页面组件。比如 Home.razor 就是首页。
  • _Imports.razor :类似于 using 命名空间,这里引入的命名空间会自动应用到所有 Razor 组件。

四、组件化开发:一切皆组件

Blazor 的开发模式是组件化的。一个页面通常由多个小组件拼凑而成。

4.1 创建一个简单的计数器组件

打开 Pages/Home.razor,把内容清空,写入以下代码:

razor 复制代码
@page "/" <!-- 路由:访问根路径时显示这个组件 -->
@rendermode InteractiveServer

<h1>欢迎来到刚子的计数器</h1>

<p>当前计数: <strong>@currentCount</strong></p>

<button class="btn btn-primary" @onclick="IncrementCount">点击我 +1</button>

@code {
    // 这里写 C# 逻辑
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

代码解析

  • @page "/":定义路由,告诉 Blazor 这是首页。
  • @currentCount:使用 @ 符号将 C# 变量输出到 HTML 中。
  • @onclick="IncrementCount":将 HTML 的点击事件绑定到 C# 的方法上。

运行项目,点击按钮,你会发现数字变了!而且完全不需要写 JavaScript,也不用操作 DOM(document.getElementById...),Blazor 会自动帮你更新界面。

五、实战进阶:连接后端 API

光有个计数器没意思,我们要把之前教程里做好的 Todo API 接入进来。

为了模拟真实的前后端分离场景,我们假设后端 API 运行在 http://localhost:5000

快速新建一个极简的 ASP.NET Core Web API

不需要手动写控制器,直接用 最小 API 方式,几行代码就搞定。步骤如下:

  1. 在现有解决方案中添加新项目

右键解决方案 → 添加 → 新建项目

选择 ASP.NET Core Web API

项目名称:TodoApi

框架:.NET 8

**    不勾选**"使用控制器" (这样会生成最小 API 模板)

  1. 修改 Program.cs 为以下代码
csharp 复制代码
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 内存数据存储
var todos = new List<Todo>
{
    new Todo { Id = 1, Title = "学习 Blazor", IsDone = false },
    new Todo { Id = 2, Title = "测试 API", IsDone = true }
};


// GET /todos
app.MapGet("/todos", () => todos);

// DELETE /todos/{id}
app.MapDelete("/todos/{id}", (int id) =>
{
    var todo = todos.FirstOrDefault(t => t.Id == id);
    if (todo == null) return Results.NotFound();
    todos.Remove(todo);
    return Results.NoContent();
});

// POST /todos
app.MapPost("/todos", (Todo todo) =>
{
    todo.Id = todos.Max(t => t.Id) + 1;
    todos.Add(todo);
    return Results.Created($"/todos/{todo.Id}", todo);
});

app.Run();

public class Todo
{
    public int Id { get; set; }
    public string? Title { get; set; }
    public bool IsDone { get; set; }
}

注意路由是 /todos(复数),没有 api 前缀。后面的前端调用也需要同步修改。

5.1 注入 HttpClient

在 Blazor Web App 中,我们通过 HttpClient 发起网络请求。首先在 Program.cs 中注册服务:

csharp 复制代码
// Program.cs

// ... 其他代码 ...

// 注册 HttpClient,BaseAddress 设为后端 API 地址
builder.Services.AddScoped(sp => new HttpClient 
{ 
    BaseAddress = new Uri("http://localhost:5000") // 这里替换为你实际的后端地址
});

// ...

5.2 定义数据模型

为了接收 JSON 数据,我们需要定义一个简单的 DTO 类。在项目中新建 Models/TodoItemDto.cs

csharp 复制代码
public class TodoItemDto
{
    public int Id { get; set; }
    public string? Title { get; set; }
    public bool IsDone { get; set; }
}

5.3 获取并展示数据

新建一个页面 Pages/Todo.razor

razor 复制代码
@page "/todo"
@rendermode InteractiveServer
@using MyTodoUI.Models
@inject HttpClient Http 

<h1>待办事项列表</h1>

@if (todos == null)
{
    <p><em>正在加载数据...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>标题</th>
                <th>状态</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in todos)
            {
                <tr>
                    <td>@item.Id</td>
                    <td>@item.Title</td>
                    <td>@(item.IsDone ? "已完成" : "进行中")</td>
                    <td>
                        <button class="btn btn-sm btn-danger" @onclick="() => DeleteTodo(item.Id)">删除</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private List<TodoItemDto>? todos;

    // 组件初始化时触发,适合加载数据
    protected override async Task OnInitializedAsync()
    {
        try 
        {
            // 调用 GET /todos 接口
            todos = await Http.GetFromJsonAsync<List<TodoItemDto>>("todos");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取数据失败: {ex.Message}");
        }
    }

    private async Task DeleteTodo(int id)
    {
        // 调用 DELETE /todos/{id} 接口
        await Http.DeleteAsync($"todos/{id}");
        
        // 刷新列表
        todos = await Http.GetFromJsonAsync<List<TodoItemDto>>("todos");
    }
}

刚子小贴士 : 注意到 @inject HttpClient Http 了吗?这依然是依赖注入。Blazor 的组件本质上也是一个类,我们可以直接在视图中注入服务,非常方便。

另外 Blazor Web App,务必在组件上添加 @rendermode InteractiveServer

OnInitializedAsync 是 Blazor 的生命周期方法,相当于 React 的 useEffect 或 Vue 的 mounted,在这里发起网络请求是最标准的做法。

六、双向绑定:让表单变简单

Web 开发离不开表单。Blazor 提供了强大的双向绑定功能。

6.1 添加新待办

我们在 Todo.razor 底部添加一个输入框:

razor 复制代码
<h3>添加新任务</h3>
<EditForm Model="@newTodo" OnValidSubmit="@AddTodo">
    <div class="form-group">
        <InputText @bind-Value="newTodo.Title" class="form-control" placeholder="输入任务内容" />
    </div>
    <button type="submit" class="btn btn-success mt-2">提交</button>
</EditForm>

@code {
    // ... 之前的代码 ...

   private TodoItemDto newTodo = new TodoItemDto() { };

	 private async Task AddTodo()
	 {
			 // 调用 POST /todos 接口
			 var response = await Http.PostAsJsonAsync("todos", newTodo);

			 if (response.IsSuccessStatusCode)
			 {
					 newTodo = new TodoItemDto(); // 清空输入框
					 todos = await Http.GetFromJsonAsync<List<TodoItemDto>>("todos"); // 刷新列表
			 }
	 }
}

核心解析

  • @bind="newTodo.Title":这是双向绑定的魔法。当你在输入框打字时,newTodo.Title 会自动更新;当你修改 newTodo 时,输入框也会自动变。
  • EditForm:Blazor 提供的表单组件,可以集成我们之前讲的 DataAnnotations 验证。

刚子敲黑板 : Blazor 的表单处理比原生 HTML 强大得多。你甚至可以在 InputText 上加 <DataAnnotationsValidator />,直接复用我们在第五篇写的验证规则,前端连验证逻辑都不用写了!

七、延伸阅读:刚子的 Blazor 深度系列

本篇实战教程旨在帮你快速打通前后端。如果你在实战过程中,想要更深入地了解 Blazor 的基础概念、路由机制、布局系统或 JS 交互,强烈推荐阅读我之前整理的系列专栏,那里有更细致的图文讲解:

通过这些文章,你将建立起完整的 Blazor 知识体系。

八、总结与下篇预告

在这篇教程中,我们通过 Blazor Server 实现了一个简单但完整的"全栈"功能:

  1. 理解了 Blazor Server 的实时通信原理。
  2. 学会了使用 @inject 注入服务。
  3. 实现了从后端 API 获取数据、删除数据和提交数据。
  4. 掌握了双向绑定简化表单开发。

现在的你,已经具备了独立开发一个小型管理系统的能力:后端用 Minimal API + EF Core,前端用 Blazor Server,全部用 C# 贯通。

下一篇预告

我们的应用已经能跑能跳了,但在互联网上裸奔是很危险的。谁都可以调用你的 /todos 接口吗?显然不行。 在下一篇教程中,我们将引入 身份验证与授权。刚子将带你深入了解 JWT (JSON Web Token),给你的 API 加上"门禁卡",只有拿着正确 Token 的用户才能进出。

安全防线,即将构筑!

如果本篇教程你对有用,欢迎点赞、收藏、转发给你身边的朋友,一起学习。

原文链接:.NET 8 Web开发入门(六):Blazor 全栈开发------告别 JavaScript 焦虑 - 码农刚子的开发笔记

相关推荐
颂love7 天前
健康打卡系统项目总结
fastapi·sqlalchemy·全栈开发·dify集成
求学中--12 天前
鸿蒙实战:用状态管理实现一个完整的Todo应用,从@State到@Provide全链路打通
华为·harmonyos·组件化开发·完整项目
雪碧聊技术15 天前
大模型爆火!Java后端如何抓住Agent全栈开发的风口
java·大模型·agent·全栈开发
渔舟小调1 个月前
P10 | 景点管理:分页查询与全文搜索实现
全栈开发·ai开发·全栈研发
ZHENGZJM1 个月前
文档解析器:支持 PDF、DOCX、Markdown
react.js·pdf·全栈开发
ZHENGZJM1 个月前
前端流式通信 Hook:useBlogStream 详解
前端·全栈开发
ZHENGZJM1 个月前
架构总览:Monorepo 结构与容器化部署
架构·go·react·全栈开发
一只小阿乐2 个月前
vue前端处理流式数据
前端·javascript·ai·大模型·全栈开发·agentai