当前位置: 代码网 > it编程>编程语言>Asp.net > ASP.NET Core MVC中Required与BindRequired用法与区别介绍

ASP.NET Core MVC中Required与BindRequired用法与区别介绍

2024年05月18日 Asp.net 我要评论
在开发asp.net core mvc应用程序时,需要对控制器中的模型校验数据有效性,元数据注释(data annotations)是一个完美的解决方案。元数据注释最典型例子是确保api的调用者提供了

在开发asp.net core mvc应用程序时,需要对控制器中的模型校验数据有效性,元数据注释(data annotations)是一个完美的解决方案。

元数据注释最典型例子是确保api的调用者提供了某个属性的值,在传统的asp.net mvc中使用的是requiredattribute特性类。该属性仍然可以在asp.net core mvc中使用,但也提供了一个新的特性类bindrequiredattribute

今天让我们来看看它们之间的细微差别。

requiredattribute的典型用法

想象一下,您的模型是下面的bookorder类。为了强制authortitle属性的值始终出现在传入的请求中,并且值不能为空,我们使用requiredattribute修饰它们。

    public class bookorder
    {
        [required]
        public string author { get; set; }
     
        [required]
        public string title { get; set; }
    }

这在传统的asp.net mvc中是很常见方法。有了这个,您可以验证modelstate是否存在错误,因为对这些属性的验证失败会反映在这里。示例:

    [route("bookorder")]
    public iactionresult postbook([fromform]bookorder bookorder)
    {
        if (!modelstate.isvalid)
        {
            return badrequest(modelstate);
        }
     
        // 正常逻辑代码
        return content("ok");
    }

如果传入的请求中缺少两个必需的属性(或者属性的值为string.empty),则响应将是一个400状态码,并将模型状态错误序列化到响应中。

使用postman进行测试,请求中只提供了title属性的值,而未提供author属性的值:

常有趣的问题,例如当我们添加类似数量的属性时(类型为int)。在这种情况下,requiredattribute将无法正常工作,因为默认值为0,并且该属性不可能为空。即使客户端在不包括属性值的情况下提交请求,模型实例的值都将为0。换句话说,requiredattribute不起作用。在我们的例子中,我们使用的是int,但是同样适用于所有值的类型,例如datetimeguid

以前,在传统的asp.net mvc中,解决这个问题的方法是使用一个可为空类型,如下所示:

    public class bookorder
    {
        [required]
        public string author { get; set; }
     
        [required]
        public string title { get; set; }
     
        [required]
        public int? quantity { get; set; }
    }

虽然它解决了这个问题,但是这不是最优雅的方式。quantity属性不能为null,如果api的调用者未提供该属性的值,则该值保持为null,配合requiredattribute特性可以达到我们的目的。

这种方法的缺点是,在正常逻辑代码中,您需要直接访问可为空的value属性。

    [route("bookorder")]
    public iactionresult postbook([fromform]bookorder bookorder)
    {
        if (!modelstate.isvalid)
        {
            return badrequest(modelstate);
        }
     
        // 正常逻辑代码
        var requestedquantity = bookorder.quantity.value;
        
        return content("ok");
    }

如果通过静态分析工具来检查代码,因为它们找不不到空值检测,所以会警告您可能出现空引用异常(即使在逻辑上,modelstate检测是足够的)。所以这并不是令人赏心悦目的方案。

如果在vs中安装了resharper工具,会显示如下警告:

这就是bindrequiredattribute产生的原因。它和requiredattribute的工作方式类似,它要求请求必须提示属性的值 。

我们将模型改为如下结构,quantity属性为int类型,并使用[bindrequired]修饰:

    public class bookorder
    {
        [required]
        public string author { get; set; }
     
        [required]
        public string title { get; set; }
     
        [bindrequired]
        public int quantity { get; set; }
    }

使用postman进行测试,在请求体不包括quantity属性的值:

测试结果为modelstate.isvalid返回的false,要求提供quantity属性的值。

requiredattribute与bindrequiredattribute的差别

bindrequiredattribute特性类只要求api的调用者提供该属性的值,但不进行空值检测,允许提供的值为空,例如我们将模型改为如下示例,所有属性中都使用了bindrequiredattribute特性类进行注释:

    public class bookorder
    {
        [bindrequired]
        public string author { get; set; }
     
        [bindrequired]
        public string title { get; set; }
     
        [bindrequired]
        public int quantity { get; set; }
    }

使用postman进行测试,在请求体包括这三个属性名称的参数,但是属性的值均为空或默认值:

测试结果为正常,bindrequiredattribute特性类只要求api的调用者提供该属性的值,但不进行空值检测,允许提供的值为空

requiredattribute 与 bindrequiredattribute 混用问题

当然,在代码中混合使用[required][bindrequired]并不是一个最令人满意的效果。值得庆幸的是,asp.net core mvc为您提供了足够的灵活性来改变requiredattribute的行为,强制它包含bindrequiredattribute的行为。

您可以通过实现自己的ibindingmetadataprovider并在您的应用程序全局范围内注册来实现这一目标。

    public class requiredbindingmetadataprovider : ibindingmetadataprovider
    {
        public void createbindingmetadata(bindingmetadataprovidercontext context)
        {
            if (context.propertyattributes?.oftype<requiredattribute>().any() ?? false) {
                context.bindingmetadata.isbindingrequired = true;
            }
        }
    }

在全局范围内注册它:

    public void configureservices(iservicecollection services)
    {
        services.addmvc(o =>
        {
            o.modelmetadatadetailsproviders.add(new requiredbindingmetadataprovider());
        });
    }

相关补充内容

1、asp.net core mvc还提供了bindneverattribute特性类用于指定该属性不进行模型绑定。例如:您拥有一个像isadmin这样的属性,这需要通过服务端来指定,而不是通过客户提交的数据来指定;

2、如果客户端提交的是json格式的数据,bindrequiredattributebindneverattribute特性类就不会起任何作用,这是因为模型直接通过json.net反序列化来创建,mvc框架并不知道属性的值从何而来。

上面补充的两点,感兴趣的同学可以自己进行测试。

总结

  • requiredattribute特性类的行为在传统的asp.net mvc与asp.net core mvc是一致的,校验属性的值不能为null
  • requiredattribute特性类对于值类型的属性,就没有任何效果了,所以在编码的过程将属性的类型改为可为空类型,不过编码的过程就比较纠结了,需要访问可为空类型的value属性,而且静态代码检测工具会警告需要进行非空的校验;
  • bindrequiredattribute特性类可以解决值类型默认值的问题,强制要求客户端提交请求时,必须包含属性的值,不过属性的值可以为空,不进行非空的校验;
  • requiredattributebindrequiredattribute混合使用的情况下,我们也提供了优雅的方法,让requiredattribute包含bindrequiredattribute的行为。

到此这篇关于asp.net core mvc中required与bindrequired用法与区别的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com