ASP.NET Core MVC 之模型(Model)

简介: ASP.NET Core MVC 之模型(Model)  1.模型绑定  ASP.NET Core MVC 中的模型绑定将数据从HTTP请求映射到操作方法参数。参数既可以是简单类型,也可以是复杂类型。

ASP.NET Core MVC 之模型(Model)
  1.模型绑定

  ASP.NET Core MVC 中的模型绑定将数据从HTTP请求映射到操作方法参数。参数既可以是简单类型,也可以是复杂类型。MVC 通过抽象绑定解决了这个问题。

  2.使用模型绑定

  当 MVC 收到一个HTTP 请求时,它会将其路由到一个控制器指定的操作方法。它基于路由数据来决定运行哪个操作,然后将值从HTTP请求绑定到操作方法的参数中,例如

  http://afei.com/movies/edit/2

  movies/edit/2 通过路由模板路由到 Movies 控制器的 Edit 方法,同时接收到一个可选参数 id 。URL 中的字符串是不区分大小写的。

  MVC 将尝试通过名称将请求数据绑定到操作参数上。 MVC 将使用参数名称和其公共可设置的属性名称查找每个参数值。上面的例子,唯一的操作参数被命名为 id ,其中 MVC 绑定到路由值中具有相同名称的值。除了 路由值, MVC 还绑定请求的各个部分的数据,并按照设置的顺序这样做。

  模型绑定查找数据源的顺序列表:

    1. Form values : 通过 HTTP POST 请求发送的表单数据(包括 jQuery POST 请求)。

    2. Route values :由 routing 提供的路由数据集。

    3. Query string : URL 的查询字符串的一部分。

  表单值,路由数据以及查询字符串都是以键值对的形式存储的。

  因为模型绑定要找一个名为 id 的键,但是表单中没有,所以接下来在路由数据中找寻。绑定发生时,该值转换为整数类型的 2 。使用 Edit(string id)的同一请求转换为字符串 “2” .

  如果Action 方法的参数是一个类,比如 Movies 类型,尽管这个类包含简单类型和复杂类型的属性,MVC 也可以模型绑定。它使用反射和递归遍历复杂类型寻找匹配的属性。模型绑定寻找 parameter_name.property_name 的模式去绑定值到属性上。如果没有从表单中找到匹配的值,则尝试只通过 property_name 进行绑定。对于集合类型,模型绑定会去匹配 parameter_name[index] 或只是 [index] 。模型绑定对待字典类型也是一样,前提是Key 是简单类型。Key 支持匹配HTML 和 Tag Helpers 为相同的模型类型生成的字段名。当创建或编辑的绑定数据未通过验证时,回传值使得用户输入的表单字段仍然保留,方便用户输入。

  为了发生绑定,类必须具有公共默认的构造函数,要绑定的成员必须是公共可写的属性,当绑定发生时,类只会使用公共默认的构造函数,然后设置属性。

  当一个参数被绑定后,模型绑定停止寻找具有该名称的值,并继续绑定下一个参数。如果绑定失败,MVC 也不会抛出异常,可以通过ModelState.IsValid 属性来查询模型状态错误。

  在执行绑定时,需要考虑一些特殊的数据类型:

    IFormFile , IEnumerable :作为 HTTP 请求一部分的一个或多个上传的文件。

    CancelationToken : 用于取消一部控制器中的活动。

  这些类型可以绑定到操作参数或类的属性上。

  一旦模型绑定完成,就会进行验证。默认模型绑定适合绝大多数开发场景,同时也可以自定义内置的行为。

  3.通过特性自定义模型绑定行为

  MVC 包含集中可以指定与默认绑定源不同行为的特性。比如,可以通过使用 [BindRequired] 或 [BindNever] 特性指定一个属性是否需要绑定,或者是否该发生。而且可以覆盖默认数据源,指定模型绑定器的数据源。

    [BindRequired] :如果不发生绑定,将添加模型状态错误。

    [BingNever] : 告诉模型绑定从不绑定到此参数。

    [FromHeader] , [FromQuery] , [FromRoute] , [FromForm] : 使用这些来指定应用的确切绑定源。

    [FromServices] : 此特性使用依赖注入来绑定服务的参数。

    [FromBody] : 使用配置的格式化程序绑定请求主体中的数据,基于请求的内容类型选择格式化器。

    [ModelBinder] : 用于覆盖默认模型绑定器,绑定源和名称。

  4.从请求主体绑定格式化的数据

  HTTP 请求数据支持各种的格式,包括 JSON , XML 以及其他格式。当使用 [FromBody] 特性的时候,表示要从请求主体中绑定参数。MVC 使用一组配置的格式化程序来根据其内容类型处理请求数据。默认情况下,MVC 包含一个 JsonInputFormatter 类来处理JSON数据,当然也可以添加其他格式化程序来处理XML 和其他自定义格式。

  每个操作最多可以有一个 [Frombody] 装饰的参数。ASP.NET Core MVC 运行时将读取请求流的职责委托给格式化程序。一旦读取了参数的请求流,通常不可能再次读取请求流以绑定其他 [FromBody] 参数。

  ASP.NET 基于Content-Type 头和参数的类型来选择输入格式化程序。如果想用 XML 或者其他格式,则必须在 Startup.cs 文件中配置它,但首先使用 NuGet 来获取 Microsoft.AspNetCore.Mvc.Formatters.Xml 引用。启动代码如下:

public void ConfigureServices(IServiceCollection services)

    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
            .AddXmlSerializerFormatters();
    }

  示例中,我们添加一个XML 格式化程序作为此MVC应用程序提供的服务。传递给 AddMvc 方法的 options参数允许在应用程序启动时从MVC添加和管理过滤器,格式化程序和其他系统选项,然后应用各种特性到控制器类或方法上实现预期的效果。

 5.模型验证

 在应用程序将数据存储到数据库之前,应用程序必须验证数据。对于数据必须检查其是否存在潜在的安全隐患,验证类型和大小是否正确并且符合所定制的规则。尽管验证的实现可能时冗余且繁琐的,但是必要的。在 MVC 中,验证可以发生在客户端和服务端。

  .NET 已经将验证抽象为验证特性。这些特性包含验证代码,从而减少必须编码。

复制代码
public class Movies

{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }
    [Required]
    [ClassicMovie(1996)]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [Required]
    [StringLength(100)]
    public string Description { get; set; }
    [Required]
    [Range(0,999.99)]
    public decimal Price { get; set; }
    [Required]
    public Genre Genre { get; set; }
    public bool Preorder { get; set; }
}

复制代码
  常见内置验证属性:

    [CreditCard] : 验证属性是否为信用卡格式

    [Compare] : 验证模型中的两个属性是否匹配

    [EmailAddress] : 验证属性是否为电子邮件格式

    [Phone] : 验证属性是否为电话号码格式

    [Range] : 验证属性值是否在给定范围内

    [RegularExpression] : 验证数据是否与指定的正则表达式匹配

    [Required] : 必填的属性

    [StringLength] : 验证字符串属性的最大长度

    [Url] : 验证属性是否为网址格式

  MVC 支持从 ValidationAttribute 派生的任何特性或者更改模型来实现 IAlidatableObject 即创建自定义验证特性以用于验证目的。许多内置的验证特性可以在 ystem.ComponentModel.DataAnnotations 中找到。

  有时候我们需要手动需要验证模型,可以调用 TryValidateModel 方法来验证,如 TryValidateModel (movie)。

  模型状态表示在HTML表单提交值的一系列验证错误。MVC 将持续验证字段直到错误数达到最大值(默认200)。可以在 ConfigureServices 方法中配置这个最大值:

services.AddMvc(options => options.MaxModelValidationErrors = 500);

  模型验证发生在每个控制器的操作 被调用之前,而检查 ModelState.IsValid 和做出适当的反应时操作方法的职责。许多情况下,适当的反应是返回某种错误响应,理想情况下则是详细介绍模型验证失败的原因。

  6.自定义验证

  实现自定义验证的方法很简单,只需要继承 ValidationAttribute,并且重写 IsValid 方法即可。IsValid 方法接受两个参数,第一个是名为 value 的 object 对象,第二个对象是名为validationContext 的 ValidationContext 对象。value 指的是自定义验证器验证的字段的值。

  下面自定义[ClassicMovie] 特性,该特性检查 Movies 类的 ReleaseDate 年份是否大于1960:

  

复制代码
public class ClassicMovieAttribute:ValidationAttribute

{
    private int _year;

    public ClassicMovieAttribute(int Year)
    {
        _year = Year;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        Movies movie = (Movies)validationContext.ObjectInstance;
        if (movie.ReleaseDate.Year > _year)
        {
            return new ValidationResult("发布年份不能大于"+_year);
        }
        return ValidationResult.Success;
    }
}

复制代码
  这个例子只对 Movies 类型有效,因为在 IsValid 方法中硬编码了 Movies 类型。一个更好的选择是 IValidationObject。

  通过在 IValidatableObject 接口上实现 Validate 方法,可以将相同的代码放在模型中。虽然自定义验证属性是用于验证单个属性,但实现 IValidationObject 可用于实现类级别验证;

复制代码
public class Movies: IValidatableObject

{
    private int _classicYear = 1960;
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }
    [Required]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [Required]
    [StringLength(100)]
    public string Description { get; set; }
    [Required]
    [Range(0,999.99)]
    public decimal Price { get; set; }
    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult("发布年份不能大于" + _classicYear,new[] { "ReleaseDate" });
        }
    }
}

复制代码
  

  7.客户端验证

  客户端验证带来了极大便利,它可以节省时间,不必花费一个来回时间等待服务器的验证结果。

  你必须引用 Javascript 脚本来进行客户端验证;

  jquery-x.x.x.min.js jquery.validate.min.js jquery.validate.unobtrusive.min.js

复制代码

复制代码

            <label asp-for="Id" class="control-label"></label>
            <input asp-for="Id" class="form-control" />
            <span asp-validation-for="Id" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="ReleaseDate" class="control-label"></label>
            <input asp-for="ReleaseDate" class="form-control" />
            <span asp-validation-for="ReleaseDate" class="text-danger"></span>
        </div>

复制代码
  上面的 Tag Helper 渲染的 HTML 如下,注意输出的 HTML 中,data-特性对应 Name 属性的验证 Attribute ,data-val-required 特性包含一个用于展示错误消息,如果没填写 ReleaseDate 字段,则错误消息将随着 一起显示:

复制代码

            <label class="control-label" for="Id">Id</label>
            <input name="Id" class="form-control" id="Id" type="number" value="" data-val-required="The Id field is required." data-val="true">
            <span class="text-danger field-validation-valid" data-valmsg-replace="true" data-valmsg-for="Id"></span>
        </div>

            <label class="control-label" for="ReleaseDate">ReleaseDate</label>
            <input name="ReleaseDate" class="form-control" id="ReleaseDate" data-val-required="The ReleaseDate field is required." data-val="true"

type="text" value="">


复制代码

  客户端验证防止表单提交直到有效为止。无论提交表单还是显示错误信息,提交按钮都会执行 Javascript 代码。

  MVC 基于 .NET 属性的数据类型决定了类型特性值。可以使用 [DataType] 特性来覆盖。基础的 [DataType] 特性并不是真正的服务端验证。浏览器选择自己的错误信息,并显示,但 Jquery Validation Unobtrusive 包可以重写消息,并让他们显示方式一致。

  

  8.远程验证

  当需要在客户端上使用服务器上的数据进行验证的时候,远程验证是一个很好的功能。比如,应用程序需要验证一个用户名是否已经被使用,并且需要查询大量数据才能执行。下载大量数据验证会占用大量资源,也可能暴露敏感信息。另一个办法是使用回传请求来验证。

  两个步骤就可以实现远程验证,首先必须使用 [Remote] 特性注释模型属性。 [Remote] 特性接受多个重载,可以使用它将客户端 Javascript 定向到要调用的相应代码。下面的代码时执行 Users 控制器的 VerfyUser 方法:

public class User
{
    [Remote(action: "VerfyUser",controller:"Users")]
    public string Name { get; set; }
}

  然后在 VerfyUser 方法中实现方法,它返回一个 JsonResult :

复制代码

public class UsersController : Controller
{
    public IActionResult VerfyUser(string name)
    {
        if (!_usersRepository.VerfyUser(name))
        {
            return Json(data:$"{name} 已存在");
        }
        return Json(data:true);
    }

}
复制代码
  现在,当用户输入名字时,视图中的 JavaScript 会进行远程调用进行验证。
原文地址https://www.cnblogs.com/afei-24/p/11183228.html

相关文章
|
3月前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
80 5
|
5月前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
128 0
|
3月前
|
开发框架 算法 中间件
ASP.NET Core 中的速率限制中间件
在ASP.NET Core中,速率限制中间件用于控制客户端请求速率,防止服务器过载并提高安全性。通过`AddRateLimiter`注册服务,并配置不同策略如固定窗口、滑动窗口、令牌桶和并发限制。这些策略可在全局、控制器或动作级别应用,支持自定义响应处理。使用中间件`UseRateLimiter`启用限流功能,并可通过属性禁用特定控制器或动作的限流。这有助于有效保护API免受滥用和过载。 欢迎关注我的公众号:Net分享 (239字符)
78 1
|
4月前
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
82 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
3月前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
71 3
|
6月前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
6月前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
151 3
|
5月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
|
6月前
|
开发框架 NoSQL .NET
利用分布式锁在ASP.NET Core中实现防抖
【9月更文挑战第5天】在 ASP.NET Core 中,可通过分布式锁实现防抖功能,仅处理连续相同请求中的首个请求,其余请求返回 204 No Content,直至锁释放。具体步骤包括:安装分布式锁库如 `StackExchange.Redis`;创建分布式锁服务接口及其实现;构建防抖中间件;并在 `Startup.cs` 中注册相关服务和中间件。这一机制有效避免了短时间内重复操作的问题。
151 4
|
7月前
|
开发框架 监控 .NET
开发者的革新利器:ASP.NET Core实战指南,构建未来Web应用的高效之道
【8月更文挑战第28天】本文探讨了如何利用ASP.NET Core构建高效、可扩展的Web应用。ASP.NET Core是一个开源、跨平台的框架,具有依赖注入、配置管理等特性。文章详细介绍了项目结构规划、依赖注入配置、中间件使用及性能优化方法,并讨论了安全性、可扩展性以及容器化的重要性。通过这些技术要点,开发者能够快速构建出符合现代Web应用需求的应用程序。
109 0