ASP.NET Web API 中的模型验证

ASP.NET Web API 中的模型验证  
ASP.NET Web API 中的参数绑定  FromUri,FromBody
ASP.NET Core 中的模型绑定 
ASP.NET Core ApiController 属性  
ASP.NET Core 自动 HTTP 400 响应  
ASP.NET Core 禁用自动 400 响应  
ASP.NET Core MVC 和 Razor Pages 中的模型验证  
将验证添加到 ASP.NET Core MVC 应用
添加验证 
文档目录  
.NET 文档  
ASP.NET 文档  

介绍如何对模型进行批注、 使用批注以进行数据验证和处理你的 web API 中的验证错误。 当客户端将数据发送到 web API 时,通常要执行任何处理之前验证数据。

在你的控制器操作,可以检查模型是否有效

using MyApi.Models;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace MyApi.Controllers
{
    public class ProductsController : ApiController
    {
        public HttpResponseMessage Post(Product product)
        {
            if (ModelState.IsValid)
            {
                // Do something with the product (not shown).
                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            else
            {
                // 模型验证失败,提示错误信息
                string message = string.Empty;
                foreach (var item in ModelState.Values)
                {
                    foreach (var error in item.Errors)
                        message += error.ErrorMessage + "|";
                }
                return Json(new { code = 0, message = message, data = 0 });

                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }
    }
}

处理验证错误
创建一个操作筛选器来调用控制器操作之前检查模型状态。 下面的代码演示一个示例

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.ModelBinding;

namespace MyApi.Filters
{
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (actionContext.ModelState.IsValid == false)
            {
                /// 推荐
                string message = string.Empty;
                foreach (var item in actionContext.ModelState.Values)
                {
                    foreach (var error in item.Errors)
                        message += error.ErrorMessage + "|";
                }

                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Accepted)
                {
                    Content = new StringContent(JsonConvert.SerializeObject(new
                    {
                        code = HttpStatusCode.BadRequest,
                        message = message,
                    }),
                    System.Text.Encoding.GetEncoding("UTF-8"), "application/json")
                };

                /// 返回BadRequest
                actionContext.Response = actionContext.Request.CreateErrorResponse(
                    HttpStatusCode.BadRequest, actionContext.ModelState);

            }
        }
    }
}

筛选器应用于所有的 Web API 控制器,将添加到筛选器的实例HttpConfiguration.Filters在配置期间的集合,\App_Start\WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new ValidateModelAttribute());
        // ...
    }
}

设置筛选器作为特性上各个控制器或控制器操作

public class ProductsController : ApiController
{
    [ValidateModel]
    public HttpResponseMessage Post(Product product)
    {
        // ...
    }
}

*、模型

public class SignInRequest : RequestBase
{
    /// <summary>
    /// 用户名
    /// </summary>
    [Required(ErrorMessage = "用户名不允许为空")]
    [StringLength(20, MinimumLength = 1, ErrorMessage = "用户名为{2}-{1}位字符")]
    [RegularExpression(@"^[A-Za-z]+$", ErrorMessage = "登录名必须是字母!")]
    public string UserName { get; set; }

    /// <summary>
    /// 密码
    /// </summary>
    [Required(ErrorMessage = "密码不允许为空")]
    [StringLength(20, MinimumLength = 6, ErrorMessage = "密码为{2}-{1}位字符")]
    [RegularExpression(@"(?!^(\d+|[a-zA-Z]+|[~!@#$%^&*?]+)$)^[\w~!@#$%^&*?]{8,16}$", ErrorMessage = "字母、数字、标点符号至少包含2种,8-16个字符!")]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    /// <summary>
    /// 确认登录密码
    /// </summary>
    [Compare("Password", ErrorMessage = "两次密码输入不一致")]
    public string ConfirmPassword { get; set; }

    /// <summary>
    /// 网址
    /// </summary>
    [Required(ErrorMessage = "网址尚未填写,请先完善")]
    [StringLength(160, ErrorMessage = "网址太长了,最大为{1}位字符")]
    [Url(ErrorMessage = "网址格式错误")]
    public string Url { get; set; }

    /// <summary>
    /// 邮箱
    /// </summary>
    [Required(ErrorMessage = "邮箱尚未填写,请先完善")]
    [StringLength(160, ErrorMessage = "邮箱太长了,最大为{1}位字符")]
    [MinLength(160, ErrorMessage = "最小长度{1}位字符")]
    [MaxLength(160, ErrorMessage = "最大长度{1}位字符")]
    [EmailAddress(ErrorMessage = "邮箱格式错误")]
    public string Email { get; set; }

    [Required(ErrorMessage = "手机号不允许为空")]
    [Phone(ErrorMessage = "手机号格式不正确")]
    [RegularExpression(@"^0?(13[0-9]|15[012356789]|18[0123456789]|14[57]|17[1235678]|170|14[57]|166|19[189])[0-9]{8}$", ErrorMessage = "格式不正确")]
    public string Phone { get; set; }

    [Required(ErrorMessage = "身份证号不允许为空")]
    [RegularExpression(@"^(11|12|13|14|15|21|22|23|31|32|33|34|35|36|37|41|42|43|44|45|46|50|51|52|53|54|61|62|63|64|65|71|81|82|91)(\d{13}|\d{15}[\dxX])$", ErrorMessage = "身份证号格式不正确")]
    public string IDCard { get; set; }

    /// <summary>
    /// 日期验证
    /// 只能验证 yyyy-MM-dd 格式日期,不能携带 HH:mm:ss 格式 
    /// </summary>
    [Required(ErrorMessage = "日期不允许为空")]
    [RegularExpression(@"^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-9]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$", ErrorMessage = "日期格式不正确")]
    public string Date { get; set; }

    /// <summary>
    /// 时间验证
    /// 支持验证 yyyy-MM-dd 或 yyyy-MM-dd HH:mm 或 yyyy-MM-dd HH:mm:ss 格式
    /// </summary>
    [RegularExpression(@"^(19|20)\d\d[-/.]((0[1-9])|([1-9])|(1[0-2]))[-/.](([0-2][1-9])|([1-2]0)|(3[0-1])|([1-9])) (([0-1]\d)|([1-9])|(2[0-3]|(0))):(([0-5]\d)|([1-9])):(([0-5]\d)|([1-9]))$")]
    public DateTime Time { get; set; }

    /// <summary>
    /// 时间验证
    /// 支持验证 HH:mm:ss 或者 HH:mm 格式
    /// </summary>
    [RegularExpression(@"^(([0-1]\d)|([1-9])|(2[0-3]|(0))):(([0-5]\d)|([1-9])):(([0-5]\d)|([1-9]))$", ErrorMessage = "日期格式不正确")]
    public TimeSpan? time { get; set; }

    /// <summary>
    /// 年份:1900 - 2099
    /// </summary>
    [Required(ErrorMessage = "年份不允许为空")]
    [RegularExpression(@"^(19|20)\d{2}$", ErrorMessage = "年份格式不正确")]
    public string year { get; set; }

    /// <summary>
    /// 年份:1900 - 9999
    /// </summary>
    [Required(ErrorMessage = "年份不允许为空")]
    [RegularExpression(@"^(19|[2-9][0-9])\d{2}$", ErrorMessage = "年份格式不正确")]
    public string year { get; set; }

    /// <summary>
    /// 月份:个位数月份前 可以加0 或者 不加0
    /// </summary>
    [RegularExpression(@"^0?[1-9]$|^1[0-2]$", ErrorMessage = "月份格式不正确")]
    public string? month { get; set; }

    /// <summary>
    /// 性别
    /// </summary>
    [Required(ErrorMessage = "性别尚未填写,请先完善")]
    [RegularExpression(@"[/^男$|^女&/]", ErrorMessage = "性别错误")]
    [RegularExpression(@"^['男'|'女']$", ErrorMessage = "性别错误")]
    [RegularExpression(@"(男|女|未知)", ErrorMessage = "性别错误")]
    [RegularExpression(@"\b(男|女|未知)\b", ErrorMessage = "性别错误")]
    public string Sex{ get; set; }

    /// <summary>
    /// 年龄
    /// </summary>
    [Required(ErrorMessage = "年龄尚未填写,请先完善")]
    [Range(18, 60, ErrorMessage = "年龄范围在{1}至{2}之间")]
    public string Age { get; set; }

    [Range(1, 99999, ErrorMessage = "排序范围在{1}至{2}之间")]
    public int Sort { get; set; }

    [Range(typeof(decimal), "0.00", "49.99")]
    public decimal Total { get; set; }

    [Range(typeof(double), "0.00", "49.99")]
    public double Amount { get; set; }
}

*、内置验证特性  
[CreditCard]:验证属性是否有信用卡格式。
[Compare]:验证模型中的两个属性是否匹配。
[EmailAddress]:验证属性是否有电子邮件格式。
[Phone]:验证属性是否有电话号码格式。
[Range]:验证属性值是否在指定范围内。
[RegularExpression]:验证属性值是否与指定的正则表达式匹配。
[Required]:验证字段是否非 NULL。 请参阅 [必需] 特性,获取关于该特性的行为的详细信息。
[StringLength]:验证字符串属性值是否未超过指定长度限制。
[Url]:验证属性是否有 URL 格式。
[Remote]:通过调用服务器上的操作方法,验证客户端上的输入。 请参阅 [远程] 特性获取关于该特性的行为的详细信息。
在 System.ComponentModel.DataAnnotations 命名空间中可找到验证特性的完整列表

--------------------------------------------- 15位身份证号 ---------------------------------------------
15位身份证号:第7、8位为出生年份(两位数),第9、10位为出生月份,第11、12位为出生日期,第15位为性别,奇数为男,偶数为女。
【位数】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 1 0 1 0 1 2 0 0 1   0   1   0   1   1
【15位身份证号】
110101200101011
【18位身份证截取出生日期】
string identityCard = "110106201901026789";
string year = identityCard.Substring(6, 4);
string month = identityCard.Substring(10, 2);
string date = identityCard.Substring(12, 2);

--------------------------------------------- ASP.Net Core ---------------------------------------------
Startup.cs、

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.Filters.Add<ValidateModelAttribute>();
        options.MaxModelValidationErrors = 50;
    })
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            var result = new BadRequestObjectResult(context.ModelState);
            result.ContentTypes.Add(MediaTypeNames.Application.Json);
            result.ContentTypes.Add(MediaTypeNames.Application.Xml);
            return result;
        };
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404";
    })
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
        options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
    });
}

ValidateModelAttribute.cs、

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Linq;
using System.Text;

namespace Asset.WebAPI
{
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                #region 返回 Json 字符串
                var result = context.ModelState.Keys.SelectMany(key => context.ModelState[key].Errors
                    .Select(x => new ValidationError(key, x.ErrorMessage))).ToList();
                context.Result = new ObjectResult(new { code = (int)EnumCode.Fail, message = result });
                #endregion

                #region 返回 Json 字符串
                var resultNew = context.ModelState.Where(x => x.Value.Errors.Count > 0)
                    .Select(x => new
                    {
                        Name = x.Key,
                        Message = x.Value.Errors?.FirstOrDefault().ErrorMessage
                    }).ToList();
                //context.Result = new ObjectResult(new { code = (int)EnumCode.Fail, message = resultNew });
                #endregion

                #region 字符串追加
                var errorNew = context.ModelState.GetValidationSummary();
                //context.Result = new JsonResult(new { code = (int)EnumCode.Fail, message = errorNew });
                #endregion

                #region 字符串追加
                string message = string.Empty;
                foreach (var item in context.ModelState.Values)
                {
                    foreach (var error in item.Errors)
                        message += error.ErrorMessage + "|";
                }
                //context.Result = new JsonResult(new { code = (int)EnumCode.Fail, message = message });
                #endregion

                #region 返回BadRequest
                //context.Result = new BadRequestObjectResult(context.ModelState);
                #endregion
            }
        }
    }

    public class ValidationError
    {
        public string Field { get; set; }
        public string Message { get; set; }

        public ValidationError(string field, string message)
        {
            Field = field;
            Message = message;
        }
    }

    public static class ModelStateExtensions
    {
        /// <summary>
        /// 获取验证消息提示并格式化提示
        /// </summary>
        public static string GetValidationSummary(this ModelStateDictionary modelState, string separator = "\r\n")
        {
            if (modelState.IsValid) return null;

            var error = new StringBuilder();

            foreach (var item in modelState)
            {
                var state = item.Value;
                var message = state.Errors.FirstOrDefault(p => !string.IsNullOrWhiteSpace(p.ErrorMessage))?.ErrorMessage;
                if (string.IsNullOrWhiteSpace(message))
                    message = state.Errors.FirstOrDefault(o => o.Exception != null)?.Exception.Message;

                if (string.IsNullOrWhiteSpace(message)) continue;

                if (error.Length > 0)
                    error.Append(separator);
                error.Append(message);
            }
            return error.ToString();
        }
    }
}

*
*
*

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值