Uneditable ViewModel properties in a edit view
In my ASP.NET MVC2 application, I have a ViewModel class called UserCreateViewModel.
In this class, there are a number of properties that directly map to a LINQ-to-SQL class, called User. I'm using AutoMapper to perform this mapping and it works fine.
In my Create action of the UserController, I receive a partially complete UserCreateViewModel, that contains information regarding OpenId authentication.
this is the definition of 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; }
}
In the Create view, I do no wish for the OpenIdClaimedIdentifier
or the OpenIdFriendlyIdentifier
to be editable.
I've used a strongly typed create view (using the built in auto create), but this provides me with editable textbox's for these two properties. If I remove the specific html completely, when the create form is return (and is returned directly to a UserCreateViewModel):
[A开发者_高级运维cceptVerbs(HttpVerbs.Post)]
public ActionResult Create(UserCreateViewModel viewModel, string ReturnUrl)
the returned viewModel doesn't contain values for OpenIdClaimedIdentifier
and OpenIdFriendlyIdentifier
.
I have investigated the use of the [HiddenInput]
attribute but I couldn't seem to make this work. I also have tried using a hidden <input/>
tag in the form, which works, but this seems a bit clunky.
Is there a better way to do this? or is using a hidden <input>
the only way?
EDIT: To clarify the logic flow:
- User tries to log in with their OpenId.
- DotNetOpenAuth performs the authentication and if successful, returns a
OpenIdClaimedIdentifier
andOpenIdFriendlyIdentifier
. - I do a Database check to see if there is already a user with this Id.
- If there isn't a user already, then create a temporary
UserCreateViewModel
with both OpenId fields set. This is stored in theTempData
. - Redirect to the UserController Create action and display the Create view with this partially complete
UserCreateViewModel
object. - This bit is the issue The user then completes the other data (DisplayName, etc) and posts the resulting
UserCreateViewModel
.
The issue is that in between steps 5 and 6, the OpenId parameters get lost if they aren't bound. I don't want to show the user OpenIdClaimedIdentifier
or OpenIdFriendlyIdentifier
during the create form, but if I remove the data, their binding is lost on the post.
I hope this clarifies the question a bit
I'm not sure if this is what you're looking for but if you don't want the OpenIdClaimedIdentifier
automatically bound then you can add it to the exclude list of the BindAttribute
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude="OpenIdClaimedIdentifier")]UserCreateViewModel viewModel, string ReturnUrl) {
}
Updated after edit
Is there a better way to do this?
Better is a relative term. There are certainly alternative ways of achieving what you want but hidden <input>
fields are often used in situations like this and, as you have stated, work.
<%=Html.Hidden("OpenIdClaimedIdentifier") %
Is there any particular reason you don't want to use a hidden field? This would help us answer your question better.
Is it because you are concerned about security? From the way you have described your logic flow, using a hidden <input>
would leave you vulnerable to someone changing the authenticated OpenIdClaimedIdentifier
and OpenIdFriendlyIdentifier
hidden values before submitting. If this is your concern then you could encrypt the data parsed back to the client.
Alternative solutions are:
Store the data in the server Session.
Session["OpenIdClaimedIdentifier"] = value;
Or split your process into two stages (consisting of 2 database commits). Update At step 4 when you have confirmed the OpenId authentication you create a user record in your database, get the unique record id created and store it in the authentication cookie (as the user is authenticated at this point). You then redirect to an 'edit user details'. The 'edit' page then takes the user id from the authentication cookie to look up the user record and not from the form.
If you are performing the necessary security checks before the data is saved then I don't see anything wrong with using hidden fields.
The issue is that you have a two stage process here with half the data coming from the DotNetOpenAuth call and the other half coming from the user. As you want the DotNetOpenAuth call to occur first you need to find some way to store that data until the final save to database call.
This should be done on the client, so the usual approach to achieve this sort of thing by having hidden fields...
<%=Html.Hidden("OpenIdClaimedIdentifier") %>
<%=Html.Hidden("OpenIdFriendlyIdentifier") %>
The other client side options are cookies or URL and neither seem more appropriate than hidden fields here.
Alternatively to could restructure your approach so that your open auth calls creates the user account and saves it to the database with details retrieved from the DotNetOpenAuth call. Then redirect the user to an Edit Account page where they could then update their details.
If you want to use the HiddenInput Attribute, And at the same time use validation attribute on your class you could modify your UserCreateViewModel this way :
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; }
}
To display your model with the attribute in your view you use
<%= Html.EditorForModel() %>
or for a single field:
<%= Html.EditorFor(m => m.OpenIdClaimedIdentifier)%>
That way your model would validate automatically and you'll have hidden field for your OpenIdClaimedIdentifier and OpenIdFriendlyIdentifier. To make sure their value hasn't change i would use a cookie...
精彩评论