使用Blazor 来实现前后端统一使用C#开发,用C#写前端,想想就刺激😃
什么是Blazor
Blazor 是一个使用 .NET 生成交互式客户端 Web UI 的框架:
使用 C# 代替 JavaScript 来创建信息丰富的交互式 UI。
共享使用 .NET 编写的服务器端和客户端应用逻辑。
将 UI 呈现为 HTML 和 CSS,以支持众多浏览器,其中包括移动浏览器。
与新式托管平台(如 Docker )集成。
使用 .NET 进行客户端 Web 开发可提供以下优势:
使用 C# 代替 JavaScript 来编写代码。
利用现有的 .NET 库 生态系统。
在服务器和客户端之间共享应用逻辑。
受益于 .NET 的性能、可靠性和安全性。
在 Windows、Linux 和 macOS 上使用 Visual Studio 保持高效工作。
以一组稳定、功能丰富且易用的通用语言、框架和工具为基础来进行生成
Blazor应用基于组件。 Blazor 中的组件是指 UI 元素,例如页面、对话框或数据输入窗体。
组件是内置到 .NET 程序集 的 .NET C# 类,它们用于:
创建项目
此文使用 vs2019 .net core 3.1
这里我从空项目开始创建。
配置项目
配置Starup
ConfigureServices 1 2 3 4 5 6 7 8 public void ConfigureServices (IServiceCollection services ){ services.AddRazorPages(); services.AddServerSideBlazor(); }
Configure 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public void Configure (IApplicationBuilder app, IWebHostEnvironment env ) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("_Host" ); }); }
配置通用依赖项
创建_Imports.razor 文件加入内容
1 2 3 4 5 6 7 8 9 @using System.Net.Http @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.JSInterop @using BlazorAppGo @using BlazorAppGo.Shared
书写_Host主页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @page "/" @namespace BlazorAppGo.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = null; } <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="utf-8" /> <meta name ="viewport" content ="width=device-width, initial-scale=1.0" /> <title > BlazorAppGo</title > <base href ="~/" /> <link rel ="stylesheet" href ="css/bootstrap/bootstrap.min.css" /> <link href ="css/site.css" rel ="stylesheet" /> </head > <body > <app > <component type ="typeof(App)" render-mode ="ServerPrerendered" /> </app > <div id ="blazor-error-ui" > <environment include ="Staging,Production" > An error has occurred. This application may no longer respond until reloaded. </environment > <environment include ="Development" > An unhandled exception has occurred. See browser dev tools for details. </environment > <a href ="" class ="reload" > Reload</a > <a class ="dismiss" > 🗙</a > </div > <script src ="_framework/blazor.server.js" > </script > </body > </html >
Razor 页面
在Blazor中,每一个页面以.cshtml结尾,页面可以绑定一个模型类用户数据操作。
Rezor布局
在Blazor中,在Shared文件夹下书写布局和通用组件。创建.razor结尾的文件写入如下文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @inherits LayoutComponentBase <div class ="sidebar" > <NavMenu /> </div > <div class ="main" > <div class ="top-row px-4" > <a href ="https://docs.microsoft.com/aspnet/" target ="_blank" > About</a > </div > <div class ="content px-4" > @Body </div > </div >
在布局文件中,使用@inherits LayoutComponentBase 来继承自LayoutComponentBase 标注为布局文件
App.razor
创建App.razor文件用于配置路由情况和默认布局
1 2 3 4 5 6 7 8 9 10 11 <Router AppAssembly ="@typeof(Program).Assembly" > <Found Context ="routeData" > <RouteView RouteData ="@routeData" DefaultLayout ="@typeof(MainLayout)" /> </Found > <NotFound > <LayoutView Layout ="@typeof(MainLayout)" > <p > Sorry, there's nothing at this address.</p > </LayoutView > </NotFound > </Router >
Razor 组件
创建.razor结尾的文件作为Razaor组件,组件可以在其他页面或组件中复用
直接使用<组件名称>当作html元素使用即可。
CURD小例子
EF连接Sqlite
在数据库连接上,这里我使用比较简单的sqlite
安装相关包
实体配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 using Microsoft.EntityFrameworkCore;namespace BlazorAppGo.Models { public class AppDbContext : DbContext { public DbSet<User> Users { get ; set ; } public AppDbContext (DbContextOptions<AppDbContext> options ) : base (options ) { } protected override void OnConfiguring (DbContextOptionsBuilder optionsBuilder ) { base .OnConfiguring(optionsBuilder); } protected override void OnModelCreating (ModelBuilder modelBuilder ) { base .OnModelCreating(modelBuilder); } } }
注入
1 services.AddDbContext<AppDbContext>(options => options.UseSqlite(Configuration.GetConnectionString("sqlite" )));
appsetting
1 2 3 4 "ConnectionStrings" : { "sqlite" : "Data Source=./myData.db" } ,
service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 using BlazorAppGo.Models;using System.Collections.Generic;using System.Linq;namespace BlazorAppGo.Services { public class UserService { private readonly AppDbContext dbContext; public UserService (AppDbContext dbContext ) { this .dbContext = dbContext; } public void Add (User user ) { dbContext.AddAsync(user); dbContext.SaveChanges(); } public void Update (int id, User data ) { var user = dbContext.Users.FirstOrDefault(x => x.Id == id); user.Name = data.Name; dbContext.Update(user); dbContext.SaveChanges(); } public void Remove (int id ) { dbContext.Remove(dbContext.Users.FirstOrDefault(x => x.Id == id)); dbContext.SaveChanges(); } public List<User> List () { return dbContext.Users.ToList(); } public User FindOne (int id ) { return dbContext.Users.FirstOrDefault(x => x.Id == id); } } }
注入 1 2 3 4 5 6 7 services.AddScoped<AppDbContext>(); services.AddScoped<UserService>();
Razor界面
userList
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 @page "/userList" @using BlazorAppGo.Models @using BlazorAppGo.Services @inject BlazorAppGo.Services.UserService userService @inject NavigationManager NavigationManager <button class ="btn btn-primary" @onclick="Add" >新增</button> <div class ="row" > <div class ="col-1" >ID</div> <div class ="col-2" ><input type="text" class ="form-control" @bind-value ="id" ></div> <div class ="col-1" >Name</div> <div class ="col-2" ><input type="text" class ="form-control" @bind-value ="name" ></div> </div> <table class ="table" style="margin-top:15px" > <thead> <tr> <th>ID</th> <th>Name</th> <th>Options</th> </tr> </thead> <tbody> @foreach (var user in users) { <tr> <td>@user.Id</td> <td>@user.Name</td> <td> <button class ="btn btn-info" @onclick="@(e=>Info(user.Id))" >详细</button> <a href="/userUpdate/@user.Id" class ="btn btn-warning" >修改</a> <button class ="btn btn-danger" @onclick="@(e=>Del(user.Id))" >删除</button> </td> </tr> } </tbody> </table> <h3>@cid</h3> @code { private List<User> users; private int id; private string name; private int cid; protected override void OnInitialized () { users = userService.List(); } private void Add () { userService.Add(new User { Id = id, Name = name }); users = userService.List(); ShouldRender(); } private void Info (int id ) { NavigationManager.NavigateTo($"/userInfo/{id} " ); } private void Del (int id ) { userService.Remove(id); users = userService.List(); ShouldRender(); } }
userUpdate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @page "/userUpdate/{Id}" @inject BlazorAppGo.Services.UserService userService <button class ="btn btn-primary" @onclick="Save" >保存</button> <div class ="row" > <div class ="col-1" >ID</div> <div class ="col-2" ><input type="text" class ="form-control" @bind-value ="Id" ></div> <div class ="col-1" >Name</div> <div class ="col-2" ><input type="text" class ="form-control" @bind-value ="name" ></div> </div> @if (show) { <h4>修改成功</h4> } <a href="/userList" >返回</a> @code { [Parameter ] public string Id { get ; set ; } string name; bool show; protected override void OnInitialized () { var user = userService.FindOne(int .Parse(Id)); name = user.Name; } void Save () { userService.Update(int .Parse(Id), new Models.User { Id = int .Parse(Id), Name = name }); show = true ; } }
userInfo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @page "/userInfo/{Id}" @inject BlazorAppGo.Services.UserService userService <h1>UserInfo @Id</h1> <h2>Id:@Id</h2> <h2>Name:@Name</h2> <a href="/userList" class ="btn btn-primary" >返回</a> @code{ [Parameter ] public string Id { get ; set ; } private string Name; protected override void OnInitialized () { var user = userService.FindOne(int .Parse(Id)); Name = user.Name; } }
效果