【问题标题】:ASP.NET MVC: Ignore field(s) when editingASP.NET MVC:编辑时忽略字段
【发布时间】:2013-03-14 05:53:01
【问题描述】:

在学习 ASP.NET MVC 的过程中,我遇到了一个问题并遇到了一些麻烦

我正在尝试创建一个简单的博客,只是为了测试我目前所学的内容。但是在编辑和离开字段时,我遇到了问题。

我正在尝试在我的博客上编辑已提交的帖子,该帖子包含几个字段:ID、标题、消息、作者和提交的日期,不应编辑,保持原样。

这里有一些代码:

我的帖子模型:

namespace MyBlock.Models
{
    public class Post
    {
        public int Id { get; set; }

        [Required]
        public string Author { get; set; }

        [Required]
        public string Headline { get; set; }

        [Required]
        public string Message { get; set; }

        public DateTime Date { get; set; }
    }
}

我的编辑:

[HttpGet]
public ActionResult Edit(int id = 0)
{
    Post post = db.Posts.Find(id);

    if (post != null) {
        return View(post);          
    }

    return HttpNotFound();
}

[HttpPost]
public ActionResult Edit(Post post)
{
    if (ModelState.IsValid) {
        db.Entry(post).State = EntityState.Modified;
        db.SaveChanges();

        return RedirectToAction("Index", "Home");
    }

    return View(post);
}

我的编辑观点:

@model MyBlock.Models.Post

@{
    ViewBag.Title = "Edit";
}

<h2>Rediger "@Model.Headline"</h2>

@using (Html.BeginForm()) {
    @Html.LabelFor(u => u.Author)
    @Html.TextBoxFor(u => u.Author)

    @Html.LabelFor(u => u.Headline)
    @Html.TextBoxFor(u => u.Headline)

    @Html.LabelFor(u => u.Message)
    @Html.TextAreaFor(u => u.Message)

    <input type="submit" value="Gem" />
}

我知道我可以输入@HiddenFor(u =&gt; u.Date),然后提交相同的日期。但我敢打赌,除了将其作为源代码中的隐藏字段之外,还有另一种方法吗?我的意思是在另一个例子中这不是那么安全吗?所以我想要这里的隐藏字段以外的东西。你们能帮帮我吗?

如果我尝试按原样运行它。我收到一个错误,即我的日期未设置,这是合乎逻辑的,因为它也想更新该日期。但我不希望它。如果你能这么说,我想把它留作可选。

【问题讨论】:

    标签: c# asp.net .net asp.net-mvc asp.net-mvc-3


    【解决方案1】:

    不要从陌生人那里拿糖果

    换句话说,不要从客户端获取信息并直接更新数据库。您应该在服务器端强制执行您的业务规则,而不是相信客户端会为您执行此操作。

    [HttpPost]
    public ActionResult Edit(Post post)
    {
        if (ModelState.IsValid) {
            var dbPost = db.Posts.FirstOrDefault(p => p.Id == post.Id);
            if (dbPost == null)
            {
                return HttpNotFound();
            }
    
            dbPost.Author = post.Author;
            dbPost.Message = post.Message;
            dbPost.Headline = post.Headline;
            db.SaveChanges();
    
            return RedirectToAction("Index", "Home");
        }
    
        return View(post);
    }
    
    [HttpPost]
    public ActionResult Add(Post post)
    {
        if (ModelState.IsValid) {
            var dbPost = db.Create<Post>();
            dbPost.Author = post.Author;
            dbPost.Message = post.Message;
            dbPost.Headline = post.Headline;
            dbPost.Date = DateTime.Now(); // Don't trust client to send current date
            db.SaveChanges();
    
            return RedirectToAction("Index", "Home");
        }
    
        return View(post);
    }
    

    在我自己的项目中,我通过将自定义验证规则添加到 ValidateEntity 方法来在域层强制执行此类规则。

    【讨论】:

    • 提交是一样的吗,我的意思是创建/写入数据到数据库?
    • 这很好用。我对“写入数据库”有疑问,我该怎么做?如何检索用户在视图中写入的内容?如果我不应该拿那个糖果 :) 现在我的 Write ActionResult 中有这个:if (ModelState.IsValid) { post.Date = DateTime.Now; db.Posts.Add(post); db.SaveChanges(); return RedirectToAction("Index", "Home"); }
    • @KasperHyldalPedersen 这一切都为你准备好了。 db.Posts.FirstOrDefault(...) 行查询数据库以查找帖子的当前状态,然后验证帖子是否确实存在。接下来的几行准备更新帖子,从 action 参数中获取用户输入。最后,db.SaveChanges() 将这些更改提交到数据库。
    • @KasperHyldalPedersen - 您不应该在编辑操作中添加帖子。您只需在创建操作中调用 Add。您检索用户所写的内容与 p.s.w.g 显示的内容完全相同。您也不想设置日期。他关于不吃糖果的观点意味着不要接受你不想改变的价值观。验证并排除它们。您必须采用他们为消息和标题输入的值。此外,您可能也不想更新作者,尽管您可能确实希望允许对其进行更改。
    • @SimonTewsi 是的。防伪令牌只是防止 CSRF 攻击。它们有助于确保请求来自有效的浏览器会话;他们不验证请求的内容或确保数据不会损坏或破坏您的数据库。当然,这取决于您的特定应用程序,但总的来说,我发现格言“不要从陌生人那里拿糖果”是一个很好的准则,尤其是在 Web 或 SOA 开发中.
    【解决方案2】:

    DateTime 是值类型,不能为空。因此,它永远不可能是可选的。

    您需要将它设为可为空的类型。即。

    public DateTime? Date {get;set;}
    

    一般来说,ViewModel 中的大多数值类型都应该可以为空,然后您使用必需属性来强制它们包含一个值。这使您可以判断他们是否未能输入值,或者它是否是默认值。

    然后,您可以在控制器中检查日期是否具有 Date.HasValue 的值,如果有,则保存日期。

    关于安全性,在这种情况下,这不是问题。假设某人可以访问该页面(他们通过了授权)并且他们有权更新日期,那么用户是否可以绕过它并不重要。他们所能做的就是提交有效的日期格式。除非您想添加逻辑以确保日期在特定时间段内,否则您不必担心。 ModelBinder 不会绑定到无效的日期格式。

    如果你想控制用户是否可以更新日期,比如基于角色,那么你可以在控制器中添加逻辑来检查日期是否有值并且用户是否处于正确的角色,否则会发出错误.

    更新:

    我认为这里最简单的解决方案是做两件事。第一个是使 Date 可以为空,正如我上面提到的。尽管如果您的视图中没有 Date 的表单域,这并不是绝对必要的,但如果您稍后添加表单域,那么如果您将文本框留空,则会收到验证错误。如果可能的话,我喜欢防止将来发生错误。此外,如果有人手动将值发布到您的编辑操作,并且它们包含一个空白日期字段,它将无法验证,而不是简单地忽略它。使值可以为空允许该值被完全忽略而不管它的值。

    其次,按照@p.s.w.g 的建议进行操作,只更新您想要更新的字段。从数据库中检索帖子,然后更新除 Id 和 Date 之外的所有字段。然后拨打SaveChanges()

    【讨论】:

    • @p.s.w.g - 嗯?他的问题是他希望日期是可选的,这与问题有关。
    • @MystereMan 是的,我想这可以解决错误,但是按照我阅读问题的方式,OP 不希望在用户编辑 @ 时在数据库中更新 Date 字段987654325@。使用您的方法,如果表单中未提供Date 字段,则会将其更新为null
    • 如果我不够清楚,我很抱歉。但我希望我的 Date 字段是可选的,无论它是否可以更新/编辑。因为它现在在我的代码中,我不想更新该字段,因为我希望它保持自我的帖子以来的状态博客已创建
    • @KasperHyldalPedersen - 你一直在自相矛盾。你说你希望它是可选的,然后你说你不希望它被更新。这是两个相互矛盾的陈述。
    • @MystereMan 很抱歉,但我仍然不喜欢这个解决方案,因为您仍然必须相信客户会在您不想要的时候发送日期更新日期。
    【解决方案3】:

    这里只有我的 2 美分。我知道这是一个简单的情况,给出的答案很好而且直截了当。但是随着属性列表的增加,它可能会变得很困难。

    因此,按照这些思路采用不同的方法

        var t = _db.Blog.Where(x => x.ID == id).FirstOrDefault();
    
        var info = typeof(Blog).GetProperties();
    //properties you don't want to update
        var properties = info.Where(x => x.Name != "xxx" && x.Name != "xxxx").ToList();
      foreach(var p in properties)
       {
          p.SetValue(t, p.GetValue(temp.Volunteer));
       }
    
    
       _db.Entry(t).State = EntityState.Modified;
       _db.SaveChanges();
    

    但是,如果您只是在做一些领域,那么上述内容是有道理的。 用你的脑袋!

    【讨论】:

      猜你喜欢
      • 2012-01-06
      • 1970-01-01
      • 2017-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多