Anjani Singh

Dynamic Models for MVC View

.net4.0

Strongly typed views are very useful in MVC for rendering model data on page and binding the properties with the input fields. Moreover, strongly typed views give intellisense support, so that we can choose the right property name for the control. No doubt, statically typed languages are of big advantages. But with .NET 4.0, supports have been provided to dynamically define the types. One of the features is ExpandoObject. Through ExpandoObject, we can create an instance at run-time by adding properties to it.

ExpandoObject can be initialized by:

dynamic expando = new ExpandoObject();

dynamic keyword (Introduced .NET 4.0) are used for initializing variables whose types are late bounded. This is different from var keyword (Introduced .NET 3.0) where we know the type at compile time.

The ExpandoObject class is a part of System.Dynamic namespace. Internally it uses IDictionary<String, Object> for managing contents. More about expandoObjects can be found on this site.

There can be scenarios where we would require dynamic models for view. For example, a view having fields which cannot be bound to any predefined class.

First of all I created expandoObject and dynamically added properties in it as:

  public ActionResult Marks()
        {

            dynamic expando = new ExpandoObject();
            var marksModel = expando as IDictionary<string, object>;

            string studentName = "Alice";
            marksModel.Add("Name", studentName);
            marksModel.Add("Physics", 24);
            marksModel.Add("Chemistry", 45);
            marksModel.Add("Biology", 31);

            return View(marksModel);

        }

In the Action Method, I created the expandoObject and added three fields to be rendered on view along with their values. I passed this dynamic model to View.

Creating dynamically typed views

On the view I declared model type of page as dynamic-

@model dynamic

<h2>Enter Marks For @Model.Name</h2>

@using(Html.BeginForm("SubmitMarks", "Account")
 {

@Html.ValidationSummary()

<fieldset>

    @Html.Hidden("Name", (string)Model.Name)

    <legend></legend>

    <ol>

        @Html.Label("Physics", (int)Model.Physics)

        @Html.TextBox("Physics", (int)Model.Physics)

    </ol>

    <ol>

        @Html.Label("Chemistry",(int)Model.Chemistry)

        @Html.TextBox("Chemistry", (int)Model.Chemistry)

    </ol>

    <ol>

        @Html.Label("Biology", (int)Model.Biology)

        @Html.TextBox("Biology", (int)Model.Biology)

    </ol>

    <input type="submit" value="Submit" />

</fieldset>
}

You will notice that I have not used extension with signature @Html.TextBoxFor(m=>m.Physics) but used @Html.TextBox(name,value). This is because Lambda expressions do not support dynamic objects.

Lambda expressions do not support dynamic objects

 

 

The value of marks which was added in model has been rendered on screen for Alice. (Please note that this marks has nothing to do with my marks during college days)

Example usage of dynamic models

There can be many scenarios where we can use dynamically typed views and dynamic models. One situation where it may be useful is in generating dynamic forms. Suppose we are having different sets of views for different students. They are enrolled in different subjects and for every student set of fields (subjects in our case) are stored in Database. Now we have to create classes at run-time based on these subjects, so that we can make changes in DB directly for assigning or removing the subjects and make corresponding changes in Views (which can also be stored in DB).

     public ActionResult Marks()
        {

            dynamic expando = new ExpandoObject();

            var marksModel = expando as IDictionary<string, object>;
            string studentName = "Bob";
            var subjects = GetSubjects(studentName);
            // Get subjects from DB for the particular student

            marksModel.Add("Name", studentName);
            foreach (string subject in subjects)
            {
                marksModel.Add(subject, 23); // Hardcoded Marks Value as 23
            }

            return View(marksModel);

        }

List of subjects are coming from Database for the student Bob.

The subjects Bob has taken, as fetched from DB are “Physics”, “Biology”, “Maths”, “Chemistry”, “Zoology”.

Let’s make the corresponding changes in Views or create another View for Poor Bob.(Poor, because I know the burden of extra subjects )

I created fields for every subject for Bob on the view as below:

@model dynamic

<h2>Enter Marks For @Model.Name</h2>

@using (Html.BeginForm("SubmitMarks", "Account"))

{

    @Html.ValidationSummary()

    <fieldset>

        @Html.Hidden("Name", (string)Model.Name)

        <legend></legend>

        <ol>

            @Html.Label("Physics", (int)Model.Physics)

            @Html.TextBox("Physics", (int)Model.Physics)

        </ol>

        <ol>

            @Html.Label("Chemistry", (int)Model.Chemistry)

            @Html.TextBox("Chemistry", (int)Model.Chemistry)

        </ol>

        <ol>

            @Html.Label("Biology", (int)Model.Biology)

            @Html.TextBox("Biology", (int)Model.Biology)

        </ol>

        <ol>

            @Html.Label("Maths", (int)Model.Maths)

            @Html.TextBox("Maths", (int)Model.Maths)

        </ol>

        <ol>

            @Html.Label("Zoology", (int)Model.Zoology)

            @Html.TextBox("Zoology", (int)Model.Zoology)

        </ol>

        <input type="submit" value="Submit" />

    </fieldset>

}

The displayed form now looks like shown below. Hence, there is no need to stop debugging the solution and the View can be generated for another student by using expandoObject features.

displayed form now looks like shown below

Posting the form to controller

Posting the form for such model will require a super-set class which has properties of all the possible properties in different views. Then views can be posted to controller just like normal form.

I created model for that-

        public class ReportCardModel
        {
            public string Name { get; set; }
            public int Physics { get; set; }
            public int Chemistry { get; set; }
            public int Maths { get; set; }
            public int Zoology { get; set; }
            public int Biology { get; set; }
            public int History { get; set; }

        }

There will be automatic binding of form with model just like it occurs for strongly typed views because default model binder for MVC looks for fields name on the view and binds with appropriate matching property of class. Screenshot below shows model is binding the field value on view.

model binder for MVC

There may be scenarios where we can’t use any class for even binding the posted values. This is possible in the cases when we have to keep everything dynamic like the Name of fields can be changed too. For example, Maths can be changed to Mathematics.

For these kinds of problems, Custom Model binder will be helpful. We can create a dictionary in our model to receive field value (as FormCollection) and map posted values in dictionary.

Summary

There are limitations when using dynamic models, like lack of intellisense support, lack of compile time error check and also lack of support in using it with Lambda Expressions. But few times they are useful in views just like dynamic types are useful at other places.

Most of the time, we decorate our properties with attributes, that is also not possible when using dynamic models. But there is a workaround as far as attributes for client side validation is concerned. Attributes on property of a model is ultimately translated to html attributes on input fields. We can create our own control extension and add exactly those HTML attributes which are added by attributes on properties. JavaScript validation framework will parse this and trigger required validation. But, implementing server side validation is still difficult.

 

Related Articles

#Tech

NHibernate, Linq and Lazy Collections

For the past few months we have been busy building a services framework for one of our clients so that they can build all of their enterprise web services without ever having to worry about the cross cutting concerns and... Read more
#Tech

Page Redirects using Spring.NET

Who is responsible for page redirects in ASPNET MVP – The View or the Presenter None of the above, it is you :) On a serious note, it is the View as one shouldn’t pollute the Presenter with the page navigation... Read more
  • Zia Haque

    Hi, could you please let me know from where i can download the code for “Dynamic models for MVC view”

  • Pingback: Discussing The Basics of Django With You – scribdbook()

  • rahul pathak

    i shall say wow nice

  • Anjani Singh

    Thanks Rahul Pathak.

  • Anjani Singh

    @disqus_FuE9LF4c34:disqus Thanks for reading and showing interest. Currently, the codebase is not shared but most of the relevant code snippets has already been posted. You can create any template MVC project and copy these snippets