Konstantin Fedoseev
Konstantin Fedoseev

Reputation: 301

What Is The Best Practice To Deal With MVC Post Models?

I'm pretty new to MVC and still confused what the best and proper way for 2 cases for with same result. Let's say some user should add new sub category for specific root category.

Case 1: SubCategory is a mapped class by EF where all properties not nullable.

Controler:

    [Authorize]
    public ActionResult Create()
    {
        SubCategory subCategory = new SubCategory();

        subCategory.RootCategoryID = 1;

        return View(subCategory);
    }

    [Authorize]
    [HttpPost]
    public ActionResult Create(SubCategory thisSubCategory)
    {
        if (ModelState.IsValid)
        {
           //And some BL logic called here to handle new object...
        }
    }

View:

    @Html.HiddenFor(model => model.ID)

    @Html.HiddenFor(model => model.RootCategoryID)

    <h3>Sub Category Name: </h3>

    @Html.EditorFor(model => model.CategoryName)

    @Html.ValidationMessageFor(model => model.CtaegoryName)

    <input id="btnAdd" type="submit" value="Add" />

Case 2: Add helper class as controller's model and populate EF object after post

Controler:

    class SubCategoryHelper
    {
       public string Name { get; set; }
    }

    [Authorize]
    public ActionResult Create()
    {
       SubCategoryHelper subCategory = new SubCategoryHelper();

       return View(subCategory);
    }

    [Authorize]
    [HttpPost]
    public ActionResult Create(SubCategoryHelper thisSubCategory)
    {
        if (ModelState.IsValid)
        {
           SubCategory newSubCategory = new SubCategory();

           newSubCategory.RootCategoryID = 1;

           newSubCategory.CtaegoryName = thisSubCategory.Name;

           //And some BL logic called here to handle new object...
        }
    }

View:

Sub Category Name:

    @Html.EditorFor(model => model.Name)

    @Html.ValidationMessageFor(model => model.Name)

    <input id="btnAdd" type="submit" value="Add" />

Both ways makes the same, but the first way looks less secure because of the hiddens that could be changed on the client side. The second way much longer, imagine the same way for rich objects such as Client or Product... What should I choose? Or there is some other way?

Upvotes: 4

Views: 1252

Answers (2)

mipe34
mipe34

Reputation: 5666

The first case is good for simplicity. If you extend your model you will have to do changes on less places. It is not less secure. You can bypass creating or binding the hidden input fields by several ways.

Use BindAttribute to bypass binding of property:

ActionResult Create([Bind(Exclude = "RootCategoryId")]
                    SubCategoryHelper thisSubCategory) {//....}

Or ScaffoldColumnAttribute on the model class property (e.g. when you use edit templates):

[ScaffoldColumn(false)]
public int RootCategoryId {get; set;}

Or just simple do not expose it (as you did in your example using the Html.HiddenInput helper).


The second approach, you have described, is often called ViewModel pattern. It encourages seperation of your Presentation and Domain layer. The advantage is, that your domain model will not be polluted with presentation layer specific code (like various display attributes etc.). Hovewer it brings another overhead of mapping between domain models and view models.

There is probably no genarel rule of thumb. It depends on type of your appliction.

If it is basically some simple data driven CRUD application, you can easily stay with the first one. Nevertheless, when your application becomes larger, you will definetly appreciate the freedom of your hands on separate layers. And if your BLL code is used with some other kind of "client" (web service, desktop etc.) except the ASP MVC I would defintely go with the second option.

I also suggest to read this great article: Is layering worth mapping

Upvotes: 2

Martin
Martin

Reputation: 11041

I always go with Case 2, whether it's a small project I work on or a big project, I always separate my data layer (entity framework) and my UI layer. Especially if you are using Entity Framework, because those objects can get huge, and it's a lot of crap that you are passing around that you more often don't need.

Instead of calling it a Helper class, call them ViewModel or Model. In your case, SubCategoryViewModel.

public class SubCategoryViewModel
{
   public int Id {get;set;}
   public int RootCategoryId {get;set;}
   [Required]
   public string Name { get; set; }
}

[Authorize]
public ActionResult Create()
{
   var subCategoryViewModel = new SubCategoryViewModel();

   return View(subCategoryViewModel);
}

[Authorize]
[HttpPost]
public ActionResult Create(SubCategoryViewModel viewModel)
{
    if (ModelState.IsValid)
    {
       var subCategory = new SubCategory();

       subCategory.RootCategoryID = 1;

       subCategory.CategoryName = viewModel.Name;

       //And some BL logic called here to handle new object...

    }
}

Upvotes: 2

Related Questions