【问题标题】:How to not bind property with JSON data如何不将属性与 JSON 数据绑定
【发布时间】:2018-09-10 22:58:22
【问题描述】:

这是我的模型:

public sealed class UserModel
{
    [Key]
    [Required]
    [StringLength(20, MinimumLength = 4)]
    public string Username { get; set; }

    [Required]
    [EmailAddress]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [StringLength(20, MinimumLength = 4)]
    public string Password { get; set; }

    public bool IsValid { get; set; }
}

UsernameEmailPassword由用户提供,但是IsValid只能由服务器修改,换句话说,如果用户提供true,服务器应该返回BAD REQUEST或者不考虑这个值。

所以,我可以在创建模型时将属性设置为false,但它并不干净。 有没有办法将属性设为私有或“仅限服务器”?

[2018-04-01]: 我找到了一个nice article,其中使用了[BindNever],遗憾的是,它不适用于[FromBody] 所指出的here 的数据。所以目前我只是自己在 POST 处理程序中将属性设置为false,但它非常难看,因此我仍在寻找其他方法!

[2018-04-02]: 终于找到了 ! Check this out !

【问题讨论】:

  • public改成private?
  • @MikeMcCaughan 我试过了,但似乎私有字段没有在数据库中注册.. :/

标签: c# asp.net json asp.net-web-api


【解决方案1】:

创建用户将在视图中直接与之交互的视图模型。尽量不要直接在视图中使用模型,因为这基本上是一种泄漏设计。

public class UserViewModel {
    [Required]
    [StringLength(20, MinimumLength = 4)]
    public string Username { get; set; }

    [Required]
    [EmailAddress]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [StringLength(20, MinimumLength = 4)]
    public string Password { get; set; }
}

在服务器端,当持久化数据时,属性将被复制到模型中。任何需要设置的附加属性都可以在服务器上安全地完成,因为模型不会泄露给客户端。

例如

public ActionResult Post([FromBody] UserViewModel viewModel) {
    if(ModelState.IsValid) {
        //create new model
        var model = new UserModel {
            Username = viewModel.Username,
            Email = viewModel.Email,
            Password = viewModel.Password
        };

        //or model retrieved from data storage

        //...some other code...

        model.IsValid = true; //only the server can modify this value

        //...
    }

    //...
}

如果客户端不应该与 IsValid 属性进行交互,它甚至不应该知道它。

【讨论】:

  • 你确定这是一个泄漏的设计吗?我太失望了!好干净好漂亮,这是微软推荐的方式吗?
  • @AlexandreDaubricourt 考虑一下。客户端是否有理由操纵该属性?如果答案是否定的,那么为什么将其发送给客户。交流应该只需要知道
  • 当然,客户端一定不能操纵IsValid,这就是为什么有/应该有办法防止某些属性的绑定。我的意思是在某些情况下这是使用[NeverBind] 完成的,所以我认为这是一个很好的模式。
【解决方案2】:

终于找到了干净的方法! ?

实现方法如下:

请求处理程序(在您的控制器中):

[HttpPost]
public async Task<IActionResult> PostUserModel([FromBody] UserModel userModel)
{
    if (!ModelState.IsValid) return BadRequest(ModelState);

    _context.Users.Add(userModel);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetUserModel), new {id = userModel.Username}, userModel);
}

还有模型(在我们的例子中是 UserModel):

[DataContract]
public sealed class UserModel
{
    [Key]
    [DataMember(IsRequired = true)]
    [StringLength(20, MinimumLength = 4)]
    public string Username { get; set; }

    [EmailAddress]
    [DataMember(IsRequired = true)]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    [DataType(DataType.Password)]
    [DataMember(IsRequired = true)]
    [StringLength(20, MinimumLength = 4)]
    public string Password { get; set; }

    public bool IsValid { get; set; }
}

我们将模型定义为数据合约,因此,只有[DataMember]s 将被绑定和序列化! 它非常干净漂亮,因为非 [DataMember] 属性存储在数据库中,它们不是私有的或类似的东西,它们只是不受序列化的影响,这意味着如果您将模型发送到客户端例如,他不会看到非[DataMember] 字段。

你也可以这样做:

public sealed class UserModel
{
    [Key]
    [Required]
    [StringLength(20, MinimumLength = 4)]
    public string Username { get; set; }

    [EmailAddress]
    [Required]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    [DataType(DataType.Password)]
    [Required]
    [StringLength(20, MinimumLength = 4)]
    public string Password { get; set; }

    [JsonIgnore]
    public bool IsValid { get; set; }
}

当然,它仍然比在自己创建时将属性设置为false 更好,但我发现第一种方法更好,因为您不需要Json.Net,它可以防止您忘记保护“私人”特性。

无论如何希望这会对你们有所帮助!

如果您从 JSON 以外的其他来源创建模型,您可能还需要添加 [NeverBind] 属性 [FromBody]

发件人:prevent property from being serialized in web api

【讨论】:

    猜你喜欢
    • 2017-02-08
    • 1970-01-01
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 2012-11-12
    • 1970-01-01
    相关资源
    最近更新 更多