Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bypassing model validation in controller?

I have created an ADO.NET model of my database. Created a new controller with CRUD (entity framework and using the ADO.NET entity model I created).

In my database I have a simple Users table. The Password row in the table will hold the users passwords encrypted with SimpleCrypto (PBKDF2).

In my ADO.NET Users.cs model I have added following validation:

[Required]
[DataType(DataType.Password)]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Password")]
public string Password { get; set; }

That works with jQuery in the browser with validation. But in my controller I am encrypting the Password, and then the Password string will be way more than 20 chars in lenght.

var crypto = new SimpleCrypto.PBKDF2();
var encryptedPass = crypto.Compute(user.Password);

user.Password = encryptedPass;
user.PasswordSalt = crypto.Salt;

_db.Users.Add(user);
_db.SaveChanges();

And this gives me and "Validation failed for one or more entities."-error.

I can copy the user over to a "var newUser" and then set all the properties there, but isn't there a easier way to bypass the model validation in this case?

EDIT: If I remove the validation of the Password prop in the model then everything works. So it is the validation that gives me the error because I alter the Password from 6-20 length chars to +100 lengt chars because of the encryption in the controller.

EDIT: Complete controller section inserted to this question.

[HttpPost]
public ActionResult Create(Users user)
{
    if (!ModelState.IsValid)
    {
        return View();
    }
    if (_db.Users.FirstOrDefault(u => u.Email == user.Email) != null)
    {
        ModelState.AddModelError("", "User already exists in database!");
        return View();
    }

    var crypto = new SimpleCrypto.PBKDF2();
    var encryptedPass = crypto.Compute(user.Password);

    user.Password = encryptedPass;
    user.PasswordSalt = crypto.Salt;

    _db.Users.Add(user);
    _db.SaveChanges();

    return RedirectToAction("Index", "User");
}
like image 496
user1281991 Avatar asked Dec 11 '22 10:12

user1281991


1 Answers

This is where ViewModels enter the game. You should create a model which you pass to the view and map that back to the domain model later.

The ViewModel:

public class RegisterModel
{
    [Required]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [StringLength(20, MinimumLength = 6)]
    [Display(Name = "Password")]
    public string Password { get; set; }
}

The domain model (your current User model):

public class User
{
    // other properties..

    [Required]
    public string Password { get; set; }
}

You can use these models in your controller like this:

The GET action:

public ActionResult Register()
{
    var registerModel = new RegisterModel();
    return View(registerModel)
}

With a view like this:

@model RegisterModel

@Html.LabelFor(model => model.UserName)
@Html.TextBoxFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName)

@Html.LabelFor(model => model.Password)
@Html.PasswordFor(model => model.Password)
@Html.ValidationMessageFor(model => model.Password)

And the POST action:

[HttpPost]
public ActionResult Register(RegisterModel registerModel)
{
    // Map RegisterModel to a User model.       
    var user = new User
                   {
                        UserName = registerModel.UserName,
                        Password = registerModel.Password   // Do the hasing here for example.
                    };
    db.Users.Add(user);
    db.SaveChanges();                           
}
like image 117
Henk Mollema Avatar answered Dec 21 '22 03:12

Henk Mollema