目录
介绍
储存库和数据库
解决方案结构
设计哲学
UI结构
页面
ViewManager
Views
布局
表单
控件
CEC.Blazor.WASM.Client项目
index.html
CSS
Program.cs
ServiceCollectionExtensions.cs
CEC.Blazor.WASM.Server项目
WeatherForecastController.cs
ServiceCollectionExtensions.cs
CEC.Blazor.Server项目
Pages
Startup.cs
ServiceCollectionExtensions.cs
总结
介绍本系列文章着眼于如何在Blazor中构建和构造一个真正的数据库应用程序。有6篇文章:
- 项目结构与框架
- 服务——构建CRUD数据层
- View组件——UI中的CRUD编辑和查看操作
- UI组件——构建HTML / CSS控件
- View组件-UI中的CRUD列表操作
- 逐步详细介绍如何向应用程序添加气象站和气象站数据
他们记录了我当前用于开发Blazor应用程序的框架。
他们不是:
- 尝试定义最佳做法。
- 成品。
根据您的需要或多或少的使用,请提供建议。
我确实提出了一些建议,主要是为了使Blazor的新手摆脱黑洞。例如,我建议停用Page这个词。路由组件不是页面。将其标记为页面,甚至是在下意识的情况下,它也会获得根本不适用的网页属性。我在显示它们的组件——RouteView之后使用术语视图。
第一部分描述了我的一些激进的开发方法,并逐步介绍了GitHub存储库上的两个项目——Blazor Server和WASM/Backend API项目——解释了结构。
储存库和数据库CEC.Blazor GitHub存储库
存储库中的一个SQL脚本位于/SQL中,用于构建数据库。
您可以在此处查看运行的项目的服务器版本。
您可以在此处查看该项目的WASM版本。
解决方案结构我使用Visual Studio,因此Github存储库由一个包含五个项目的解决方案组成。这些是:
- CEC.Blazor——核心库,包含可以在任何项目中重复使用和重用的所有内容。
- CEC.Weather——这是服务器和WASM专家共享的库。几乎所有项目代码都位于此处。示例包括EF DB上下文、模型类、特定于模型的CRUD组件、Bootstrap SCSS、视图、表单...
- CEC.Blazor.Server——服务器项目。
- CEC.Blazor.WASM.Server——WASM后端服务器项目。具有支持代码的API控制器。
- CEC.Blazor.WASM.Client——WASM客户端项目。
该项目的数据端是按照常规的结构构建的,大致基于三层模型(数据、逻辑层和表示层)。公开的数据类均作为服务运行,并且可用于依赖项注入。第二篇文章将详细介绍。
用户界面更为激进:
- 自定义Component类用作基本UI组件——ControlBase仅由开箱即用的数据控件使用。
- 路由被丢弃。有一个管理用户界面的新ViewManager。
页面是充当应用程序主机的网页。通常每个应用程序一个。
ViewManagerViewManager是在 RenderTree
中的子根组件,由应用程序载入。目的是管理和加载视图。支持ViewData类用于存储View配置数据。使用的主要方法是LoadViewAsync。有多种版本,但所有版本均加载ViewData中定义的View。ViewManager通过级联值将自身暴露给所有其他组件。
视图是由ViewManager加载到页面中的组件。他们必须实现IView并可以定义布局。
public interface IView : IComponent
{
/// provides a unique reference for the instance of the view
public Guid GUID => Guid.NewGuid();
/// The cascaded ViewManager Instance
[CascadingParameter] public ViewManager ViewManager { get; set; }
}
布局
布局是Blazor的即用型布局。ViewManager
会以作为子内容的View呈现Layout
。
表单是控件的逻辑集合,这些控件显示在视图或模式对话框中。列表、视图表单、编辑表单都是经典表单。表单包含的控件不是HTML。
控件控件是显示某些内容的组件:它们触发HTML代码。例如,编辑框、下拉菜单、按钮...窗体是控件的集合。
CEC.Blazor.WASM.Client项目该项目几乎是空的。控件和服务都在库中。
index.htmlindex.html 几乎是标准的问题:
- 添加了样式表引用。请注意,您使用虚拟目录_content/Assembly_Name访问依赖程序集wwwroot文件夹中公开的内容。脚本的访问方式相同。
- app的基本内容是HTML块,在应用程序初始化时显示微调框。
CEC.Blazor.WASM
Web Application Loading
An unhandled error has occurred.
Reload
🗙
CSS
所有CSS都是共享的,因此位于CEC.Weather中。我使用Bootstrap,并通过SASS对其进行了一些自定义。我在Visual Studio中安装了WEB COMPILER扩展程序,可以即时编译SASS文件。
Program.csCEC.Blazor和本地应用程序服务一起加载。请注意,此处定义了Blazor根组件。您不必使用App。
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
// Full class name used here to make it a little more obvious.
// Not required if the assemble is referenced.
builder.RootComponents.Add("app");
// Added here as we don't have access to builder in AddApplicationServices
builder.Services.AddScoped(sp => new HttpClient
{ BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
// the Services for the CEC.Blazor Library
builder.Services.AddCECBlazor();
// the local application Services defined in ServiceCollectionExtensions.cs
builder.Services.AddApplicationServices();
await builder.Build().RunAsync();
}
ServiceCollectionExtensions.cs
加载的特定于站点的服务是控制器服务WeatherForecastControllerService和作为IWeatherForecastDataService接口加载的数据服务WeatherForecastWASMDataService。最终的临时服务是“编辑”表单的Fluent验证程序。
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
// Scoped service for the WASM Client version of WeatherForecast Data Service
services.AddScoped();
// Scoped service for the WeatherForecast Controller Service
services.AddScoped();
// Transient service for the Fluent Validator for the WeatherForecast record
services.AddTransient();
return services;
}
}
CEC.Blazor.WASM.Server项目
服务器项目中的唯一文件,除了对试图导航到该站点的任何人进行错误处理外,都是WeatherForecast Controller和启动/程序文件。
WeatherForecastController.cs这是一个标准的API类型控制器。它使用已注册IWeatherForecastDataService的数据层通过IWeatherForecastDataService接口进行异步调用。
[ApiController]
public class WeatherForecastController : ControllerBase
{
protected IWeatherForecastDataService DataService { get; set; }
private readonly ILogger logger;
public WeatherForecastController(ILogger logger,
IWeatherForecastDataService weatherForecastDataService)
{
this.DataService = weatherForecastDataService;
this.logger = logger;
}
[MVC.Route("weatherforecast/list")]
[HttpGet]
public async Task GetList() =>
await DataService.GetRecordListAsync();
[MVC.Route("weatherforecast/count")]
[HttpGet]
public async Task Count() => await DataService.GetRecordListCountAsync();
[MVC.Route("weatherforecast/get")]
[HttpGet]
public async Task
GetRec(int id) => await DataService.GetRecordAsync(id);
[MVC.Route("weatherforecast/read")]
[HttpPost]
public async Task
Read([FromBody]int id) => await DataService.GetRecordAsync(id);
[MVC.Route("weatherforecast/update")]
[HttpPost]
public async Task Update([FromBody]DbWeatherForecast record) =>
await DataService.UpdateRecordAsync(record);
[MVC.Route("weatherforecast/create")]
[HttpPost]
public async Task Create([FromBody]DbWeatherForecast record) =>
await DataService.CreateRecordAsync(record);
[MVC.Route("weatherforecast/delete")]
[HttpPost]
public async Task Delete([FromBody] DbWeatherForecast record) =>
await DataService.DeleteRecordAsync(record);
}
ServiceCollectionExtensions.cs
特定于站点的服务是加载WeatherForecastServerDataService或WeatherForecastDummyDataService的单例IWeatherForecastDataService接口。WeatherForecastDummyDataService用于演示目的,不需要后端SQL数据库。它按其说的创建了应用程序内数据集。
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
// You have a choice of data sources.
// services.AddSingleton();
services.AddSingleton();
// Factory for building the DBContext
var dbContext = configuration.GetValue("Configuration:DBContext");
services.AddDbContextFactory
(options => options.UseSqlServer(dbContext), ServiceLifetime.Singleton);
return services;
}
}
CEC.Blazor.Server项目
这个项目几乎与CEC.Blazor.WASM.Client相同。
Pages我们有一个真实的页面——标准版_Host.cshtml。当我们在服务器上运行时,这是一个asp.net core页面。
- 添加了样式表引用。请注意,您使用虚拟目录_content/Assembly_Name访问依赖程序集wwwroot文件夹中公开的内容。脚本的访问方式相同。
- 在这个例子中,app的基本内容使用TagHelper加载根组件CEC.Weather.Components.App。同样,您不依赖于App,只需指定其他组件类即可。
@page "/"
@namespace CEC.Blazor.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = null;
}
CEC.Blazor.Server
An error has occurred. This application may no longer respond until reloaded.
An unhandled exception has occurred. See browser dev tools for details.
Reload
🗙
Startup.cs
添加了本地服务和CEC.Blazor库服务。
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddCECBlazor();
services.AddApplicationServices();
}
ServiceCollectionExtensions.cs
特定于站点的服务是一个单例IWeatherForecastDataService接口,它加载WeatherForecastServerDataService或WeatherForecastDummyDataService,WeatherForecastControllerService为编辑器提供范围和瞬时Fluent Validator服务。
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
//services.AddSingleton();
services.AddSingleton();
services.AddScoped();
services.AddTransient();
return services;
}
总结
到此结束。这只是一个概述,后面还会有更多详细信息。希望它可以演示您可以使用Blazor项目实现的抽象级别。下一节将介绍服务和实现数据层。
需要注意的一些关键点:
- 在Blazor Server和Blazor WASM项目中,几乎所有代码都是通用的。您可以小心地编写可以以任何一种方式部署的应用程序。
- 对术语要非常小心。我们的应用程序中没有“页面”。