Modelstate在ASP.NET MVC 2中的型号上报告为私有属性无效
-
14-09-2020 - |
题
我正在使用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您的暴饮暴食到这些代码更改。您可以将一个简单的字符串添加到单个方法调用中。什么是大交易?我在这里采取务实的方法。
我使用一个视图模型,因为它是最好的工作。不要想到干燥意义,你不能在两个对象上重复属性,将其视为“在两个地方不重复逻辑或持续相同的数据”。在这种情况下,处理模型绑定的语义与您的域模型不匹配,因此您需要一种转换它的方法。