编辑视图中的不可编辑的ViewModel属性

时间:2010-02-11 04:37:21

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

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

在这个类中,有许多属性直接映射到LINQ-to-SQL类,称为User。我正在使用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创建操作并使用此部分完整的UserCreateViewModel对象显示“创建”视图。
  6. 此位是问题用户然后完成其他数据(DisplayName等)并发布结果UserCreateViewModel
  7. 问题在于,在步骤5和步骤6之间,如果未绑定OpenId参数,则会丢失。我不想在创建表单中显示用户OpenIdClaimedIdentifierOpenIdFriendlyIdentifier,但如果删除数据,则会在帖子上丢失其绑定。

    我希望这有点澄清这个问题

3 个答案:

答案 0 :(得分:4)

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

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

修改后更新

  

有更好的方法吗?

更好的是相对术语。肯定有其他方法可以达到你想要的效果,但隐藏的<input>字段通常用于这种情况,并且正如你所说,工作。

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

您是否有任何特殊原因想要使用隐藏字段?这有助于我们更好地回答您的问题。

是因为你担心安全吗?从您描述逻辑流程的方式来看,使用隐藏的<input>会让您在提交之前更改经过身份验证的OpenIdClaimedIdentifierOpenIdFriendlyIdentifier隐藏值的人员。如果这是您关心的问题,那么您可以加密解析回客户端的数据。

替代解决方案是:

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

    Session["OpenIdClaimedIdentifier"] = value;

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

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

答案 1 :(得分:1)

问题是你有一个两阶段的过程,一半的数据来自DotNetOpenAuth,另一半来自用户。如您所希望首先进行DotNetOpenAuth调用,您需要找到一些方法来存储该数据,直到最后保存到数据库调用。

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

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

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

或者可以重构您的方法,以便您的open auth调用创建用户帐户并将其保存到数据库中,并从DotNetOpenAuth调用中检索详细信息。然后将用户重定向到“编辑帐户”页面,然后他们可以更新其详细信息。

答案 2 :(得分:1)

如果你想使用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 ......