Web Forms Model Binding Part 1: Selecting Data (ASP.NET vNext Series)

This is the third in a series of blog posts I'm doing on ASP.NET vNext.

The next releases of .NET and Visual Studio include a ton of great new features and capabilities.  With ASP.NET vNext you'll see a bunch of really exciting improvements with both Web Forms and MVC - as well as in the core ASP.NET base foundation that both are built upon.

Today's post is the first of three posts I'll do over the next week that talk about the new Model Binding support coming to Web Forms.  Model Binding is an extension of the existing data-binding system in ASP.NET Web Forms, and provides a code-focused data-access paradigm.  It takes advantage of a bunch of model binding concepts we first introduced with ASP.NET MVC - and integrates them nicely with the Web Forms server control model.

Some Background on Data-binding today

While Web Forms includes a number of datasource controls (e.g. SqlDataSource, EntityDataSource, LinqDataSource) that allow you to declaratively connect server-side controls directly to datasources, many developers prefer to retain full control over their data-access logic - and write this logic using code.

In previous versions of Web Forms, this could be achieved by setting a control's DataSource property directly, and then calling its DataBind() method from the page's code-behind. While this works for many scenarios, it doesn't work well with richer data controls (like a GridView) that support automatic operations like sorting, paging and editing.

Another option available today is to use the ObjectDataSource control. This control allows for a cleaner separation of UI code from the data-access layer, and does allow data-controls to provide automatic functionality such as paging and sorting.  However, while it works well for selecting data, it is still cumbersome when performing 2-way data-binding, only supports simple properties (with no "deep" binding of complex types) and often requires developers to write a lot of complex code to handle many scenarios (including common ones like validation errors).

Introducing Model Binding

ASP.NET vNext includes new support for "Model Binding" within Web Forms. 

Model Binding aims to simplify working with code-focused data-access logic while still retaining the benefits of a rich, 2-way data-binding framework.  It incorporates the model binding pattern we first introduced with ASP.NET MVC, while also integrating really nicely with the Web Forms server control model.  It makes it easy to perform common CRUD style scenarios with Web Forms - and enables you to do so using any data access technology (EF, Linq to SQL, NHibernate, DataSets, raw ADO.NET, etc).

I'll be doing several posts this week that walkthrough how to take advantage of the new model binding capabilities.  In today's post I'll demonstrate how to use Model Binding to retrieve data - and enable sorting and paging over it within a GridView control.

Retrieving Data using the SelectMethod

Model binding is a code-focused approach to data-binding.  It allows you to write CRUD helper methods within the code-behind file of your page, and then easily wire them up to any server-controls within the page.  The server-controls will then take care of calling the methods at the appropriate time in the page-lifecycle and data-bind the data. 

To see a simple example of this in action, let's use an <asp:gridview> control.  The Gridview below has 4 columns - 3 of them standard BoundFields, and the 4th a TemplateField.  Note how we have set the ModelType property on the GridView to be a Category object - this enables strongly-typed data-binding within the templatefield (e.g. Item.Products.Count instead of using the Eval() method):

<asp:GridView ID="categoriesGrid" runat="server" ModelType="WebApplication1.Model.Category"

    SelectMethod="GetCategories" AutoGenerateColumns="false">

    <Columns>

        <asp:BoundField DataField="CategoryID" HeaderText="ID" />

        <asp:BoundField DataField="CategoryName" HeaderText="Name" />

        <asp:BoundField DataField="Description" HeaderText="Description" />

        <asp:TemplateField HeaderText="# of Products">

            <ItemTemplate><%# Item.Products.Count %></ItemTemplate>

        </asp:TemplateField>

    </Columns>

</asp:GridView>

We've configured the GridView to retrieve its data using Model Binding by setting the GridView's SelectMethod property to point to the GetCategories() method within the page's code-behind file.  This GetCategories() method looks like the following:

public IQueryable<Category> GetCategories() {

    var northwind = new Northwind();

    return northwind.Categories.Include(c => c.Products);

}

Above I'm using EF Code First to execute a LINQ query that returns a list of categories from the Northwind sample database. Note that we do not have to perform the database query within the code-behind - I could have alternatively performed this within a repository or data-access layer and just used the GetCategories() helper method to connect the control to it.

When we run the page, the GridView will call the above method to automatically retrieve the data and render it out to the page like so:

image

Avoiding N+1 Selects

One thing you might have noticed with the code above is that we are using the .Include(c=>c.Products) helper extension on our LINQ query.  This tells EF to modify the query so that in addition to retrieving the Category information, it also includes the related Products (avoiding having to make a separate call to the database to retrieve this information for each row returned).

Sorting and paging support

We could have returned the categories from our GetCategories() method using an IEnumerable<Category> - or a type that implements that interface like List<Category>.  Instead, though, we returned the categories using an IQueryable<Category> interface:

public IQueryable<Category> GetCategories() {

    var northwind = new Northwind();

    return northwind.Categories.Include(c => c.Products);

}

The benefit of returning IQueryable<T> is that it enables deferred execution on the query, and allows a data-bound control to further modify the query before executing it.  This is particularly useful with controls that support paging and sorting.  These controls can automatically add the appropriate sort and page operators onto an IQueryable<T> query before executing it.  This has the benefit of making sorting and paging really easy to implement in your code - as well as making sure that the sort and page operations are done in the database and are super efficient.

To enable sorting and paging with our GridView, we will modify it to have the AllowSorting and AllowPaging properties set to true, and specify a default PageSize of 5.  We will also specify an appropriate SortExpression on two of our columns:

<asp:GridView ID="categoriesGrid" runat="server" AutoGenerateColumns="false"

    AllowSorting="true" AllowPaging="true" PageSize="5"

    ModelType="WebApplication1.Model.Category"

    SelectMethod="GetCategories">

    <Columns>

        <asp:BoundField DataField="CategoryID" HeaderText="ID" SortExpression="CategoryID" />

        <asp:BoundField DataField="CategoryName" HeaderText="Name" SortExpression="CategoryName" />

        <asp:BoundField DataField="Description" HeaderText="Description" />

        <asp:TemplateField HeaderText="# of Products">

            <ItemTemplate><%# Item.Products.Count %></ItemTemplate>

        </asp:TemplateField>

    </Columns>

</asp:GridView>

And now when we run the page, we can page and sort over our data:

image

Only the categories visible in the current sort page will be retrieved from the database - since EF will optimize the query to perform the sort and page operation as part of the database query, and not do the sort/page in the middle-tier.  This makes sorting/paging efficient even over large amounts of data.

Quick Video of Modeling Binding and SelectMethods

Damian Edwards has a great 90 second video that shows off using model binding to implement a GridView scenario that enables sorting and paging.  You can watch the 90 second video here.

Summary

The new Model Binding support in ASP.NET vNext is a nice evolution of the existing Web Forms data-binding system.  It borrows concepts and features from the Model Binding system in ASP.NET MVC (you'll see this more in later posts), and makes working with code-focused data-access paradigms simpler and more flexible.

In futures posts in this series I'll extend on Model Binding and look at how we can easily integrate filtering scenarios into our data selection scenarios, as well as how to handle editing scenarios (including ones using validation).

Hope this helps,

Scott

P.S. In addition to blogging, I use Twitter to-do quick posts and share links. My Twitter handle is: @scottgu

60 Comments

  • Very nice post? Scott! Thank you!

  • Very nice post, Scott! Thank you!

  • It's an improvement, but still makes separation between view and model difficult if not impossible. We usually put all the BO/DA logic in a separate project. The view can't / shouldn't query the database directly. This works for quick and dirty solutions, but not for big projects. The control could talk to the DA layer via an interface / object and let the data layer do the sorting/paging etc...

  • It's an improvement, but still makes separation between view and model difficult if not impossible. We usually put all the BO/DA logic in a separate project. The view can't / shouldn't query the database directly. This works for quick and dirty solutions, but not for big projects. The control could talk to the DA layer via an interface / object and let the data layer do the sorting/paging etc...

  • Why not just kill WebForms and give the resources to the ASP.NET MVC team?

  • I am really looking forward to this feature. I always want to code data binding like this and always get frustrated when it doesn't work that way. This is way more intuitive.

  • Hi Scott

    Great to see new model binding in Web Forms. Sorting and paging operations are also very nice for heavy data driven apps.

    When are you planing to provide the next version of Asp.net? Is it come with new .Net framework 5 or something else. Please reply.

    Thanks.

  • Scott, how does this model binding come into the picture for those of us who is using Object Datasource? Seems like an extension of ODS and we could still use all of our existing business model layer.

    Thanks!
    ..Ben

  • @Peter,

    >>>>>>> It's an improvement, but still makes separation between view and model difficult if not impossible. We usually put all the BO/DA logic in a separate project. The view can't / shouldn't query the database directly. This works for quick and dirty solutions, but not for big projects. The control could talk to the DA layer via an interface / object and let the data layer do the sorting/paging etc...

    You can keep all of your BO/DA logic in a separate project using model binding. I mentioned above that you do not need to put any data logic within your code-behind. The better practice would be to keep this separate and simply using the helper methods in the code-behind as glue code within the view layer that binds to it. This would enable clean view and model separation.

    Hope this helps,

    Scott

  • @Colin,

    >>>>>> Why not just kill WebForms and give the resources to the ASP.NET MVC team?

    Lots of people use Web forms and lots of people use MVC. You'll see us investing heavily in both with vNext. If you are a MVC fan I think you'll find a ton of improvements coming with the upcoming release - it has a huge number of improvements that I'll be blogging about soon.

    Hope this helps,

    Scott

  • @Sumanta,

    >>>>>>> When are you planing to provide the next version of Asp.net? Is it come with new .Net framework 5 or something else. Please reply.

    We'll be sharing more details about the next release at the Build conference that starts next week.

    Stay tuned,

    Scott

  • @BenHayat,

    >>>>>> Scott, how does this model binding come into the picture for those of us who is using Object Datasource? Seems like an extension of ODS and we could still use all of our existing business model layer.

    The ODS continues to work going forward. I think you'll find the Model Binding improvements a cleaner and more flexible approach though. The good news is that you can re-use all of your existing business model layer logic that you can using the ObjectDataSource with it - so if you use ODS today it is pretty easy to start taking advantage of some of the new model binding features.

    Hope this helps,

    Scott

  • Finally, the asp.net support this feature, it can save a lot of time. Thank you for your effort

  • Hi Scott,

    nice post, but isn't this the same with ObjectDataContexts? Does the ModelBinding here gather by the method all records and applies the paging within the memory? We always use for Paging Skip().Take() cause of tables with millions of records for optimized SQL Statements. Will this be implemented in the ModelBinding too?

    Have a nice day.

  • @Colin

    Comment's like yours annoy me, Web Forms was never a problem, the problem has always been, and continues to be, the developers. It's JUST as easy to write rubbish code in MVC as it is in Web Forms. Sooner or later people will begin to blame MS for it's implementation of MVC that is the problem, not developers lack-of-understanding.

    @Scott

    Sometimes I wish examples given promoted some more best practice, otherwise we end up with a community who doesn't look at your example of the functionality of the control, but rather a "how-to" which is copy pasted and results in pain for more seasoned developers in the future.

  • "as well as making sure that the sort and page operations are done in the database and are super efficient."

    How do the sorting & paging parameters get passed to EF,the GetCategories method does not accept any parameters

    - Amit

  • Ho Scott

    I wish you guys could stop using 'include' in your examples because thats Entity Framework only. Its very bad practice because EF is not POCO as it should be (EF Code first is just not good enough).


  • Are there any changes planned on making transition from web forms to mvc easier?
    we (and lots of others) have user controls which would then have to be rewritten making transition harder. If you could somehow have a web forms ascx in a view that would be awesome, although prob impossible due to viewstate etc..

    On examples, any chance of showing better practice (ie northwind context in a different project)? Know this is a quick view, but when comes from you will be taken as best practice by many. At least shouldn't norteind be in a using??

  • Do the controls take full advantage of the IQueryable part, i.e. do they also optimize the projection (the 'Select' part) of the query? In the example, you don't actually need to retrieve the actual product information, you only need the # of products per category.

  • @Colin why not do the opposite of what you say? I find Web Forms to be a better technology than MVC. Also I don't like you :)

  • Hi Scott,

    I don't mean to be rude but the main issue I can see with such a feature is that it's encouraging developpers in the wrong way on application development : No separation of concerns, no n layers... A step forward to spagetti code.

  • Hi Scott,

    Thank you for this informative post. I cannot wait to use these features, I hope there are many more features to come with the next version of ASP.Net. Can we expect new releases of Web Forms in next couple of months? Are these features comes with new Framework version or any SP of Framework 4?

    Thanks again
    Nirav

  • >> You can keep all of your BO/DA logic in a separate project using model binding. I mentioned above that you do not need to put any data logic within your code-behind. The better practice would be to keep this separate and simply using the helper methods in the code-behind as glue code within the view layer that binds to it. This would enable clean view and model separation.

    Please please can we have a tutorial/video to demonstrate this. I totally agree with the points made about querying tables directly. :-)

  • Hi Scott,

    Great Post and nice feature for ASP.NET web form.

    Basing on @Peter's comment, I want to know if GetCategories() method is located in another separate BL project for example CategoryLogic, then how to write SelectMethod property of GridView? like SelectMethod = 'CategoryLogic.GetCategories' ?

    Thanks

  • Hi Scott,

    Nice feature for web forms.

    According to Peter's comments, I want to know if I write GetCategories() into another separate BL project named BLL, and with a class named CategoryLogic, should I write GridView's SelectMethod property like SelectMethod = 'BLL.CategoryLogic.GetCategories' ?

    Thanks

  • I like the idea to combining ODS to GridView.
    And I very much like to see how this thing gonna work in two-way binding mode.
    Current ODS doesn't work as much as I expect when doing Insert or Update things.
    Questions. What exactly the tag returns, a string?
    How can I bind a data from boolean field to Label's Visible property
    or bind HTML color code to Label's ForeColor property?
    Will you release this as an SP2 for VS2010? I want it now.

  • >> You can keep all of your BO/DA logic in a separate project using model binding. I mentioned above that you do not need to put any data logic within your code-behind. The better practice would be to keep this separate and simply using the helper methods in the code-behind as glue code within the view layer that binds to it. This would enable clean view and model separation.

    In the example shown, the main benefits are that the GridView control can alter the sort and paging operators before the EF query is executed? In effect the GridView, through data-binding is generating the query and executing it against the database. It's fair to say the GridView is part of the view. In true separation between view & model, a component of the view shouldn't be able to perform data access.

    I think this improvement is great, but I don't think it's correct to say you can achieve clean separation using this approach. I also think there's a valid argument to say that in many cases, you don't need to achieve it. WebForms is not all things to all men.

  • Thanks for getting back into posting, Scott! I'm excited about these new features in ASP.NET, although less interested in WebForms nowadays. Keep the posts coming!

  • If the new ModelBinding feature use of IQueryables in whatever ORM, is it caching the ObjectContext / Datacontext? For instance, assuming your example is using EF and the northwind object is a ObjectContext, wouldn't attempts at retrieve the query results return an error since the context is out of scope ?

  • Scott, in your sorting and paging example, you are creating a Northwind object, which I'm assuming is either an EF ObjectContext or DbContext which are both IDisposables. Therefore, shouldn't you be using a using statement to dispose of the object properly and free unmanaged resources held by it (i.e. it's network connection)? If you did, wouldn't this cause an exception to happen when the sorting and paging is applied because the ObjectContext has already been disposed at that point? If you are using Code Analysis you will receive warnings about not disposing the disposable.

  • Another thing I'm wondering is, will you be able to use Razor with ASP.NET Web Forms in the future?

  • I submitted a post asking about shouldn't you be using a using statement with the Northwind object. While my later two posts went through, that one didn't, so, I'm posting again. Northwind is an IDisposable. If you are using Code Analysis, you will receive a warning that you are not disposing of it properly. If you use a using statement, will that cause the sorting and paging to break (since by the time the sorting and paging are applied, the ObjectContext/DbContext has already been disposed)?

  • I'm wondering if this will cause more confusion while just providing another way to do the same thing? If the MVC pattern continues to creep into webforms, then the hybrid apps that will be created may be more difficult to maintain as different approaches can be found in the same project. If you want to allow people to use mvc in a webforms context then perhaps have the .aspx.view aspx.control and aspx.model get created when creating a new webform. Enforce separation of concerns for unit testing and mvc purity purposes by only allowing each piece to contain what it should. Come up with new controls that follow the pattern as well, but don't tie those controls to the framework, but release as a toolkit. The beauty of webforms is the simplicity and speed that apps can be built. Adding more layers to fit a pattern, takes the technology away from what was a fundamental reason for using the technology. ODSes and tableadapters are under appreciated tools in the webforms arsenal. Building two tier apps has been fun.

  • @Andrew Remember that the purpose of separation between view and data access layer is to provide structure to code and make it more maintainable i.e. it's easier to fix an error with a select statement in one location the data access layer instead of multiple locations the view. So in terms of the goal you are still keeping to the structure despite what happens behind the scenes. Also by not taking advantage of the built in paging and writing your own code for paging in the data access layer, you'll be needing to do that in multiple places for different queries breaking the goal being more maintainable.

    Scott, can't we just use LinqDataSource with the selecting event and set e.Result in the code behind so that we can still use deep binding, while keeping the implementation of GetCategories in the data access layer? Still what you're proposing is still nice in saving me from having another control on the page. Would be cool if it could infer the model type from the declared return type in the method in the code behind for strongly typed data binding.

  • Hi Scott, I've missed your regular insights now you're in 'cloud territory'! Good to see you're still around somewhat :) Come back!!!

  • ModelType and strong-type data binding is good. But SelectMethod is somehow not necessary.
    You should just fix the way DataSource work. Give away a more fine-grained events and arguments
    that let developers take more control to filtering/sorting/paging operations (grouping would be nice too).
    I think the reason of this design might be related with the 2-way binding operation and validation.
    But still want to see improvement in DataSource base rather than hooking it tightly to GridView. It's too magic.

  • Forms Authentication - Any chance of getting the static wrapper to allow UserData to be set in the ticket.

  • @Jeff This is how you would write the GridView SelectMethod:
    public IQueryable GridView_SelectMethod() { return BLL.CategoryLogic.GetCategories(); }

  • Instead of the paging and sorting happening magically, can you pass parameters to GetCategories method optionally? The reason is I am using webformsmvp where presenter is passed the parameters for paging and sorting and only in memory collections are returned. Hope its flexible enough where it gives you control in situations where your service layer takes startrow, maxrows,sortcolumn

  • I really like the strongly typed binding and the controls modifying the query to do sorting and paging.

    Had a thought - will there be nested templating in list views in vNext? It would be nice to be able to have markup something like:









  • Is there any hope for new Dynamic Data? I know there is LightSwitch, but that is closer to Access than to DD.
    DD was a good start, with this new improvments it would be a perfect admin tool. Basicly an instant portal admin UI.

    ty.

  • this was required us a lot of code in previous version. finally we got this feature :)

  • Whereabouts of ASP.NET in translation MVC3 to AJAX memory Web transfer generation on rise, or else vNext series will develop into the Private Cloud computing Windows VS2008 R2 series in vNext edition arrival?

  • Its really very good one Scott!! Thanks.

  • it like more user friendly feature in source design mode.

  • It would be great if the SelectMethod can be bound to a method on the model i.e. the object you are binding the control.

  • good and nice info

    thank you very much for the good post

  • why is this post in Arabic
    http://weblogs.asp.net/scottgupersian/archive/2011/09/10/html-editor-smart-tasks-and-event-handler-generation-asp-net-vnext-series.aspx

  • Many Thanks scott i am looking for this ....

  • Isn't anybody worried about inefficient queries due a Include load just to count, or multiple database calls within one binding?

  • Awesome!!! Very Excited for ASP.NET vNext!

  • When will we be able to download asp.net vnext? Is the next release of Visual Studio going to be called vNext?

  • Nice article and features. I'm glad to see WebForms getting some significant improvements.

    This sentence stuck out: "Only the categories visible in the current sort page will be retrieved from the database - since EF will optimize the query to perform the sort and page operation as part of the database query, and not do the sort/page in the middle-tier. This makes sorting/paging efficient even over large amounts of data."

    I don't recall that type of functionality being in MVC or WebPages, is it? It sounds very nice!

    People seem to be getting picky. What we need is 3 scottgus. 1 to write this article, 1 to write the "recommended way to do it" article and then 1 to just write all our code for us so we don't need to :)

  • Hello Scott,
    Any support for custom paging and sorting at the level of data bound controls ?

  • Very nice future. Microsoft is doing a great job. ASP.NET is becoming better and better every day.

  • its very nice~! ASP.NET will be win PHP :D
    Vietnam visa on arrival
    Vietnamese cooking

  • Very useful feature. Nice!

  • Scott, I've got to applaud Microsoft on the last few years of knowing what us Developers need. Between Silverlight, MVC/MVVC, XAML (briding the gap between Windows/Web/Mobile), Linq and now improvements to design-time binding with Intellisense on our data in the mark-up... amazing.

    Either other people are all begging for the same great stuff or you guys are reading minds, either way Fantastic! Keep this up and the LAMP stack is going to have to leave RAD development altogether. :P (Despite my respect Linux and all their associated products. Don't flame me fanboys!)

  • How about supporting Nested Object Property, for e.g., Category.Product.Name or even Category.Products[i].Name

  • Really fantastic post. I hope the best the WebForms power with New Model Binding

Comments have been disabled for this content.