2

I'm not quite understanding how this works.

Passing parameters from my entity objects works fine. But when I create new fields, only the first one is retrieved.

Model User Class:

public class User {

    [Key]
    public long Uid { get; set; }

    [Required]
    [StringLength(50, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 4)]
    [DataType(DataType.EmailAddress)]
    [Display(Name = "Email:")]
    public string Email { get; set; }

    [Required]
    [StringLength(20, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 4)]
    [Display(Name = "User Name:")]
    public string Username { get; set; }

    public string Password { get; set; }

    public byte Role { get; set; }

    public DateTime Created { get; set; }
}

CSHTML:

@using (Html.BeginForm( null,
                    null,
                    FormMethod.Post,
                    new { id = "regform" })
    ) {
@Html.ValidationSummary(true)
<fieldset>
    <legend>Register</legend>

    <div class="editor-label">
       @Html.LabelFor(model => model.Email)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Email)
        @Html.ValidationMessageFor(model => model.Email)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Username)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Username)
        @Html.ValidationMessageFor(model => model.Username)
    </div>

    <div class="editor-label">
        Password:
    </div>
    <div class="editor-field">
        @Html.Password("pwd")
    </div>

    <div class="editor-label">
        Confirm Password:
    </div>
    <div class="editor-field">
        @Html.Password("confirm")
    </div>

    <p>
        <input type="submit" value="Register" />
    </p>
</fieldset>
}

Controller:

    [HttpPost]
    public ActionResult Register(User user, string pwd, string confirm) {
        user.Username = confirm;
        user.Created = DateTime.Now;
        user.Role = 255;
        user.Password = EncryptPassword.Password(pwd);


        if (ModelState.IsValid && pwd == confirm) {
            db.Users.Add(user);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(user);
    }

Where I'm getting confused, is pwd picks up fine. confirm on the other hand remains null. My initial thought that it was calling by order and confirm in the model was simply conPwd. When that didn't work, I changed it's name to confirm. It still is not working and I can't find anything that explains how multiple parameters are passed to the controller.

Edit: Updated my code. Believe it or not, this alone has taken me most of the day to write because I've been trying to understand what I'm doing. There is just so much to take in when you're learning Entities, LINQ, MVC, ASP.NET and Razor all at the same time. Basic C# is the only part I came in to this knowing. :)

David East
  • 31,526
  • 6
  • 67
  • 82
Blanky
  • 251
  • 1
  • 3
  • 15

1 Answers1

1

You need a strongly typed view for your RegisterModel then use a Html.BeginForm to post the data to the controller.

Model

// This is the Model that you will use to register users
public class RegisterModel
{
    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.EmailAddress)]
    [Display(Name = "Email address")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

View (CSHTML)

// This is your strongly typed view that will use
// model binding to bind the properties of RegisterModel
// to the View.
@model Trainer.Models.RegisterModel

// You can find these scripts in default projects in Visual Studio, if you are
// not using VS, then you can still find them online
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

// This is where your form starts
// The "Account" parameter states what controller to post the form to
@using (Html.BeginForm((string)ViewBag.FormAction, "Account")) {
    @Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.")

    <fieldset>
        <legend>Registration Form</legend>
        <ol>
            <li>
                @Html.LabelFor(m => m.UserName)
                @Html.TextBoxFor(m => m.UserName)
                @Html.ValidationMessageFor(m => m.UserName)
            </li>
            <li>
                @Html.LabelFor(m => m.Email)
                @Html.TextBoxFor(m => m.Email)
                @Html.ValidationMessageFor(m => m.Email)
            </li>
            <li>
                @Html.LabelFor(m => m.Password)
                @Html.PasswordFor(m => m.Password)
                @Html.ValidationMessageFor(m => m.Password)
            </li>
            <li>
                @Html.LabelFor(m => m.ConfirmPassword)
                @Html.PasswordFor(m => m.ConfirmPassword)
                @Html.ValidationMessageFor(m => m.ConfirmPassword)
            </li>
        </ol>
        <!-- The value property being set to register tells the form
             what method of the controller to post to -->
        <input type="submit" value="Register" /> 
    </fieldset>
}

Controller

// The AccountController has methods that only authorized
// users should be able to access. However, we can override
// this with another attribute for methods that anyone
// can access
[Authorize]
public class AccountController : Controller
{

    // This will allow the View to be rendered
    [AllowAnonymous]
    public ActionResult Register()
    {
        return ContextDependentView();
    }

        // This is one of the methods that anyone can access
        // Your Html.BeginForm will post to this method and
        // process what you posted.
        [AllowAnonymous]
        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            // If all of the information in the model is valid
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                MembershipCreateStatus createStatus;
                Membership.CreateUser(model.UserName, model.Password, model.Email, passwordQuestion: null, passwordAnswer: null, isApproved: true, providerUserKey: null, status: out createStatus);

                // If the out parameter createStatus gives us a successful code
                // Log the user in
                if (createStatus == MembershipCreateStatus.Success)
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, createPersistentCookie: false);
                    return RedirectToAction("Index", "Home");
                }
                else // If the out parameter fails
                {
                    ModelState.AddModelError("", ErrorCodeToString(createStatus));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

}
David East
  • 31,526
  • 6
  • 67
  • 82
  • You're making me think in a completely different way and more in tune with ASP.Net MVC. One question: I am actually encrypting the password before I store it in the DB (the model is an entity). Where would I put this function? I will update my code. I didn't realize I left too much out. – Blanky Jun 23 '12 at 04:37
  • You add encryption within your Membership provider. When I call Membership.CreateUser(...) I then encrypt the password and send it off to the database. When I call the Log on method, I encrypt the password and compare it with the encrypted password in the database. It's pretty simple if you write it in Membership once and re-use where it is needed. – David East Jun 23 '12 at 04:43
  • No problem. If you need help with Membership just post another question and I can help out there as well. – David East Jun 23 '12 at 04:45
  • 1
    Don't encrypt if you absolutely don't need to, use the hashing abilities of the membership functions and choose sha512 with a salt. Linkedin's recent hack should reinforce this. – Adam Tuliper Jun 23 '12 at 19:52
  • Great point Adam. Could you provide an article that discusses this topic? – David East Jun 23 '12 at 21:35