农副产品销售网站开发,室内设计软件下载,王也踏青图是哪一集,公司网站设计制作公司Blazor 是将 C# 引入浏览器的 Microsoft 试验框架#xff0c;正好可以填补欠缺的 C# 一环。如今#xff0c;C# 程序员可以编写桌面、服务器端 Web、云、电话、平板电脑、手表、电视和 IoT 应用程序。Blazor 填补了欠缺的一环#xff0c;C# 开发人员现在可以直接在用户浏览器… Blazor 是将 C# 引入浏览器的 Microsoft 试验框架正好可以填补欠缺的 C# 一环。如今C# 程序员可以编写桌面、服务器端 Web、云、电话、平板电脑、手表、电视和 IoT 应用程序。Blazor 填补了欠缺的一环C# 开发人员现在可以直接在用户浏览器中共享代码和业务逻辑。对于 C# 开发人员来说这是一项十分强大的功能可显著提升工作效率。本文将展示常见的代码共享用例。我将展示如何在 Blazor 客户端和 WebAPI 服务器应用程序之间共享验证逻辑。目前你不仅要在服务器中验证输入还要在客户端浏览器中验证输入。新式 Web 应用程序的用户希望获得准实时反馈。在填写长窗体并单击“提交”后仅看到红色错误返回的日子已经一去不复返了。在浏览器中运行的 Blazor Web 应用程序可以与 C# 后端服务器共享代码。可以将逻辑放入共享库中并在前端和后端使用它。这会带来很多好处。可以将所有规则都集中放置在一处并知道只需在一处更新它们。它们的工作方式确实相同因为它们是相同的代码。在客户端和服务器逻辑并不总是完全相同的情况下可以节省大量测试和故障排除时间。也许最值得一提的是可以在客户端和服务器上使用一个库进行验证。以前JavaScript 前端强制开发人员编写两个版本的验证规则一个是用适用于前端的 JavaScript 编写另一个是用适用于后端的语言编写。若要尝试解决这种不匹配问题需要涉及复杂的规则框架和额外的抽象层。使用 Blazor可以在客户端和服务器上运行同一.NET Core 库。虽然 Blazor 仍是试验框架但它的进展迅速。生成此示例前请先确保已安装正确版本的 Visual Studio、.NET Core SDK 和 Blazor 语言服务。有关入门步骤请访问 blazor.net。新建 Blazor 应用程序首先新建 Blazor 应用程序。在“新建项目”对话框中依次单击“ASP.NET Core Web 应用程序”和“确定”再选择图 1 所示对话框中的“Blazor”图标。单击“确定”。这会创建默认的 Blazor 示例应用程序。如果已试用过 Blazer便会对此默认应用程序很熟悉。图 1选择 Blazor 应用程序新的注册窗体将展示验证业务规则的共享逻辑。图 2 展示了包含“名字”、“姓氏”、“电子邮件地址”和“电话”字段的简单窗体。在此示例中它会验证所有字段是否都为必填、姓名字段是否有长度上限以及电子邮件地址和电话字段的格式是否正确。它会在每个字段下显示错误消息这些消息会在用户键入内容的同时更新。最后只有在没有错误的情况下“注册”按钮才处于启用状态。图 2注册窗体共享库所有需要在服务器和 Blazor 客户端之间共享的代码都位于一个独立的共享库项目中。共享库包含模型类和非常简单的验证引擎。模型类保留注册窗体中的数据字段。该命令如下所示public class RegistrationData : ModelBase{ [RequiredRule] [MaxLengthRule(50)]public String FirstName { get; set; } [RequiredRule] [MaxLengthRule(50)]public String LastName { get; set; } [EmailRule]public String Email { get; set; } [PhoneRule]public String Phone { get; set; }}RegistrationData 类继承自 ModelBase 类后者包含所有可用于验证规则并返回绑定到 Blazor 页面的错误消息的逻辑。每个字段都使用映射到验证规则的属性进行修饰。我选择了创建非常简单的模型它很像实体框架 (EF) 数据注释模型。此模型的所有逻辑都包含在共享库中。ModelBase 类包含 Blazor 客户端应用程序或服务器应用程序可用来确定是否有任何验证错误的方法。它还会在此模型更改时触发事件以便客户端能够更新 UI。任何模型类都可以继承自它并自动获取所有验证引擎逻辑。首先我将在 SharedLibrary 项目中新建 ModelBase 类如下所示public class ModelBase{}错误和规则现在我将向 ModelBase 类添加包含验证错误列表的专用字典。_errors 字典先以字段名称为键再以规则名称为键。值是要显示的实际错误消息。通过此设置可以轻松确定特定字段是否有验证错误并快速检索错误消息。代码如下private DictionaryString, DictionaryString, String _errors new Dictionarystring, Dictionarystring, string();现在我将添加 AddError 方法以将错误输入内部错误字典。AddError 有 fieldName、ruleName 和 errorText 参数。它先搜索内部错误字典并删除已有条目再添加新的错误条目如下面的代码所示private void AddError(String fieldName, String ruleName, String errorText){if (!_errors.ContainsKey(fieldName)) { _errors.Add(fieldName,new Dictionarystring, string()); }if (_errors[fieldName].ContainsKey(ruleName)) { _errors[fieldName].Remove(ruleName); } _errors[fieldName].Add(ruleName, errorText); OnModelChanged();}最后我将添加 RemoveError 方法它接受 fieldName 和 ruleName 参数并在内部错误字典中搜索并删除匹配的错误。代码如下private void RemoveError(String fieldName, String ruleName){if (!_errors.ContainsKey(fieldName)) { _errors.Add(fieldName,new Dictionarystring, string()); }if (_errors[fieldName].ContainsKey(ruleName)) { _errors[fieldName].Remove(ruleName); OnModelChanged(); }}下一步是添加 CheckRules 函数这些函数负责查找并执行附加到此模型的验证规则。有两种不同的 CheckRules 函数一种是缺少参数但对所有字段验证全部规则另一种有 fieldName 参数并仅验证特定字段。在字段更新时使用的是第二种函数并立即对此字段验证规则。CheckRules 函数使用反射来查找附加到字段的属性列表。然后它测试每个属性以确定属性类型是否为 IModelRule。找到 IModelRule 后它调用 Validate 方法并返回结果如图 3 所示。图 3CheckRules 函数public void CheckRules(String fieldName){var propertyInfo this.GetType().GetProperty(fieldName);var attrInfos propertyInfo.GetCustomAttributes(true);foreach (var attrInfo in attrInfos) {if (attrInfo is IModelRule modelrule) {var value propertyInfo.GetValue(this);var result modelrule.Validate(fieldName, value);if (result.IsValid) { RemoveError(fieldName, attrInfo.GetType().Name); }else { AddError(fieldName, attrInfo.GetType().Name, result.Message); } } }}public bool CheckRules(){foreach (var propInfo in this.GetType().GetProperties( System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) CheckRules(propInfo.Name);return HasErrors();}接下来我将添加 Errors 函数。此函数需要使用 fieldname 参数并返回包含相应字段的错误列表的字符串。它使用内部 _errors 字典来确定相应字段是否有任何错误如下所示public String Errors(String fieldName){if (!_errors.ContainsKey(fieldName)) { _errors.Add(fieldName,new Dictionarystring, string()); } System.Text.StringBuilder sb new System.Text.StringBuilder();foreach (var value in _errors[fieldName].Values) sb.AppendLine(value);return sb.ToString();}现在我需要添加 HasErrors 函数它会在此模型的任意字段有任何错误时返回 true。客户端使用此方法来确定是否应启用“注册”按钮。另外WebAPI 服务器也使用此方法来确定传入的模型数据是否有错误。此函数的代码如下public bool HasErrors(){foreach (var key in _errors.Keys)if (_errors[key].Keys.Count 0) { return true; }return false;}值和事件是时候添加 GetValue 方法了它需要使用 fieldname 参数并使用反射来查找此模型中的字段并返回字段值。Blazor 客户端使用此方法来检索当前值并在输入框中显示它如下所示public String GetValue(String fieldName){var propertyInfo this.GetType().GetProperty(fieldName);var value propertyInfo.GetValue(this);if (value ! null) { return value.ToString(); }return String.Empty;}现在添加 SetValue 方法。它使用反射来查找此模型中的字段并更新字段值。然后它触发 CheckRules 方法以对相应字段验证所有规则。Blazor 客户端使用此方法以在用户在输入文本框中键入内容的同时更新值。代码如下public void SetValue(String fieldName, object value){var propertyInfo this.GetType().GetProperty(fieldName); propertyInfo.SetValue(this, value); CheckRules(fieldName);}最后我添加 ModelChanged 事件。如果此模型中的值已更改或在内部错误字典中添加或删除了验证规则便会触发这个事件。Blazor 客户端侦听此事件并在事件触发时更新 UI。正因为此显示的错误会更新如下面的代码所示public event EventHandlerEventArgs ModelChanged;protected void OnModelChanged(){ ModelChanged?.Invoke(this, new EventArgs());}得承认此验证引擎的设计非常简单还有很多改进机会。在生产业务应用程序中设置错误的严重性级别如“信息”、“警告”和“错误”会很有用。在某些情况下如果无需修改代码即可从配置文件动态加载规则将会很有帮助。我不是在提倡创建你自己的验证引擎只是有很多选择。此验证引擎既要足够好以便演示实际示例又要足够简单以适应本文且易于理解。创建规则此时有包含窗体字段的 RegistrationData 类。此类中的字段使用 RequiredRule 和 EmailRule 等属性进行修饰。RegistrationData 类继承自 ModelBase 类后者包含所有用于验证规则并向客户端通知更改的逻辑。验证引擎的最后一部分是规则逻辑本身。接下来我将对此进行探索。首先我在 SharedLibrary 中新建 IModelRule 类。此规则由一个返回 ValidationResult 的 Validate 方法组成。每个规则都必须实现 IModelRule 接口如下所示public interface IModelRule{ValidationResult Validate(String fieldName, object fieldValue);}接下来我在 SharedLibrary 中新建 ValidationResult 类它由两个字段组成。IsValid 字段指明规则是否有效而 Message 字段则包含要在规则无效时显示的错误消息。代码如下所示public class ValidationResult{public bool IsValid { get; set; }public String Message { get; set; }}示例应用程序使用四个不同的规则所有规则都是继承自 Attribute 类并实现 IModelRule 接口的公共类。现在是时候创建规则了。请注意所有验证规则都只是继承自 Attribute 类并实现 IModelRule 接口的 Validate 方法的类。如果输入的文本超过指定的长度上限图 4 中的长度上限规则返回错误。其他用于验证必填字段、电话和电子邮件地址字段格式的规则的工作方式类似区别在于它们对要验证的数据类型采用不同的逻辑。图 4MaxLengthRule 类public class MaxLengthRule : Attribute, IModelRule{private int _maxLength 0;public MaxLengthRule(int maxLength) { _maxLength maxLength; }public ValidationResult Validate(string fieldName, object fieldValue){ var message $Cannot be longer than {_maxLength} characters;if (fieldValue null) { return new ValidationResult() { IsValid true }; } var stringvalue fieldValue.ToString();if (stringvalue.Length _maxLength ) {return new ValidationResult() { IsValid false, Message message }; }else {return new ValidationResult() { IsValid true }; } }}创建 Blazor 注册窗体至此验证引擎已在共享库中完成它可以应用于 Blazor 应用程序中的新注册窗体。首先我在 Blazor 应用程序中添加对共享库项目的引用。为此可使用“引用管理器”对话框的“解决方案”窗口如图 5 所示。图 5添加对共享库的引用接下来我向应用程序的 NavMenu 添加新导航链接。打开SharedNavMenu.cshtml 文件并向列表添加新注册窗体链接如图 6 所示。图 6添加注册窗体链接div class(collapseNavMenu ? collapse : null) onclickToggleNavMenuul classnav flex-columnli classnav-item px-3NavLink classnav-link href MatchNavLinkMatch.Allspan classoi oi-home aria-hiddentrue/span Home/NavLink/lili classnav-item px-3NavLink classnav-link hrefcounterspan classoi oi-plus aria-hiddentrue/span Counter/NavLink/lili classnav-item px-3NavLink classnav-link hreffetchdataspan classoi oi-list-rich aria-hiddentrue/span Fetch data/NavLink/lili classnav-item px-3NavLink classnav-link hrefregistrationformspan classoi oi-list-rich aria-hiddentrue/span Registration Form/NavLink/li/ul/div最后我在 Pages 文件夹中添加新 RegistrationForm.cshtml 文件。为此可使用图 7 中的代码。图 7 中的 cshtml 代码在 form 标记内有四个 TextInput 字段。TextInput 标记是自定义 Blazor 组件用于处理字段的数据绑定和错误显示逻辑。此组件只需要三个参数即可正常运行Model 字段标识数据要绑定到的类。FieldName标识数据要绑定到的数据成员。DisplayName 字段让组件可以显示易记消息。图 7添加 RegistrationForm.cshtml 文件page /registrationforminject HttpClient Httpusing SharedLibraryh1Registration Form/h1if (!registrationComplete){ form div classform-group TextInput Modelmodel FieldNameFirstName DisplayNameFirst Name / /div div classform-group TextInput Modelmodel FieldNameLastName DisplayNameLast Name / /div div classform-group TextInput Modelmodel FieldNameEmail DisplayNameEmail / /div div classform-group TextInput Modelmodel FieldNamePhone DisplayNamePhone / /div button typebutton classbtn btn-primary onclickRegister disabledmodel.HasErrors()Register/button /form}else{ h2Registration Complete!/h2}functions {bool registrationComplete false; RegistrationData model { get; set; }protected override void OnInit(){base.OnInit(); model new RegistrationData() { FirstName test, LastName test, Email testtest.com, Phone 1234567890 }; model.ModelChanged ModelChanged; model.CheckRules(); }private void ModelChanged(object sender, EventArgs e){base.StateHasChanged(); }async Task Register(){await Http.PostJsonAsyncRegistrationData(https://localhost:44332/api/Registration, model); registrationComplete true; }}在页面的 functions 块内代码只有一点点。OnInit 方法使用其中的一些测试数据来初始化模型类。它绑定到 ModelChanged 事件并调用 CheckRules 方法来验证规则。ModelChanged 处理程序调用 base.StateHasChanged 方法以强制执行 UI 刷新。Register 方法在“注册”按钮获得单击时调用并将注册数据发送到后端WebAPI 服务。TextInput 组件包含输入标签、输入文本框、验证错误消息以及在用户键入内容的同时更新模型的逻辑。Blazor 组件非常易于编写并提供了将接口分解为可重用部分的强大方法。参数成员使用 Parameter 属性进行修饰以便让 Blazor 知道它们是组件参数。输入文本框的 oninput 事件连接到 OnFieldChanged 处理程序。每当输入更改都会触发此事件。然后OnFieldChanged 处理程序调用 SetValue 方法以对相应字段执行规则并在用户键入内容的同时实时更新错误消息。图 8 展示了代码。图 8更新错误消息using SharedLibrarylabelDisplayName/labelinput typetext classform-control placeholderDisplayName oninput(e OnFieldChanged(e.Value))valueModel.GetValue(FieldName) /small classform-text stylecolor:darkred;Model.Errors(FieldName) /smallfunctions { [Parameter] ModelBase Model { get; set; } [Parameter] String FieldName { get; set; } [Parameter] String DisplayName { get; set; }public void OnFieldChanged(object value){ Model.SetValue(FieldName, value); }}服务器上的验证验证引擎现已开始在客户端上运行。下一步是在服务器上使用共享库和验证引擎。为此我先向解决方案添加另一个 ASP.NET Core Web 应用程序项目。这次我在图 1 所示的“新建 ASP.NET Core Web 应用程序”对话框中选择的是“API”而不是“Blazor”。新建 API 项目后我就添加对共享项目的引用就像在 Blazor 客户端应用程序中见图 5一样。接下来我向 API 项目添加新控制器。新控制器接受来自 Blazor 客户端的 RegistrationData 调用如图 9 所示。注册控制器在服务器上运行并且是后端 API 服务器的典型特征。区别在于它现在运行在客户端上运行的相同验证规则。图 9注册控制器[Route(api/Registration)][ApiController]public class RegistrationController : ControllerBase{ [HttpPost]public IActionResult Post([FromBody] RegistrationData value){if (value.HasErrors()) {return BadRequest(); }// TODO: Save data to databasereturn Created(api/registration, value); }}注册控制器有一个 POST 方法它接受 RegistrationData 作为自己的值。它调用 HasErrors 方法以验证所有规则并返回布尔值。若有错误控制器返回 BadRequest 响应否则它返回成功响应。我特意省略掉了将注册数据保存到数据库的代码这样我就可以验证方案为重点了。现在共享验证逻辑在客户端和服务器上运行。远景此简单示例展示了如何在浏览器和后端之间共享验证逻辑仅仅触及全栈 C# 环境强大功能的皮毛。Blazor 的神奇之处在于使用它现有 C# 开发人员大军可以生成功能强大的新式响应式单页应用程序且最大限度地缩短启动时间。使用它企业可以重用和重新打包现有代码以便能够直接在浏览器中运行现有代码。能够在浏览器、桌面、服务器、云和移动平台之间共享 C# 代码将大大提升开发人员的工作效率。它还便于开发人员更快地向客户交付更多功能和更多业务价值。原文地址https://msdn.microsoft.com/zh-cn/magazine/mt833288.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com