MVC continued

I had a skype conversation with Peter Morris, describing the new ability to create offline objects with ECO, and how that can be used to let MVC work on the model directly as described here.

We both agree that even if it is perfectly possible to let MVC use the business objects this way – it is not optimal for a couple of reasons: security, business rules and overall control of information.

It is preferred to add a layer of abstraction between the model and the view – the view model. The view model can be described as a perspective or a section or a transformation of parts of the model and it offers a good place to mold information from the model in specific formats – like when combining multiple attributes that builds up an address to a customer in the model to a single string that we may want to present in the view.

It is also likely that in large projects with multiple developers that hold different skills – like model savvy developers and view savvy developers – the model developer might not “trust” the view developer to access only the “correct” or intended part of the model for the task at hand. Then the View model is a perfect way to define each use case / task / view and only hold the information needed.

View models defined in Modlr are described in multiple articles on this site – but the problem until now – was that they always needed to belong to an EcoSpace. This made it impossible for MVC to instantiate them to send back data from a postback to our controller.

How we solved it:

The View models too can now be in Offline mode. They can be code generated for easy static type check and data binding support. They work equally well in MVC, WPF, Silverlight or whatever your choice of UI layer.

The code generated ViewModel has been cleaned up for this release (compared to how we introduced it)– if you used them earlier you will need to adapt your code (we dropped the “Root” from vm.Root.Attribute so that it is now vm.Attribute. Further more the base class VMClass is no longer inheriting Dictionary<>, if you need your vm to act as a dictionary use the vm.AsDictionary property)

Given this model:

image

I declare a ViewModel:

image

And now I can use the standard MVC scaffolding for creating Views:

image

I also use the standard actions in Visual Studio to create Controllers, but change the base class to EcoController (from Peters Sample). Some controller code examples:

    public class ElaborateVMController : EcoController
    {
        //
        // GET: /Elaborate/

        public ActionResult Index()
        {
          var all=EcoSpace.Extents.AllInstances<ElaborateClass>().
                            Select(o => ElaborateVM.Create(EcoSpace, o));
          return View(all);
        }

        //
        // GET: /Elaborate/Details/5

        public ActionResult Details(string Identity)
        {
          IObject io = EcoSpace.ExternalIds.ObjectForId(Identity);
          return View(ElaborateVM.Create(EcoSpace, io.AsObject as ElaborateClass));
        }

        //
        // POST: /Elaborate/Create

        [HttpPost]
        public ActionResult Create(ElaborateVM offlineElaborateVM)
        {
          try
          {
            ViewModelHelper.ApplyValues(offlineElaborateVM, 
                           ElaborateVM.Create(EcoSpace, new ElaborateClass(EcoSpace)), null);
            if (Commit())
              return RedirectToAction("Index");
            return View();
          }
          catch
          {
            return View();
          }
        }


and example of the scaffolded View code:

@model EcoMVC.ViewModelCodeGen_ElaborateVM.ElaborateVM

@{
    ViewBag.Title = "Details";
}

<h2>Details</h2>

<fieldset>
    <legend>ElaborateVM</legend>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.Attribute1)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Attribute1)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.Attribute2)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Attribute2)
    </div>

It ends up looking like this:

image image

 

Attributes in generated code

Oh – and before I forget – you probably want to decorate the ViewModel attributes with specific MVC attributes like [Required]. In Modlr all tagged values that start with a star “*” is added to the generated code. This:

image

on a ViewModel column, will come out like:

    [System.ComponentModel.DataAnnotations.Required()]
    [GeneratedCodeAttribute("ECO", "6.0.0.0")]
    public string Attribute1 {
      get {

And that will be picked up by MVC as :

image

 

(Swedish for Field Attribute1 is required)

Taking it further

As I said earlier I am still no MVC expert. I can see the merits to MVC but I am also still confused on all the name matching that is going on behind the scenes. I would be very happy to have someone do a better sample and share with all here…

This entry was posted in Modlr, MVC, ViewModel. Bookmark the permalink.

14 Responses to MVC continued

  1. wangwei says:

    This is the way to resolve problem,but this is complex. And how to use viewmodel? I didn’t find help document.

  2. wangwei says:

    this is one bug while add Attributes in tagged value at modlr.
    I add two attributes ,and code updated, the code like this:
    [System.ComponentModel.DataAnnotations.Display(“Name=\”username\””)]
    [System.ComponentModel.DataAnnotations.Required(“”)]
    but this code is error ,don’t compile. the right code should be like this:

    [System.ComponentModel.DataAnnotations.Display(Name=”姓名”)]
    [System.ComponentModel.DataAnnotations.Required]

  3. wangwei says:

    how to update one offline class?

  4. wangwei says:

    how to update the class from the view modal class ?

  5. Hans says:

    You call ViewModelHelper.ApplyValues with one offline viewmodel and one online viewmodel.
    The the thouched values in offline, will be applied to the online…
    Since the online is rooted in real online objects – these will be updated…

    ViewModelHelper.ApplyValues(offlineElaborateVM, ElaborateVM.Create(EcoSpace, new ElaborateClass(EcoSpace)), null);

  6. wangwei says:

    ViewModelHelper.ApplyValues(offlineElaborateVM, ElaborateVM.Create(EcoSpace, new ElaborateClass(EcoSpace)), null);
    Have the param of “ElaborateVM.Create(EcoSpace, new ElaborateClass(EcoSpace))” created new object of “ElaborateClass ” ?

    • hans says:

      Yes – that creates a new ElaborateClass.

      To update an existing go like this:

      ElaborateClass e1 = EcoSpace.ExternalIds.ObjectForId(Identity).AsObject as ElaborateClass;
      ViewModelHelper.ApplyValues(offlinevm, ElaborateVM.Create(EcoSpace, e1), null);

  7. Alois says:

    using TaggedValues in codegenerated viewmodels requires a namespace reference like “using Eco.UmlCodeAttributes” which is currently not set in the codegenerated file (ECO6).

    Kind regards
    Alois

  8. Alois says:

    As wangwei already mentioned, the creation of System.ComponentModel.DataAnnotations with a prefixed “*” doesn’t work in some scenarios.
    A possible solution may be, to modify the code creation in this case, to completely omit the value part of the TaggedValue (option should also omit the paranthesis). The tag part should then contain the complete DataAnnotation statement with all parameters.
    In the case of TaggedValues with prefixed “*” it also would be nice to have the System.ComponentModel.DataAnnotations namespace included within the using list.
    Kind Regards
    Alois

Leave a Reply

Your email address will not be published. Required fields are marked *

*