如何不使用JSON数据绑定属性

时间:2018-04-01 14:42:32

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

这是我的模特:

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只应由服务器修改,换句话说,如果用户提供{{} 1}}服务器应返回true或不考虑此值。

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

[2018年4月1日]: 我发现nice article使用了false,遗憾的是它不能用于[BindNever]指向here的数据。所以目前我只是自己在POST处理程序中将属性设置为[FromBody],但它非常难看,因此我仍然在寻找其他方法来做到这一点!

[2018年4月2日]: 终于找到了 ! Check this out !

2 个答案:

答案 0 :(得分: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属性进行交互,客户端甚至不应该知道require 'rails/all' RSpec.describe WikisController, type: :controller do let(:user) { User.create!(email: "user@email.com", password: "password") } let(:wiki) { Wiki.create!(title: "New Wiki Title", body: "New Wiki Body", private: false, user: user) } describe "GET show" do it "returns http success" do get :show expect(response).to have_http_status(:success) end end describe "GET edit" do it "returns http success" do get :edit expect(response).to have_http_status(:success) end end end 属性。

答案 1 :(得分:0)

最终找到了干净的方式!

以下是如何实现它:

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

[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将被绑定和序列化! 这是非常干净的&amp;很好,因为非[DataMember]属性存储在数据库中,它们不是私有的或类似的东西,它们不受序列化的影响,这意味着如果你将模型发送到客户端,例如,他&# 39; ll看不到非[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并且它可以防止您忘记保护&#34;私人&#34;属性。

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

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

来自:prevent property from being serialized in web api