views:

187

answers:

4

Background

I'm learning the ropes around how to use ASP.NET MVC properly, and ran into this issue with models:

I have a model that describes a contact I can get that out of the form for creating a new contact, but say when we edit a form, I retrieve it from the repository, show the fields on the contact form and then get the contact object and send that to the model.

Problem

I have a business rule that some fields are not allowed to be edited after creation and other fields are only available after editing.

I receive a dirty object from the user (one with fields they should touch) and using the MVC Binding method (sspecifying the object in the method signature) the users inserts a non-editable field contact_dob.

Question

  1. Should I instead retrieve the record again, overwrite only the fields I want to update and then send it to the database?

  2. What's the best method when I don't want to retrieve the Entire object again from the database, do I just redo another EntityModel that's a lighter version of the main model and use that back and forth?

  3. Am I going about this the wrong way? What are the best practices for limiting what users can edit?

+1  A: 

I think you can build your model, the Contact class, and in the edit view you should allow only fields that can be edited, and hide or set as not editable the fields you don't want to be edited, then in your controller you'll get the original contact and update it with the values of the fields you allowed in the edit view like:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
    Contact contact = repository.GetById(id);
    try {
        UpdateModel(contact);
        repository.Save(contact);
        return RedirectToAction("Details", new { id=contact.Id });
    }
    catch(Exception ex) {
        // Do something...
    }

    return View(contact);
}
Alaor
A: 

You should use the EXCLUDE and INCLUDE constraints in Action method. This way your model will exclude unwanted fields during model binding.

public ActionResult Create([Bind(Exclude="contact_dob")] Contact contact)

    {
        _db.AddToContacts(contact);
        _db.SaveChanges(); 
        return RedirectToAction("Index");
    }
Rasik Jain
Thats cool, I didnt know you could do that! What about in your SaveChanges method, how do people manage this?
Lisa Auckett
@Lisa Auckett: You'd implement this in your repository; but the 'SaveChanges' method he speaks of is actually a part of an ORM -- Linq-To-SQL.
George Stocker
A: 

The 'best practice' is to have validation done against your submitted model and not allow changes to certain fields. You can use JQuery / JavaScript to grey out textboxes that cannot be changed; as well as validation on the Model side to disallow changes to certain fields (by comparing them against what came from the database).

You can use Model Validation to disallow changes to certain fields. ASP.NET MVC 2 has this functionality. You don't even need to re-retrieve the object.

In the 'NerdDinner Walkthrough' (ASP.NET MVC 1.0), there's a walkthrough of Validation.

George Stocker
+1  A: 

It sounds like the best solution would be to use a custom ViewModel. This is an object that contains all the fields that you would want the user to submit to the controller.

You will need to reload the contact object from the database - I don't think you can get around that without opening yourself up to other issues.

public ActionResult Edit(ContactViewModel viewModel)
{
    var contact = repository.GetContacts().WithId(viewModel.Id);

    // Update the contact with the fields from the viewModel

    repository.Save(contact);
}
Jaco Pretorius