【问题标题】:Uneditable ViewModel properties in a edit view编辑视图中不可编辑的 ViewModel 属性
【发布时间】:2010-02-11 04:37:21
【问题描述】:

在我的 ASP.NET MVC2 应用程序中,我有一个名为 UserCreateViewModel 的 ViewModel 类。

在这个类中,有许多属性直接映射到称为 User 的 LINQ-to-SQL 类。我正在使用 AutoMapper 执行此映射,它工作正常。

在 UserController 的 Create 操作中,我收到了部分完整的 UserCreateViewModel,其中包含有关 OpenId 身份验证的信息。

这是 UserCreateViewModel 的定义:

public class UserCreateViewModel
{
    public string OpenIdClaimedIdentifier { get; set; }
    public string OpenIdFriendlyIdentifier { get; set; }
    public string Displayname { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
}

在“创建”视图中,我不希望 OpenIdClaimedIdentifierOpenIdFriendlyIdentifier 可编辑。

我使用了强类型的创建视图(使用内置的自动创建),但这为我提供了用于这两个属性的可编辑文本框。如果我完全删除特定的 html,当创建表单返回时(并直接返回到 UserCreateViewModel):

 [AcceptVerbs(HttpVerbs.Post)]
 public ActionResult Create(UserCreateViewModel viewModel, string ReturnUrl)

返回的 viewModel 不包含 OpenIdClaimedIdentifierOpenIdFriendlyIdentifier 的值。

我已经调查了[HiddenInput] 属性的使用,但我似乎无法完成这项工作。我也尝试过在表单中​​使用隐藏的<input/> 标签,这很有效,但这似乎有点笨拙。

有没有更好的方法来做到这一点?还是使用隐藏的<input> 是唯一的方法?

编辑:澄清逻辑流程:

  1. 用户尝试使用他们的 OpenId 登录。
  2. DotNetOpenAuth 执行身份验证,如果成功,则返回 OpenIdClaimedIdentifierOpenIdFriendlyIdentifier
  3. 我进行数据库检查以查看是否已有具有此 ID 的用户。
  4. 如果还没有用户,则创建一个临时的UserCreateViewModel 并设置两个 OpenId 字段。这存储在TempData
  5. 重定向到 UserController Create 操作并显示带有这个部分完成的 UserCreateViewModel 对象的 Create 视图。
  6. 这就是问题所在然后用户完成其他数据(DisplayName 等)并发布结果UserCreateViewModel

问题在于,在第 5 步和第 6 步之间,如果未绑定 OpenId 参数,它们就会丢失。我不想在创建表单期间向用户显示OpenIdClaimedIdentifierOpenIdFriendlyIdentifier,但如果我删除数据,它们的绑定会在帖子中丢失。

我希望这能稍微澄清一下这个问题

【问题讨论】:

  • 你在创建中,如果没有设置空值是不是很正常?你想要什么,空字符串?
  • 这不是我的意思,我已经重新澄清了这个问题。
  • 您是否有不想使用隐藏字段的原因?它可以帮助我们更好地回答您的问题。在您修改后,我已经更新了我的答案。

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


【解决方案1】:

我不确定这是否是您要查找的内容,但如果您不希望 OpenIdClaimedIdentifier 自动绑定,则可以将其添加到 BindAttribute 的排除列表中

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude="OpenIdClaimedIdentifier")]UserCreateViewModel viewModel, string ReturnUrl) {
}

编辑后更新

有没有更好的方法来做到这一点?

更好是一个相对术语。当然有其他方法可以实现您想要的,但隐藏的 <input> 字段通常用于这种情况,并且正如您所说的那样有效。

<%=Html.Hidden("OpenIdClaimedIdentifier") %

您是否有什么特别的原因不想使用隐藏字段?这将有助于我们更好地回答您的问题。

是因为您担心安全吗?从您描述逻辑流程的方式来看,使用隐藏的&lt;input&gt; 会使您容易受到有人在提交之前更改已验证的OpenIdClaimedIdentifierOpenIdFriendlyIdentifier 隐藏值的攻击。如果这是您关心的问题,那么您可以加密解析回客户端的数据。

替代解决方案是:

  • 将数据存储在服务器 Session 中。

    Session["OpenIdClaimedIdentifier"] = value;

  • 或者将您的流程分成两个阶段(由 2 个数据库提交组成)。 更新 在第 4 步确认 OpenId 身份验证后,您在数据库中创建用户记录,获取创建的唯一记录 ID 并将其存储在身份验证 cookie 中(因为此时用户已通过身份验证) .然后,您重定向到“编辑用户详细信息”。然后,“编辑”页面从身份验证 cookie 中获取用户 ID,而不是从表单中查找用户记录。

如果您在保存数据之前执行了必要的安全检查,那么我认为使用隐藏字段没有任何问题。

【讨论】:

  • 感谢您提供更新的答案。我没有考虑过 2 阶段数据库提交过程。我会继续调查,看看能找到什么。
  • 当编辑计时器:如果这是一种标准的做法,我很乐意使用隐藏字段。我喜欢 2 阶段过程的想法,但这是否意味着我必须在某一时刻将模型的用户 ID 存储在数据库更新的表单上?或者这就是 [Bind] Exclude 起作用的地方?
  • @Alistair 您通常会将用户 ID 存储在身份验证 cookie 中。这样您就知道用户 ID 没有更改。查看我的更新。
  • 这就是我选择处理此事的方式。我对我的代码流做了一些重构,并认为这是最好的方法。我感谢所做的努力和编辑。谢谢。
【解决方案2】:

问题是您在这里有一个两阶段流程,其中一半数据来自 DotNetOpenAuth 调用,另一半来自用户。由于您希望首先发生 DotNetOpenAuth 调用,因此您需要找到某种方法来存储该数据,直到最终保存到数据库调用。

这应该在客户端完成,所以通常的方法是通过隐藏字段来实现这种事情......

<%=Html.Hidden("OpenIdClaimedIdentifier") %>
<%=Html.Hidden("OpenIdFriendlyIdentifier") %>

其他客户端选项是 cookie 或 URL,似乎都不比这里的隐藏字段更合适。

或者,可以重组您的方法,以便您的开放身份验证调用创建用户帐户并将其保存到数据库中,其中包含从 DotNetOpenAuth 调用中检索到的详细信息。然后将用户重定向到编辑帐户页面,然后他们可以更新他们的详细信息。

【讨论】:

    【解决方案3】:

    如果你想使用 HiddenInput 属性,同时在你的类上使用验证属性,你可以这样修改你的 UserCreateViewModel :

    public class UserCreateViewModel
    {
        [HiddenInput(DisplayValue=false)]
        public string OpenIdClaimedIdentifier { get; set; }
        [HiddenInput(DisplayValue=false)]
        public string OpenIdFriendlyIdentifier { get; set; }
        [Required]
        public string Displayname { get; set; }
        [Required]
        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }
        [Required]
        [DataType(DataType.PhoneNumber)]
        public string PhoneNumber { get; set; }
    }
    

    要在视图中显示具有属性的模型,请使用

    <%= Html.EditorForModel() %>
    

    或者对于单个字段:

    <%= Html.EditorFor(m => m.OpenIdClaimedIdentifier)%>
    

    这样您的模型将自动验证,并且您将拥有 OpenIdClaimedIdentifier 和 OpenIdFriendlyIdentifier 的隐藏字段。为了确保它们的值没有改变,我会使用 cookie...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多