MVC View Model constraints

I made a little MVC sample. I deliberately made it small and simple – but ensured it shows the creation, deletion, and updating of attributes and relations.

01 - VM constraints.png

I have added this sample to the Demos in the general download.

Three ViewModels:

  • One to act as an index page:
02 - VM constraints.png
  • One that shows Example1 and its connected Example2’s:
03 - VM constraints.png
  • And one that shows a single Example2:
04 - VM constraints.png

Then, I made 2 controllers - one for Example1 and one for Example2.

The main goal of using the model-defined ViewModels is to use as little code as possible in the Views and in the Controllers and to also make the code as predictable, simple, and easy to maintain as possible.

The patterns that emerge appear like this:

1. The SHOW STUFF:

        public ActionResult Details(string Identity)
        {
          EcoProject1.Example2 e2 = this.EcoSpace.ExternalIds.ObjectForId(Identity).AsObject as EcoProject1.Example2;
          return View("Details",  VMExample2.Create(this.EcoSpace, e2));
        }

Here we resolve an id to an object, then use the ViewModel as a façade on that object and send it to the view. The benefit is that I do not have to expose my whole business object to the view, and I can also do view specific derivations in the ViewModel.

2. The UPDATE STUFF:

        [HttpPost]
        public ActionResult Details(string Identity, VMExample2 offlinevm)
        {
          Example2 e2 = EcoSpace.ExternalIds.ObjectForId(Identity).AsObject as Example2;
          try
          {
            VMExample2 onlinevm=VMExample2.Create(EcoSpace, e2);
            ViewModelHelper.ApplyValues(offlinevm, onlinevm, null);
            Commit();
            return View("Details", onlinevm);
          }
          catch
          {
            return View("Details", offlinevm);
          }
        }

Here we resolve the id to an object, create an online ViewModel for that object, apply the values from the sent-in offline ViewModel, and commit. The benefits here are mainly that only the things in the ViewModel can change, protecting the rest of your business object. The ViewModel can also be a compilation of details from other parts of your model – and the view need not know anything about this. The ViewModel also has the ability to opt-out of the constraints from the seen classes that do not make sense in this view. This way, class-wide constraints can be used and filtered per view.

3. The DELETE STUFF:

        public ActionResult Delete(string Identity)
        {
          Example1 e1 = this.EcoSpace.ExternalIds.ObjectForId(Identity).AsObject as Example1;
          BusinessDelete(e1);
          Commit();
          return View("Index", VMExample1Index.Create(this.EcoSpace, null));
        }

Again, look up the object from the id, call the BusinessDelete that checks our delete constraints, then prepare a ViewModel for where we should end up afterward. The benefits here are that constraints that are put in place to protect the information from ending up in any illegal state are effectively applied even if the update touches several objects.

4. The CREATE STUFF:

        public ActionResult Create()
        {
          Example1 x1 = new Example1(this.EcoSpace) { Attribute1="HoHoHo",Attribute2="HeHeHe"};
          CommitSkipValidate();
          return View("Index",VMExample1Index.Create(this.EcoSpace, null));
        }

Just create the object and commit, skipping the Validate – since I do not know how to react to objects that break their constraints at birth…

The Views use the ViewModels and get code completion since the ViewModels have generated code:

<table>
@foreach (var item in Model.Example2) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Attribute1)
        </td>
        <td>
            @Html.ActionLink("Details & Edit", "DetailsForExample2", new {  Identity=item.Identity }) |
            @Html.ActionLink("Delete", "DeleteExample2", new { Identity=item.Identity })
        </td>
    </tr>
}
    </table>

Having the bulk of your logic and your rules in the model is a good thing.

Additional Features

To help you maintain your model, there are several new features you may want to use:

1. The CheckModel checks all expressions – ViewModel columns and constraints and derived attributes and associations:

05 - VM constraints.png

2. There is a new CrossReference menu that works on all things in the model - Classes, Attributes, and Associations. You can easily see if an Attribute is in a ViewModel or used by an association, etc:

06 - VM constraints.png
This page was edited 68 days ago on 02/10/2024. What links here