2010-02-11 83 views
4

在我的ASP.NET MVC2应用程序中,我有一个名为UserCreateViewModel的ViewModel类。编辑视图中的不可编辑的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) 

返回的视图模型不包含OpenIdClaimedIdentifierOpenIdFriendlyIdentifier值。

我调查了[HiddenInput]属性的使用,但我似乎无法完成此项工作。我也曾尝试在表单中使用隐藏的<input/>标记,该标记有效,但这看起来有点笨拙。

有没有更好的方法来做到这一点?或者正在使用隐藏的<input>唯一的方法?

编辑:为了澄清逻辑流程:

  1. 用户尝试使用其OpenID登录。
  2. DotNetOpenAuth执行身份验证,如果成功,则返回OpenIdClaimedIdentifierOpenIdFriendlyIdentifier
  3. 我做了一个数据库检查,看看是否已经有一个用户与这个Id。
  4. 如果还没有用户,则创建一个临时设置为UserCreateViewModel的OpenId字段。这存储在TempData
  5. 重定向到UserController创建操作并显示带有部分完成的UserCreateViewModel对象的“创建”视图。
  6. 这一点是问题用户然后完成其他数据(显示名称等),并张贴结果UserCreateViewModel

问题是在步骤5和步骤6之间,如果OpenId参数未绑定,则会丢失OpenId参数。我不想在创建表单中显示用户OpenIdClaimedIdentifierOpenIdFriendlyIdentifier,但是如果我删除了数据,则他们的绑定在帖子上丢失。

我希望这个澄清一点

+0

你在一个创建,如果没有设置它有空值是不是正常的?你想要什么,空弦? – 2010-02-11 04:49:11

+0

这不完全是我的意思,我已经重新澄清了这个问题。 – 2010-02-11 11:05:08

+0

有没有你不想使用隐藏字段的原因?它可以帮助我们更好地回答你的问题。编辑完成后,我已更新了我的答案。 – 2010-02-15 15:15:49

回答

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获取用户标识以查找用户记录,而不是从表单中查找。

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

+0

感谢您提供最新的答案。 2阶段的数据库提交过程并不是我想到的。我会继续调查,看看我能找到什么。 – 2010-02-16 00:03:56

+0

Dang编辑计时器:如果这是一个标准的做法,我很乐意使用隐藏字段。我喜欢2阶段过程的想法,但是这并不意味着我将不得不将模型的用户ID存储在数据库更新的窗体上?或者这是[绑定]排除的作用? – 2010-02-16 00:27:01

+0

@Alistair您通常会将用户标识存储在身份验证Cookie中。这样你就知道用户ID没有改变。查看我的更新。 – 2010-02-16 15:05:28

1

问题在于你有两个阶段的过程,其中一半数据来自DotNetOpenAuth调用,另一半来自用户。当你想要首先发生DotNetOpenAuth调用时,你需要找到一些方法来存储这些数据,直到最后保存到数据库调用。

这应该在客户端上完成,所以通常的办法由具有隐藏字段实现这样的事情......

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

其他客户端选项是cookies或URL既不似乎更合适比这里隐藏的领域。

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

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 ...