我正在使用ASP.NET MVC 2.0,我正在尝试利用我的控制器中的模型绑定以及ModelState验证。然而,我已经反对一个问题,并希望与人们分享它,以查看您的想法。

好的,我在我的模型类库中有我的清洁用户poco ...

namespace Model
{    
    public partial class User
    {
        public virtual int Id { get; private set; }
        public virtual string UserName { get; private set; }
        public virtual string DisplayName { get; set; }
        public virtual string Email { get; set; }

        public User(string displayName, string userName)
            : this()
        {
            DisplayName = displayName;
            UserName = userName;
        }
    }
}
.

在构建对象之后,我才能允许进行某些要编辑的属性。用户名例如只能在构造对象时设置,对我来说,这使得OO Sense,但是我问题的关键,所以我想在这里突出显示它。

然后我有一个'buddy class',它定义了我的用户类的验证元数据...

namespace Model
{
[MetadataType(typeof(UserMetadata))]
public partial class User
{
    class UserMetadata
    {
        [Required]
        public virtual int Id { get; set; }

        [Required]
        public virtual string UserName { get; set; }

        [Required]
        public virtual string DisplayName { get; set; }

        [RegularExpression(@"^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$", ErrorMessage = "Invalid address")]
        public virtual string Email { get; set; }
    }
}
.

}

然后在我的Web层中我想要允许我的用户能够编辑此对象。所以我在我的个人资料控制器中有以下两个动作方法。

namespace Web.Controllers
{
    public class ProfileController : Controller
    {
        [Authorize]
        public ActionResult Edit()
        {
            var user = _session.Single<User>(x => x.UserName == HttpContext.User.Identity.Name );
            return View(user);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        [Authorize]
        [TransactionFilter]
        public ActionResult Edit(User updatedUser)
        {
            // Get the current user to update.
            var user = _session.Single<User>(x => x.UserName == HttpContext.User.Identity.Name);

            if (ModelState.IsValid)
            {
                TryUpdateModel(user);
                // Update store...                
            }
            return View(updatedUser);
        }
    }
}
.

这具有强烈键入的视图,可以使用它...

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Model.User>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Edit
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <%=Html.Script("jquery.validate.js")%>
    <%=Html.Script("MicrosoftMvcJQueryValidation.js")%>
    <%=Html.Script("MvcFoolproofJQueryValidation.js")%>
    <div class="container">
        <div class="column span-14">
        <% using (Html.BeginForm()) {%>
            <%= Html.AntiForgeryToken() %>
            <fieldset>
                <%: Html.DisplayFor(model => model.UserName) %>
                <%= Html.Label("Display Name") %>
                <%= Html.HiddenFor(model => model.DisplayName)%>
                <%= Html.ValidationMessageFor(model => model.DisplayName)%>
                <%= Html.Label("Email address") %>
                <%= Html.EditorFor(model => model.Email)%>
                <%= Html.ValidationMessageFor(model => model.Email)%>
                <%= Html.HiddenFor(model => model.UserName)%>
                <p>
                    <input type="submit" value="Save" />
                </p>
            </fieldset>
        </div>
        <div class="clear"></div>
        <% } %>
    </div>
</asp:Content>
. 好的,那就是这样所有的代码!!

所以这是问题,在初始获取请求后,视图呈现很好。但是当用户发布表格后,例如编辑其显示名称后,模型助天无效。这是因为Username属性有一个私有Setter。然而,这是通过设计,对于安全性和语义,我不希望他们更改用户名,因此Setter是私有的。但是,由于我已将所需属性添加到属性,因此它失败,因为它未设置!

问题是应该将ModelBinding报告为验证错误吗?!由于属性是私人的,我设计了它不设置,因此通过设计我不希望模型活页夹设置它,但我不希望验证错误。我认为它应该只生成它可以设置的属性的验证错误。

好的,所以我可能已经提出的解决方案。

使房产公开。

如果我这样做,我打开自己,以允许为现有用户更改用户名。我必须在某处添加额外的逻辑来捕捉这个,并不是非常好的。我还必须在动作方法上添加一个绑定,以阻止尝试通过帖子设置它的任何顽皮人员。

删除错误

我相信我可以从Modelstate字典中删除错误,这会在这个场合很好,但我认为这将介绍一些代码的味道,因为我必须为所有有私人定居者的对象添加这个代码。我可能会忘记!!

强烈键入我对接口的视图

我已经阅读了一些人将他们的视图绑定到他们的模型的界面,这是ModelView界面的王在业务模型对象上。我喜欢这个想法,但我松开了自动绑定,需要将我的模型对象与我的Web层中的构造函数复制,不确定吗?!这里有一些信息 http://www.codethinked.com/post/2010/04/12/easy-and-safe-model-binding-in-aspnet-mvc.aspx

使用模型视图

这只是对我来说似乎没有干燥?!如果我没有适合的现有模型对象(例如,我使用注册模型视图),我很乐意使用这些。

custommodelbinder

我的首选选择,但我不确定我知道我在做什么!!如果我可以让活页夹只绑定到它可以设置的属性,那么我会笑!!

人们的想法是什么?评论上述选项,任何其他解决方案,我刚刚与我的架构下的标记?

谢谢:)

有帮助吗?

解决方案 3

jfar发布了Brad Wilson的帖子的一个很好的链接,其中brad评论...

仍然可以进行部分编辑,但是 你不能做部分验证 更多的。所以,如果你排除绑定 [必填]的东西 属性,然后验证将失败。 你有几个选择来解决 这个:

  • 使用视图模型,该模型精确镜像数据数据

  • 预填写[必需],但在呼叫之前使用数据具有未绑定字段 (尝试)updateModel使 验证将成功(即使是 你不打算做任何事情 该数据)

  • 允许发生验证错误,然后从中删除它们 验证后的模型工作站完成后, 由于它们不适当错误。

我的案例似乎适合“部分编辑”案例,在那里我不希望更新某些字段。

我将把这些视为解决方案。

其他提示

我已经为它设计不设置,因此通过设计我不希望模型活页夹设置它,但我不想要验证错误。我认为它应该只产生验证它可以设置的属性错误。

阅读更多关于此设计的关于此设计的更多信息:

http ://bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.html

有趣的是,大多数人抱怨你对抱怨的完全相反。 ;)

您基本上告诉系统应该始终设置无法设置的东西。所以我不会说MVC正在不正确或类似的东西工作。你只是编码一个不可能的场景。


整体而言,您的刚刚达到了Metadatabuddy技术的疼痛点。主要是需要对新的和编辑方案具有不同的验证。

如果我这样做,我打开自己,以允许为现有用户更改用户名。我必须在某处添加额外的逻辑以捕捉此功能,并不是非常好的。我也必须添加一个绑定排除在操作方法上,以阻止任何顽皮的人试图通过帖子设置它。

imho您的暴饮暴食到这些代码更改。您可以将一个简单的字符串添加到单个方法调用中。什么是大交易?我在这里采取务实的方法。

我使用一个视图模型,因为它是最好的工作。不要想到干燥意义,你不能在两个对象上重复属性,将其视为“在两个地方不重复逻辑或持续相同的数据”。在这种情况下,处理模型绑定的语义与您的域模型不匹配,因此您需要一种转换它的方法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top