In-Depth
ASP.NET 4.5 Test-Drive
In the upcoming versions of Microsoft Web development tools, ASP.NET makes data binding more flexible while ASP.NET MVC makes creating AJAX applications and building mobile applications easier, among other goodies in both environments.
Before the end of the year, Web developers will have a new version of Visual Studio (11), ASP.NET (4.5) and ASP.NET MVC (4). Here's a look at what's new in ASP.NET, followed by new features in ASP.NET MVC. There are enough new goodies that this article will just concentrate on what's new in the presentation layer in both toolsets.
There won't be room, for instance, for any discussion of the new features available for developers who are creating their own HttpHandlers. (Note that these are beta products, and could change before official release.)
In ASP.NET 4.5, one of the first things you'll notice if you use the Web Application template project is that the content for the default.aspx page is now completely useless. I've never been a big fan of the pages added in the default Web Application template, because most developers (I suspect) will need to replace them with their own pages almost immediately. However, the new default.aspx page (see Figure 1) doesn't even pretend to be supporting an application. Instead, the page now offers advice to the developer as to what to do next -- no detail on how to do it, mind you, just good advice (such as "Configure membership"). To be fair, the default login and change password pages are probably useful (you might be able to keep them), and the default master page is relatively innocuous.
[Click on image for larger view.] |
Figure 1. The new ASP.NET default.aspx page features a new look and a bunch of content you'll want to delete immediately. |
HTML- and Client-Side-Related Changes
If you're looking for new ASP.NET controls in the ASP.NET Web Forms toolbox once you start building pages, you're going to be disappointed. The changes in ASP.NET 4.5 are all about what the existing controls -- especially the DataViews -- will do, rather than adding new controls. You also won't see any new controls in the HTML section of the toolbox, but that doesn't mean they aren't there.
Visual Studio 11 IntelliSense supports the new HTML5 tags out of the box. The new default.aspx page includes section tags, for instance, and IntelliSense shows that the related header, footer and article tags are also known to Visual Studio. These new tags mean you can stop using <span> and <div> tags with Cascading Style Sheet (CSS) classes to structure related elements on your page, and use tags dedicated to that task.
If you use an HTML5 tag with an attribute that accepts URLs, you can use the ASP.NET "~" operator to mark the "current site." And if you decide to use some of the new HTML5 input tags, the ASP.NET Validator controls and the UpdatePanel will work with them.
On the older HTML tags, the new HTML5 attributes (including the custom data attributes and the Accessible Rich Internet Applications, or ARIA, accessibility attributes, among others) are also supported in IntelliSense. Because the latest version of jQuery supports the data attributes (through the data function), this gives you another way to organize elements in addition to a tool for managing data that's related to an element but that you don't want to display.
More importantly for Web Forms developers, the TextBox TextMode property now supports the new HTML5 options such as Color, DateTime, Number and so on. The FileUpload control supports uploading multiple files if you set its AllowMultiple property to True.
To retrieve all of the uploaded files, you use the control's PostedFiles collection, like so:
For Each file In Me.FileUpload1.PostedFiles
file.SaveAs(Server.MapPath(file.FileName))
Next
For these items, remember that it's up to the browser as to whether those tags and attributes will be recognized.
The ASP.NET team has taken unobtrusive JavaScript to heart for client-side validation by moving virtually all the JavaScript validation out of the page. You don't have to do anything to make this happen: The option is set through the Validation Settings: UnobtrusiveValidationMode added in the appSettings section of the web.config by default.
Another improvement in client-side-related validation: If a user in previous versions of ASP.NET entered anything that looked suspiciously like HTML or scripting into a data entry control (and ASP.NET was very suspicious), the page blew up. By default, ASP.NET 4.5 sets the new requestValidationMode attribute on the httpRuntime attribute to "4.5," which positions you to stop the page from blowing up if the user enters suspicious content. You'll need to set the ValidateRequestMode property to Disabled on the controls or pages on which you want to permit the user to enter HTML (the default for the property is "Inherit").
Simplifying Binding
A set of changes to the DataView controls (for instance, GridView, DataList and so on) means that you can bypass the various DataSource controls if you want to write your own retrieval and update code -- a set of technologies that the ASP.NET teams have bundled under the name "Model Binding." If you're moving to Model-View-Controller (MVC)-style processing and test-driven development (TDD) in your ASP.NET applications, you can significantly reduce the code in your codebehind files to support both of those goals by leveraging Model Binding.
If you've been working with DataView controls, until now you've been using data binding expressions to attach your control properties to data. You might have been letting the DataBindings dialog box or the DataView control generate those expressions for you. But if you've been writing the expressions yourself, you've been using either Bind (for two-way data binding) or Eval (for one-way data binding) in Source View, like this:
<asp:TextBox ID="firstName" runat="server"
Text='<%# Bind("CompanyID") %>' />
What you haven't been getting is any IntelliSense support in those Bind or Eval expressions. That left you open to "spelling counts" errors with the field name that you typed inside those double quotes.
ASP.NET 4.5 adds a new property called ItemType to DataView controls, which you can set to the name of some class in your application. Once you do that, the syntax for data binding not only gets simpler (you don't need to reference the Bind or Eval functions anymore), but you also get IntelliSense support for the data item to which you're binding.
What replaces the Bind and Eval functions are BindItem (for two-way binding in a control's property) and Item (for one-way binding anywhere you want). You won't be able to use Item and BindItem unless you set ItemType to a valid class name; but once you do, both Item and BindItem will show all of the ItemType class properties in their IntelliSense lists, as Figure 2 shows.
Your binding expressions must still be enclosed in the <%# %> delimiter.
[Click on image for larger view.] |
Figure 2. Using Bind and Item along with the ItemType on a DataView control gives you IntelliSense support for binding entity properties. |
However, if you're expecting your property to return some of the "reserved" HTML characters (for example, "<" or "&" or ">") and you don't want those characters to be treated as HTML, you should add a colon to the delimiter to use <%#: %>. Because it's unusual to return HTML from your object's properties, <%#: %> is actually your safest choice.
The example in Listing 1 binds the GridView to a Customer object using the ItemType attribute. It then binds the GridView's columns to the Customer object's CustomerId property (read-only in all templates) and CompanyName property (updateable in its ItemTemplate). I've used the HTML encoding throughout (after all, the CompanyName might include an ampersand).
Unfortunately, there doesn't seem to be a way to cause the DataView's SmartTag to generate tags using BindItem and Item. You'll need to count on the Visual Studio IntelliSense support to guide you through generating all the tags required to configure a DataView.
Retrieving and Updating Data
To bypass using DataSources to retrieve and update data, you can use the new SelectMethod and UpdateMethod properties on the DataView. In the SelectMethod property, you specify a method in your page that returns a collection of the objects specified in your ItemType. A typical method would look like this:
Public Function GetCustomers() As List(Of Customer)
Dim custs As List(Of Customer)
Using nw As New NorthwindEntities()
custs = (From cust In nw.Customers
Select cust).ToList
End Using Return custs End Function
The method specified in the UpdateMethod property will be passed an instance of the object as each row is updated. Typical code for that method would look like the example in Listing 2. I've used Entity Framework objects here so I can use their EntityState property to determine if the object was updated, deleted or inserted.
A typical GridView that ties all of these components together would look like this:
<asp:GridView ID="GridView1"
runat="server" AutoGenerateColumns="False"
DataKeyNames="CustomerID"
ItemType="PHVSite.Customer"
SelectMethod="GetCustomers"
UpdateMethod="UpdateCustomer">
You can also use the SelectMethod with display-only controls like the DropDownList. With the DropDownList, you'll also need to specify which properties on the object will be used for the ListItem's Text and Value properties. This example ties a DropDownList to my previous method and specifies that the City property is to be displayed in the list:
<asp:DropDownList ID="DropDownList1" runat="server"
SelectMethod="GetCustomers" DataTextField="City">
</asp:DropDownList>
While you can use the ItemType with the DropDownList, it doesn't get you much: You can't use Item to bind properties on the object to the control. You'll just have to be careful when you type in the property name.
One last note: You don't need to put all of the code shown here in your .cs or .vb files. The methods in your page referenced by the SelectMethod and UpdateMethod methods can just call a method on some MVC class, passing values from controls on the page.
Filtering Data
With DataSources, you can automatically filter your data by tying the DataSource to a control on the page or some other data in the environment just by declaring where the filter values were to come from. You can do that declaratively with your SelectMethod property, too.
If, for instance, you don't like the syntax for accessing cookie values, you can retrieve a named value from the cookies returned to the server and have it passed as a parameter to your SelectMethod by decorating a parameter with the Cookie attribute. When you use the Cookie attribute, you must pass it the name of the cookie you want to retrieve the value from.
The code in Listing 3 ties the method's City parameter to a value from a cookie called CustCity.
On the other hand, if you want to retrieve a value from a DropDownList on your page, your parameter will need to be decorated with the Control attribute. The Control attribute needs to be passed the name of the control:
Public Function GetCustomers(
<System.Web.ModelBinding.Control("DropDownList1")> City As String)
As List(Of Customer)
ASP.NET will attempt to do any conversions required to convert the incoming data to your parameter's data type. However, if the incoming data doesn't have an item with a matching name, your method's parameter will be passed Nothing or null. It's a good idea to have your parameter accept a String or some other nullable value (for example, integer? rather than integer).
ASP.NET MVC 4 and Single Page Applications
One big change included in ASP.NET MVC 4 -- and it's a big change for the Microsoft .NET Framework as a whole -- is the new ASP.NET Web API for implementing services. I discuss this in my Practical .NET column, along with the upcoming changes in Windows Communication Foundation (WCF) 4.5 (see "Changes Large and Small: WCF 4.5 and the ASP.NET Web API," ). In this part of the article, I'm going to focus on changes that more directly affect the ASP.NET MVC 4 presentation layer -- which means, as fond as I am of code generation, I won't be looking at its new support for creating code-generation recipes. As you'll see, however, talking about the presentation layer still forces a discussion of the many server-side changes.
The first things you'll notice when creating an ASP.NET MVC 4 application are the three new project templates: Single Page Application, Web API Application and Mobile Application. The templates have much in common. The Login View for all of them, for instance, now uses a jQuery UI to display a model dialog that allows users to register. The default Index View displays general helpful advice to the developer, similar to the default.aspx page in ASP.NET. You also get the same support for HTML5 that Visual Studio provides to ASP.NET.
The Single Page Application, however, is special: it's both a template for a project and a type of Controller that you add to other projects. As a project template, the Single Page Application includes all the script libraries needed to support the paradigm that Web applications are moving toward: the user goes to the server to get a page, stays on that page while having a conversation with a set of services, then goes back to the server to move to the next page. As a project template, the name isn't perfect: a typical application will probably consist of several "single pages" that implement this paradigm.
To support all the JavaScript libraries required, the project template includes a new layout file (_SpaLayout.vbhtml) that references the scripts your Views need. Included in the script libraries that come with the project template is the Knockout library (see John Papa's MSDN Magazine Client Insight column, "Getting Started with Knockout," at bit.ly/xYfE79). Knockout supports implementing the Model-View-ViewModel (MVVM) in the client in order to separate JavaScript logic from presentation logic.
The Microsoft Upshot library (formerly RIA/JS) is also included to provide a single API for integrating both Web and local storage. To support Upshot, the HTMLHelper class has a new method called MetaData that returns the information about the class used with your View that Upshot needs. The method shoves a "JSON-like" description of your class into the page ("JSON-like" because the description includes type information that JSON doesn't provide).
Also provided by default is the History script library, which lets you associate a state in your UI with a URL. This lets you deliver an application that doesn't post back to the server but that the user can still navigate through using the back and forward buttons.
On the server, ASP.NET MVC 4 introduces a new controller type: DataController. The DataController inherits from the ApiController, which is introduced to support the ASP.NET Web API services. The DataController builds on the Web Service capabilities of the ApiController to provide support for business-level infrastructure: transactions, validation and integration with a data-access layer, among other features.
When you add a new controller in Visual Studio 11, the scaffolding options allow you to pick from several different kinds of controllers, including a Single Page Application. In addition, you can also specify a data context class to be used with your controller.
The data context class is intended to provide a single control point for data access; it can be, for instance, an Entity Framework model. If you pick the "new data context" option, Visual Studio creates a class that inherits from the DbContext object -- the starting point for creating a Code First Entity Framework model. And, by the way, adding a Single Page Application controller also adds all of the Views to support basic Create, Read, Update and Delete (CRUD) activity, plus a JavaScript file containing a Knockout MVVM model to which that JavaScript code in the Views binds.
Creating Mobile Applications
For mobile applications, the most obvious change to the basic ASP.NET MVC project structure is the inclusion of the jQuery Mobile 1.0 libraries. The Knockout library is also included, though Upshot and History aren't.
Less obvious are the changes to the default CSS file, which force buttons to the screen width, and the viewport meta tag in the default layout file. Some of Microsoft's documentation suggests that the default CSS file will, eventually, also set CSS media rules for small screens, but that isn't present in the beta. While Visual Studio will work with any number of emulators, these changes mean you can get a good idea of what your mobile Web pages will look like just by resizing your browser window (see Figure 3).
[Click on image for larger view.] |
Figure 3. Resizing your browser window gives an impression of a Web page in a mobile device without using an emulator. |
ASP.NET MVC 4 makes it easier to generate different Views (or partial Views) for mobile devices. If you include the word Mobile in a View name, it will automatically be selected if a mobile device requests your View in place of another View with the same name that doesn't contain the word "Mobile." So, if you generate two Views with the names Customer.vbhtml and Custom-er.Mobile.vbhtml, the Customer.vbhtml View is automatically delivered to desktop browsers while the Customer.Mobile.vbhtml is delivered to mobile devices. The same convention applies to layout and partial Views: include Mobile in the layout or View's name and it will be selected automatically if the client is a mobile device.
This isn't bad, but isn't necessarily optimal, either -- it's not clear that, for instance, a tablet needs to or should have the same View as a smartphone, even though both are mobile devices. To support different Views for different mobile devices, you can create new display modes that are tied to specific devices.
You must first define the conditions when the display mode applies in your global.asax file's Application_Start event. After adding an Imports or using statement for System.Web.WebPages, code like this adds a new DefaultDisplayMode (called iTab) with a ContextCondition that checks to see if the user agent's name contains the stringiTab:
DisplayModeProvider.Instance.Modes.Insert(0,
New DefaultDisplayMode("iTab") _
With {
.ContextCondition = (Function(context) _
context.GetOverriddenUserAgent().IndexOf("iTab",
StringComparison.OrdinalIgnoreCase) >= 0)
})
When the lambda expression in the ContextCondition returns true, ASP.NET MVC 4 will automatically select Views, layouts and partial Views that contain the word iPad in their names.
You can also implement View switching by overriding the user agent information provided by the client, and treating the client as a specific browser. This allows you to provide the user with the option of treating his device as if it were, for instance, a desktop browser instead of a smartphone or tablet.
Installing the jQuery.Mobile.MVC package provides the infrastructure to implement this feature, including a partial View, a layout and a controller. You'll need to add the necessary display modes and incorporate the partial View into your Views.
To Upgrade or Not to Upgrade?
There's a lot to like in both upgrades. I have some items on my wish list that still aren't fulfilled (a site map editor would be nice, for instance). I also wish that the ASP.NET MVC templates didn't send just the structure of the HTML page and then immediately issue an AJAX request for the data. Other than potentially reducing some of the HTML sent to the client when there's a ton of repeated data, there's no good reason why the initial page couldn't satisfy the user's request by including the data. After that initial display, service requests would take care of updates to the UI -- but that's why we have programmers, isn't it?
Overall, though, ASP.NET MVC makes life easier for mobile developers (well, if mobile development is ever easy), and both platforms enhance their support for integrating with data stores. While there might be nothing groundbreaking here, both versions are worth upgrading to. If you're building mobile applications, you need ASP.NET MVC 4; if you want to get support for HTML5, move to the new client-side paradigm or integrate with an Object Relation Mapping tool, both upgrades will make you more productive.