0

I have a web application in ASP.Net MVC 4.

I have a model called User with many properties like Name, Email, Password, BirthDate, Gender, etc.

public class UserModel
{
    public string UsrId { get; set; }

    [Required(ErrorMessage = "Please enter the user's name.")]
    public string UsrName { get; set; }

    [Required(ErrorMessage = "Please enter the email.")]
    public string UsrEmail { get; set; }

    [Required(ErrorMessage = "Please enter the password.")]
    public string UsrPwd { get; set; }

    [Required(ErrorMessage = "Please select the gender")]
    public ParamData Gender { get; set; }

    [Required(ErrorMessage = "Please select birthdate")]
    public string UsrBirthDate { get; set; }

//.... other properties
}

I used ModelState validation in a Login Validation. For Login I used the properties Email and Password. Both properties had Annotations of type "Required" , to validate not to enter empty strings. I used a ViewModel "LoginViewModel" viewmodel which one its properties was "User" type. I called ModelState.IsValid and it worked ok.

public class LoginViewModel
{
    public UserModel LoginDat { get; set; }
    // other props of ViewModel  ...
}

Now I am doing a Registration (1st step of registration) validation. For that I have a "Register1ViewModel" viewmodel, and again, one of its properties is of type User model. But for registration (first step) I only need the following 3 User's properties: Name, Gender, BirthDate. Those properties are too in User Model. I wrote Required annotations for these 3 properties.

public class RegiViewModel
{
    public UserModel RegiDat { get; set; }
    // other props of ViewModel  ...
}

But when I call ModelState.IsValid it results false because it asks for Email and Password properties.

[HttPost]
public ActionResult RegisterStep1Post(RegiViewModel VM, string Answer)
{   
    if (ModelState.IsValid)
    {
        RegiViewModel VM2 = GetSomeStuff(VM); 
        return View("Step2Validation", VM2);  // Ok go next step

    }
    else
    {
        return View("RegiStep1ViewPost", VM); // return to form
    }        
}

Is there any way of use only a defined subset of a model's properties when using ModelState.IsValid? I don't want to duplicate my User model.

Paul Z.
  • 105
  • 1
  • 2
  • 11
  • Please post the code for the models. – JuanR Oct 04 '17 at 13:39
  • I think your registration model gets fail because of paramData in gender. did you check which exact field getting error in debug while validating model in controller? – Ubiquitous Developers Oct 04 '17 at 14:28
  • No, ParamData is just a class. Even I comment that, the ModelState gives false. In Debug I saw it asks for Email and Password . – Paul Z. Oct 04 '17 at 14:43
  • 1
    View models should not contain properties which are data models. The whole point of view models is to create a class containing only the properties you need in a view - [What is ViewModel in MVC?](https://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) –  Oct 04 '17 at 22:34

2 Answers2

2

You need to break down your models.

For login purposes, I assume you only need a an e-mail and password, so your model should look like this:

public class LoginViewModel
{
    [Required(ErrorMessage = "Please enter the email.")]
    public string UsrEmail { get; set; }

    [Required(ErrorMessage = "Please enter the password.")]
    public string UsrPwd { get; set; }
}

Your registration model should contain only the information it cares about:

public class RegiViewModel
{
    [Required(ErrorMessage = "Please enter the user's name.")]
    public string UsrName { get; set; }

    [Required(ErrorMessage = "Please select the gender")]
    public ParamData Gender { get; set; }

    [Required(ErrorMessage = "Please select birthdate")]
    public string UsrBirthDate { get; set; }
}

At some point in the registration process, you will ask the user to enter an e-mail and password. At that time, you use the LoginViewModel class again.

JuanR
  • 7,405
  • 1
  • 19
  • 30
-1

Can't you just make a base class with the 3 properties needed in your login? And then derive your UserModel class from this one?

Another way but not really recommended is to create your own 'RequiredAttribute':

    public class SpecialRequired : RequiredAttribute
{    
    string _context = "";
    public string Context
    {
        get
        {
            return _context;
        }
        set
        {
            _context = value;
        }
    }

    public override bool IsValid(object value)
    {
        if (_context == "Register")
        {
            return true;
        }
        return false; // With some more own logic
    }
}

You could use it like this: [SpecialRequired(Context="Register")]

Reno
  • 542
  • 3
  • 13
  • I tried to use inheritance, but ModelState goes through inheritance and asks for the properties in base class. – Paul Z. Oct 04 '17 at 15:03
  • 2
    OK, you don't just add properties but the "required" constraint needs also to be removed based on the context.... In this case it's recommended to break down your model per view, like described by Juan below. At the end they are "View Models". Another possibility is to make your own 'contextual' 'required'-attribute. I'll add an example in my answer – Reno Oct 04 '17 at 15:49
  • 1
    I don't think a special attribute is a good idea. It feels like we are putting a patch as a result of misuse of models. – JuanR Oct 04 '17 at 16:25
  • I agree; I would go too for breaking down your models in different ones – Reno Oct 04 '17 at 16:27
  • Ok, so I break it. But talking about Email and Password. These both properties are common to Login and Register. Please write the Login and Register viewmodels about these properties. How should I write the two classes please – Paul Z. Oct 04 '17 at 16:54
  • And If we talking about UserName property, it's used in one step of Register process, but also it's used in almost every part inside the apllication – Paul Z. Oct 04 '17 at 17:11
  • @PaulZ.: You are mixing apples and oranges. One thing is the information you are collecting from the user. Another one is the information you need to provide the view. You can certainly use the model to pass data to the view, but you can't mark it as required if you are not going to send it back (which is what is happening with the credentials). Some of the information you pass to the view could go into the `ViewBag`. – JuanR Oct 04 '17 at 18:12