ASP.NET MVC迁移Blazor:Web API与Blazor共享模型方案咨询
最佳方案:共享类库 + 客户端数据管理实践
一、共享模型类库的实现
这是复用模型的核心方案,步骤如下:
- 创建**.NET Standard 2.1+或.NET 6+**类库项目(Blazor WebAssembly和Web API均兼容此目标框架)
- 将Web API中
Manga、MangaChapterViewModel等模型迁移至该类库,保留序列化相关特性(如[JsonPropertyName]、[Required])以保证两端序列化逻辑一致 - 在Web API项目和Blazor客户端项目中添加对该类库的引用
示例模型代码:
// 共享类库中的模型定义 using System.Text.Json.Serialization; namespace SharedModels { public class Manga { [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("title")] public string Title { get; set; } = string.Empty; [JsonPropertyName("author")] public string Author { get; set; } = string.Empty; } public class MangaChapterViewModel { [JsonPropertyName("chapterNumber")] public int ChapterNumber { get; set; } [JsonPropertyName("title")] public string Title { get; set; } = string.Empty; [JsonPropertyName("releaseDate")] public DateTime ReleaseDate { get; set; } } }
二、Blazor客户端序列化/反序列化配置
Blazor WebAssembly默认使用System.Text.Json,与Web API默认序列化工具一致,需确保两端配置对齐:
在Blazor的Program.cs中配置HttpClient的序列化选项:
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }.ConfigureHttpClientJsonOptions(options => { // 与Web API保持驼峰命名规则 options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; // 序列化时忽略null值 options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; }));
三、Blazor客户端HTTP请求封装
建议封装统一的API服务类,避免重复编写HTTP请求逻辑,同时直接复用共享模型:
// Blazor客户端的API服务类 using SharedModels; using System.Net.Http.Json; namespace BlazorClient.Services { public class MangaApiService { private readonly HttpClient _httpClient; public MangaApiService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<List<Manga>> GetAllMangasAsync() { return await _httpClient.GetFromJsonAsync<List<Manga>>("api/manga") ?? new List<Manga>(); } public async Task<MangaChapterViewModel?> GetChapterAsync(int mangaId, int chapterNumber) { return await _httpClient.GetFromJsonAsync<MangaChapterViewModel>($"api/manga/{mangaId}/chapters/{chapterNumber}"); } // 新增漫画示例方法 public async Task<Manga> AddMangaAsync(Manga newManga) { var response = await _httpClient.PostAsJsonAsync("api/manga", newManga); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<Manga>() ?? new Manga(); } } }
在Program.cs中注册该服务:
builder.Services.AddScoped<MangaApiService>();
四、客户端模型管理实践
1. 组件内数据管理
在Blazor组件中通过依赖注入获取API服务,直接加载并使用共享模型:
@page "/mangas" @inject MangaApiService MangaService @using SharedModels <h3>漫画列表</h3> @if (_mangas == null) { <p><em>加载中...</em></p> } else { <ul> @foreach (var manga in _mangas) { <li>@manga.Title - @manga.Author</li> } </ul> } @code { private List<Manga>? _mangas; protected override async Task OnInitializedAsync() { _mangas = await MangaService.GetAllMangasAsync(); } }
2. 全局状态管理(可选)
如果多个组件需要共享同一模型数据(如用户选中的漫画),可实现简单的状态容器:
// 全局状态容器 using SharedModels; namespace BlazorClient.State { public class MangaStateContainer { public Manga? SelectedManga { get; set; } public event Action? OnChange; public void SetSelectedManga(Manga manga) { SelectedManga = manga; NotifyStateChanged(); } private void NotifyStateChanged() => OnChange?.Invoke(); } }
注册为单例服务:
builder.Services.AddSingleton<MangaStateContainer>();
在组件中使用状态容器:
@inject MangaStateContainer State @using SharedModels <button @onclick="SelectManga">选择当前漫画</button> @code { [Parameter] public Manga? CurrentManga { get; set; } private void SelectManga() { if (CurrentManga != null) { State.SetSelectedManga(CurrentManga); } } }
注意事项
- 不要在共享模型中添加Web API专属特性(如EF Core的
[Key]、[Table]),若需数据库映射,可拆分模型:共享DTO模型 + Web API项目内的EF实体模型,用AutoMapper等工具实现转换 - 确保日期、枚举等类型在两端的序列化配置一致,避免解析错误
- Blazor中HttpClient为作用域/单例对象,禁止在模型中持有HttpClient引用,需通过依赖注入获取
内容的提问来源于stack exchange,提问作者Darth Vader
相关产品推荐
相关产品推荐

