ASP.NET Core MVC的Model Binding会将HTTP Request数据,以映射的方式对应到参数中。基本上跟ASP.NET MVC差不多,但能Binding的来源更多了一些。
本篇将介绍ASP.NET Core的Model Binding。

Model Binding

要接收Client 传送来的数据,可以通过Action 的参数接收,如下:

using Microsoft.AspNetCore.Mvc;

namespace MyWebsite.Controllers
{
public class HomeController : Controller
{
public IActionResult Index(int id)
{
return Content($"id: {id}");
}
}
}

id就是从HTTP Request的内容被Binding的Model参数。
预设的Model Binding会从HTTP Request的三个地方取值(优先顺序由上到下):

  • Form
    透过HTTP POST的form取值。如下图:

  • Route
    是通过MVC Route URL取值。
    如:http://localhost:5000/Home/Index/2id取出的值就会是2。
  • Query
    是通过URL Query参数取值。
    如:http://localhost:5000/Home/Index?id=1id取出的值就会是1。

如果三者都传入的话,会依照优先顺序取值Form > Route > Query

Binding Attributes

除了预设的三种Binding 来源外,还可以通过Model Binding Attributes 从HTTP Request 的其他数据中Binding。有以下6 种:

  • [FromHeader]
    从HTTP Header取值。
  • [FromForm]
    通过HTTP POST的form取值。
  • [FromRoute]
    是通过MVC Route URL取值。
  • [FromQuery]
    是通过URL Query参数取值。
  • [FromBody]
    从HTTP Body取值,通常用于取JSON, XML。
    ASP.NET Core MVC预设的序列化是使用JSON,如果要传XML格式做Model Binding的话,要在MVC服务加入XmlSerializerFormatters,如下:

    Startup.cs

// ...
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddXmlSerializerFormatters();
}
  • [FromServices]
    这个比较特别,不是从HTTP Request取值,而是从DI容器取值。
    DI预设是使用Constructor Injection,但Controller可能会因为每个Action用到不一样的Service导致很多参数,所以也可以在Action注入Service。

范例程序

// ...
public class HomeController : Controller
{
public IActionResult FirstSample(
[FromHeader]string header,
[FromForm]string form,
[FromRoute]string id,
[FromQuery]string query)
{
return Content($"header: {header}, form: {form}, id: {id}, query: {query}");
} public IActionResult DISample([FromServices] ILogger<HomeController> logger)
{
return Content($"logger is null: {logger == null}.");
} public IActionResult BodySample([FromBody]UserModel model)
{
return Ok(model);
}
} // ...
public class UserModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string Address { get; set; }
}

输出结果

FirstSample输出结果:

DISample输出结果:
http://localhost:5000/Home/DISample

logger is null: False.

BodySample输出结果:

  • JSON
  • XML

Model 验证

Model Binding 也可以顺便帮忙验证字段数据,只要在字段的属性上面带上Validation Attributes,如下:

using System.ComponentModel.DataAnnotations;
// ...
public class UserModel
{
[Required]
public int Id { get; set; } [RegularExpression(@"\w+")]
[StringLength(20, MinimumLength = 4)]
public string Name { get; set; } [EmailAddress]
public string Email { get; set; } [Phone]
public string PhoneNumber { get; set; } [StringLength(200)]
public string Address { get; set; }
}

然后在Action 加上判断:

Controllers\HomeController.cs

using Microsoft.AspNetCore.Mvc;

namespace MyWebsite.Controllers
{
public class HomeController : Controller
{
// ...
public IActionResult BodySample([FromBody]UserModel model)
{
// 由于 Id 是 int 类型,int 默认为 0
// 虽然带上了 [Required],但不是 null 所以算是有值。
if (model.Id < 1)
{
ModelState.AddModelError("Id", "Id not exist");
}
if (ModelState.IsValid)
{
return Ok(model);
}
return BadRequest(ModelState);
}
}
}

输入错误数据的输出结果:

.NET Core提供了很多的Validation Attributes,可以参考官网:System.ComponentModel.DataAnnotations

自定义Validation Attributes

如果.NET Core提供的Validation Attributes不够用还可以自己做。
例如上述范例的数据模型多了生日字段,需要验证年龄:

using System;
using System.ComponentModel.DataAnnotations; namespace MyWebsite.Attributes
{
public class AgeCheckAttribute : ValidationAttribute
{
public int MinimumAge { get; private set; }
public int MaximumAge { get; private set; } public AgeCheckAttribute(int minimumAge, int maximumAge)
{
MinimumAge = minimumAge;
MaximumAge = maximumAge;
} protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var date = Convert.ToDateTime(value); if (date.AddYears(MinimumAge) > DateTime.Today
|| date.AddYears(MaximumAge) < DateTime.Today)
{
return new ValidationResult(GetErrorMessage(validationContext));
} return ValidationResult.Success;
} private string GetErrorMessage(ValidationContext validationContext)
{
// 有帶 ErrorMessage 的话优先使用
// [AgeCheck(18, 120, ErrorMessage="xxx")]
if (!string.IsNullOrEmpty(this.ErrorMessage))
{
return this.ErrorMessage;
} // 自定义错误信息
return $"{validationContext.DisplayName} can't be in future";
}
}
}

参考

Overview of ASP.NET Core MVC
Introduction to model validation in ASP.NET Core MVC
ASP.NET CORE 2.0 MVC MODEL BINDING
ASP.NET CORE 2.0 MVC MODEL VALIDATION

老司机发车啦:https://github.com/SnailDev/SnailDev.NETCore2Learning

ASP.NET Core 2 学习笔记(九)模型绑定的更多相关文章

  1. Asp.Net Core WebApi学习笔记(四)-- Middleware

    Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Mid ...

  2. sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)

    sql server 关于表中只增标识问题   由于我们系统时间用的过长,数据量大,设计是采用自增ID 我们插入数据的时候把ID也写进去,我们可以采用 关闭和开启自增标识 没有关闭的时候 ,提示一下错 ...

  3. ASP.NET Core 2 学习笔记(七)路由

    ASP.NET Core通过路由(Routing)设定,将定义的URL规则找到相对应行为:当使用者Request的URL满足特定规则条件时,则自动对应到相符合的行为处理.从ASP.NET就已经存在的架 ...

  4. ASP.NET Core 2 学习笔记(十三)Swagger

    Swagger也算是行之有年的API文件生成器,只要在API上使用C#的<summary />文件注解标签,就可以产生精美的线上文件,并且对RESTful API有良好的支持.不仅支持生成 ...

  5. ASP.NET Core 2 学习笔记(十二)REST-Like API

    Restful几乎已算是API设计的标准,通过HTTP Method区分新增(Create).查询(Read).修改(Update)和删除(Delete),简称CRUD四种数据存取方式,简约又直接的风 ...

  6. ASP.NET Core 2 学习笔记(十)视图

    ASP.NET Core MVC中的Views是负责网页显示,将数据一并渲染至UI包含HTML.CSS等.并能痛过Razor语法在*.cshtml中写渲染画面的程序逻辑.本篇将介绍ASP.NET Co ...

  7. ASP.NET Core 2 学习笔记(一)开始

    原文:ASP.NET Core 2 学习笔记(一)开始 来势汹汹的.NET Core似乎要取代.NET Framework,ASP.NET也随之发布.NET Core版本.虽然名称沿用ASP.NET, ...

  8. 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(九)-- 单元测试

    本篇将结合这个系列的例子的基础上演示在Asp.Net Core里如何使用XUnit结合Moq进行单元测试,同时对整个项目进行集成测试. 第一部分.XUnit 修改 Project.json 文件内容, ...

  9. ASP.NET Core MVC学习笔记

    最近由于疫情紧张,遂在家办公,在领导的带领下,学习了一下.Net Core MVC. 一,构建web应用 1.选择c#-所有平台-web  找到ASP.NET Core web应用程序 2.项目命名之 ...

随机推荐

  1. vue基础篇---vue组件

    vue模块第一篇,因为公司马上要用到这vue开发.早就想好好看看vue了.只有实际工作中用到才会进步最快.vue其他的简单指令就不多讲了,没啥意思,网上一大堆.看w3c就ok. 组件这个我个人感觉坑蛮 ...

  2. Kafka记录-Kafka简介与单机部署测试

    1.Kafka简介 kafka-分布式发布-订阅消息系统,开发语言-Scala,协议-仿AMQP,不支持事务,支持集群,支持负载均衡,支持zk动态扩容 2.Kafka的架构组件 1.话题(Topic) ...

  3. Linux下SVN使用

    转载:参考文章http://www.linuxidc.com/Linux/2011-09/42347.htm 1. 将文件checkout到本地目录     svn checkout path(pat ...

  4. IP地址分类以及子网划分

    五类IP地址段 根据上表的说明,我们可以知道: 你只要知道 IP 的第一个十进制数,就能够约略了解到该 IP 属于哪一个等级, 以及同网域 IP 数量有多少. 这也是为啥我们上头选了 192.168. ...

  5. Phalcon的Mvc结构及启动流程(部分源码分析)

    Phalcon本身有支持创建多种形式的Web应用项目以应对不同场景,包括迷你应用.单模块标准应用.以及较复杂的多模块应用 创建项目 Phalcon环境配置安装后,可以通过命令行生成一个标准的Phalc ...

  6. 支付宝app支付流程

  7. Bleve代码阅读(一)——新建索引

    引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...

  8. Java基础编程题——分别统计出其中汉字、英文字母、空格、数字和其它字符的个数

    package com.yangzl.basic; import java.util.Scanner; /** * 分别统计出其中汉字.英文字母.空格.数字和其它字符的个数 * @author Adm ...

  9. 青云VPC网络配置

    1 创建VPC网络 2 申请公网IP 3 回到VPC图形界面绑定公网ip 4 创建私有网络,并绑定私有网络 5 创建3台主机 6 新建防火墙,并绑定到VPC 7 配置VPC端口转发规则 8 添加防火墙 ...

  10. B - Finding Palindromes (字典树+manacher)

    题目链接:https://cn.vjudge.net/contest/283743#problem/B 题目大意:给你n个字符串,然后问你将这位n个字符串任意两两组合,然后问你这所有的n*n种情况中, ...