IModelBinder for ASP.NET MVC

Posts   
 
    
Posts: 134
Joined: 10-Jan-2007
# Posted on: 15-Jan-2009 21:53:51   

Not sure if this is the right forum?

Here is a ModelBinder to use with the new ASP.NET MVC framework (tested with the Beta release, all bets are off when RC1 comes out). This will automatically create and populdate LLBLGen objects from form post, query string and route data. Works with both SelfServicing and Adapter.

An overview of Model Binding in ASP.NET MVC can be found here: http://weblogs.asp.net/scottgu/archive/2008/09/02/asp-net-mvc-preview-5-and-form-posting-scenarios.aspx and here: http://weblogs.asp.net/scottgu/archive/2008/10/16/asp-net-mvc-beta-released.aspx#three

This implementation inherits from the provided DefaultModelBinder and defers most of the work to it. For non LLBLGen entities, they just pass through to the default implementation. This code is to help set the primary keys and stop infinite recursive Parent-Child-Parent calls.

Requirements

  • LLBLGen Pro v2.6
  • .NET 3.5 SP1
  • ASP.NET MVC Beta

Usage

Add the LLBLGenModelBinder.cs to your project

In the Global.asax.cs, add this to the Application_Start(): ModelBinders.DefaultBinder = new MvcHelpers.LLBLGenModelBinder();

You will be able to write code like this and have the entities automatically populated from the request

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(CompanyEntity company)
    {
        if (ModelState.IsValid)
        {
            company.Save(true);
            return RedirectToAction("Edit", new { id = company.CompanyId });
        }
        else
        {
            return View(company);
        }
    }

How it works

In order for the Model Binding to find the correct fields, they need to be named correctly.

For the top level object, the take the form parameterName.Field so: <%= Html.TextBox("company.CompanyId", ViewData.Model.CompanyId)%>

For 1-to-1 objects, they look like <%= Html.TextBox("company.NormalAddress.Address", ViewData.Model.NormalAddress.Address)%>

For 1-to-many it gets a little more complex (note: this is the MVC implementation and may change with the RC release) For the many side, it looks for a field that holds the index numbers to iterate, then looks for named form post fields:

<% foreach (ContactEntity contact in ViewData.Model.Contacts) {%>
<tr>
    <td>Contacts.index</td>
    <td><%= Html.TextBox("company.Contacts.index", contact.ContactId)%></td>
</tr>
<tr>
    <td>Contacts.ContactId</td>
    <td><%= Html.TextBox("company.Contacts[" + contact.ContactId + "].ContactId", contact.ContactId)%></td>
</tr>
<tr>
    <td>Contacts.FirstName</td>
    <td><%= Html.TextBox("company.Contacts[" + contact.ContactId + "].FirstName", contact.FirstName)%></td>
</tr>
<tr>
    <td>Contacts.LastName</td>
    <td><%= Html.TextBox("company.Contacts[" + contact.ContactId + "].LastName", contact.LastName)%></td>
</tr>
<% } %>

if you want to add a new object, create any unique index: <%= Html.TextBox("company.Contacts.index", -1)%> <%= Html.TextBox("company.Contacts[-1].ContactId", 0)%> <%= Html.TextBox("company.Contacts[-1].FirstName")%>

NOTES

The Model Binder sets IsNew if a primary key field is set to a meaningful value (for ints > 0, strings not blank, etc.). You can change this behaviour by providing your own form field (i.e. company.IsNew) AND removing the "IsNew" from the list of excluded fields in the LLBLGenModelBinder

The binder only follows relations where the entity is on the PK Side, this keeps circular references from spinning out.

This process "creates" child objects, it does not "syncronize" child objects. It can syncronize objects, but you need to use the UpdateModel method to manually walk the child elements of 1-to-many. In this case, DO NOT output the .index form element because they will be in the child collection twice.

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit2(int id)
    {
        CompanyEntity company = new CompanyEntity(id);
        UpdateModel(company, "company");
        foreach (ContactEntity contact in company.Contacts)
        {
            UpdateModel(contact, "company.Contacts[" + contact.ContactId + "]");
        }

        if (ModelState.IsValid)
        {
            company.Save(true);
            return RedirectToAction("Edit", new { id = company.CompanyId });
        }
        else
        {
            return View(company);
        }
    }

Thanks

Brian Chance

Attachments
Filename File size Added on Approval
LLBLGenModelBinder.zip 3,394 16-Jan-2009 20:18.32 Approved
MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 15-Jan-2009 22:04:56   

As good as any other simple_smile

Matt

Posts: 134
Joined: 10-Jan-2007
# Posted on: 16-Jan-2009 20:20:13   

Forgot to attach, code now attached on the top message.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 18-Jan-2009 10:23:08   

Thanks Brian! smile

I'm sure it will be of help to others simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Posts: 134
Joined: 10-Jan-2007
# Posted on: 29-Jan-2009 23:40:19   

Updated version for use with ASP.NET MVC RC1 is here:

http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=15191

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 30-Jan-2009 02:55:54   

Thanks Brian simple_smile ... I definitely will look into it soon simple_smile

David Elizondo | LLBLGen Support Team