Question

I have defined a base class with some properties like:

public string CreatedByName { get; set; }
public DateTime CreatedOn { get; set; }

public string UpdatedByName { get; set; }
public DateTime UpdatedOn { get; set; }

If I create a model object inheriting from this base class like following in my controller:

[HttpPost]
public ActionResult Create(Person person)
{
    if (ModelState.IsValid)
    {
        person.Id = Guid.NewGuid();

        //audit information
        person.UpdatedByName = User.Identity.Name;
        person.UpdatedOn = DateTime.Now;
        person.CreatedByName = User.Identity.Name;
        person.CreatedOn = DateTime.Now;            

        UoW.Persons.Add(person);
        UoW.Commit();
        return RedirectToAction("Index");
    }
    return View(person);
}

it never works as ModelState.IsValid always returns false because the audit properties are not set yet at this stage.

Is there any way to set this of kind of the values in some common place (I tried to write helper class but how to get User?) and that to before model validation kicks in?

Or only choice is to make the audit properties nullabe [not required]?

EDIT:-

tried @archil's suggestion:

HAHAHAH......... DO THIS IN Get Action

public ActionResult Create()
{
    var person=new Person();
    person.UpdatedByName = User.Identity.Name;
    person.UpdatedOn = DateTime.Now;
    person.CreatedByName = User.Identity.Name;
    person.CreatedOn = DateTime.Now;

    return View(person);

still getting:

  • The CreatedOn field is required.
  • The UpdatedOn field is required.
Was it helpful?

Solution

That's why you should be using ViewModels in controller actions, not domain models. Viewmodel would only contain properties needed for person creation, and you could set audit and all the other values later on already validated model.

[HttpPost]
public ActionResult Create(CreatePersonViewModel createPerson)
{
    if (ModelState.IsValid)
    {
        Peron person = MapViewModel(createPerson);

        //audit information
        person.UpdatedByName = User.Identity.Name;
        person.UpdatedOn = DateTime.Now;
        person.CreatedByName = User.Identity.Name;
        person.CreatedOn = DateTime.Now;            

        UoW.Persons.Add(person);
        UoW.Commit();
        return RedirectToAction("Index");
    }
    return View(createPerson);
}

For mapping, you could use widely used AutoMapper or similar

Update

You could use Controller.UpdateModel or Controller.TryUpdateModel to manually invoke model-binding and validation

Something like this

[HttpPost]
public ActionResult Create()
{
    Person person = new Person();
    person.UpdatedByName = User.Identity.Name;
    person.UpdatedOn = DateTime.Now;
    person.CreatedByName = User.Identity.Name;
    person.CreatedOn = DateTime.Now;    


    if (TryUpdateModel(person))
    {
        UoW.Persons.Add(person);
        UoW.Commit();
        return RedirectToAction("Index");
    }
    return View(person );
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top