代码之家  ›  专栏  ›  技术社区  ›  Alastair Pitts

编辑视图中不可编辑的视图模型属性

  •  4
  • Alastair Pitts  · 技术社区  · 16 年前

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

    在这个类中,有许多直接映射到Linq-to-SQL类(称为用户)的属性。我正在使用automapper执行这个映射,它工作得很好。

    在UserController的创建操作中,我接收到一个部分完整的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; }
    }
    

    在创建视图中,我不希望 OpenIdClaimedIdentifier OpenIdFriendlyIdentifier 可编辑。

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

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

    返回的ViewModel不包含 打开IDclaimedidentifier OpenID友好标识符 .

    我已经调查了 [HiddenInput] 但我似乎做不到。我也试过用隐藏的 <input/> 表单中的标签有效,但这似乎有点笨拙。

    有更好的方法吗?或者正在使用隐藏的 <input> 唯一的办法?

    编辑:澄清逻辑流程:

    1. 用户尝试使用其OpenID登录。
    2. DotNetOpenAuth执行身份验证,如果成功,则返回 打开IDclaimedidentifier OpenID友好标识符 .
    3. 我做了一个数据库检查,看看是否已经有一个具有这个ID的用户。
    4. 如果已经没有用户,则创建一个临时 UserCreateViewModel 同时设置了两个OpenID字段。它存储在 TempData .
    5. 重定向至“用户控制器创建”操作,并显示“创建”视图,此部分完成 用户创建视图模型 对象。
    6. 这就是问题所在 然后用户完成其他数据(显示名称等)并发布结果 用户创建视图模型 .

    问题是,在步骤5和6之间,如果OpenID参数没有绑定,它们就会丢失。我不想给用户看 打开IDclaimedidentifier OpenID友好标识符 在创建表单的过程中,但是如果删除数据,它们的绑定将在日志中丢失。

    我希望这能澄清一点问题

    3 回复  |  直到 16 年前
        1
  •  4
  •   David Glenn    16 年前

    OpenIdClaimedIdentifier BindAttribute

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

    <input>

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

    是因为你担心安全吗?从您描述逻辑流程的方式来看,使用隐藏的 <输入& GT; 会让你容易被更改身份验证的人攻击 打开IDclaimedidentifier OpenIdFriendlyIdentifier 提交前隐藏值。如果这是您的问题,那么您可以加密解析回客户机的数据。

    其他解决方案包括:

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

      Session["OpenIdClaimedIdentifier"] = value;

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

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

        2
  •  1
  •   Russell Giddings    16 年前

    问题是,这里有一个两阶段的过程,一半数据来自dotNetOpenAuth调用,另一半数据来自用户。当您希望DotNetOpenAuth调用首先发生时,您需要找到一些方法来存储该数据,直到最终保存到数据库调用。

    这应该在客户机上完成,所以通常的方法是通过隐藏字段来实现这类事情…

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

    另一个客户端选项是cookie或url,两者都不比隐藏字段更合适。

    或者,可以重新构造方法,以便open-auth调用创建用户帐户并将其保存到数据库中,其中包含从dotnetopenauth调用中检索到的详细信息。然后将用户重定向到一个编辑帐户页面,在那里他们可以更新他们的详细信息。

        3
  •  1
  •   moi_meme    16 年前

    如果要使用hiddeninput属性,同时在类上使用validation属性,则可以通过以下方式修改用户createViewModel:

    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的隐藏字段。为了确保它们的价值不变,我会用一个饼干…