MVC 3 Beta – First Impressions
I’m sure most of you have read ScottGu’s announcement about MVC 3 going Beta. I was able to play with the bits and here are my thoughts about this release.
One of the first things I noticed was that the Razor view engine (which was initially named as CshtmlViewEngine) has been renamed as RazorViewEngine. This is a good thing now that Razor supports not just the C#, but also VB.net. Plus RazorViewEngine makes lot more sense than CshtmlViewEngine (IMHO, even in the earlier version when only CS was supported).
When you create an MVC3 project, you’re shown this window.
Selecting Internet Application gives you a project/folder/file structure that we’re already familiar with. The ‘Empty’ template has some of the following features:
- No controllers
- No views
- No master page
- A very basic version of Site.css
The other thing to notice here is that now Razor is the default view engine. Seems like MS wants to encourage developers to use Razor (not a bad thing). But here’s where this idea breaks. If you have a view defined in both WebForm and in Razor (say Index.aspx and Index.cshtml), MVC selects the aspx version. I think they should change the default behavior so that RazorViewEngine is registered before the WebFormViewEngine. In the sample application, you’ll see there is a Component.ascx and and Component.cshtml. If you just run the application (home/index), it chooses the .ascx version.
You can, however change this behavior by adding the below code to the Application_Start method (Global.asax) .
1: ViewEngines.Engines.Clear();
2: ViewEngines.Engines.Add(new RazorViewEngine());
3: ViewEngines.Engines.Add(new WebFormViewEngine());
You can now decide the order of the properties when you call Editor (or EditorFor or EditorForModel) on a model.
I have an Employee class:
1: public class Employee
2: {
3: public string FirstName { get; set; }
4: public string LastName { get; set; }
5: public int EmployeeId { get; set; }
6: }
Now in my controller, I initialize an instance of this class and pass it to the view.
1: public ActionResult ShowEmployee()
2: {
3: Employee employee = new Employee();
4: employee.EmployeeId = 12;
5: employee.FirstName = "Jack";
6: employee.LastName = "Bauer";
7: return View(employee);
8: }
And my view just says:
1: <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Mvc3Beta.Models.Employee>" %>
2:
3: <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
4: Employee Details
5: </asp:Content>
6:
7: <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
8: <%: Html.EditorForModel(Model) %>
9: </asp:Content>
The order in which the class declares the properties is the order in which they get rendered.
But now I can set the ordering on the properties of my class.
1: using System.ComponentModel.DataAnnotations;
2:
3: namespace Mvc3Beta.Models
4: {
5: public class Employee
6: {
7: [Display(Order = 2)]
8: public string FirstName { get; set; }
9: [Display(Order = 1)]
10: public string LastName { get; set; }
11: [Display(Order = 0)]
12: public int EmployeeId { get; set; }
13: }
14: }
Now my output looks all well ordered.
MVC 3 adds new helper methods for creating grids and charts (on the fly).
To create a grid, I had to use the following code:
1: public ActionResult ShowGrid()
2: {
3: List<Component> components = new List<Component>
4: {
5: new Component
6: {
7: Name = "Light Bulb",
8: ManufacturerCompany = "Philips"
9: },
10: new Component
11: {
12: Name = "Battery",
13: ManufacturerCompany = "Everready"
14: },
15: new Component
16: {
17: Name = "Jacket",
18: ManufacturerCompany = "North Shore"
19: }
20: };
21: return View(components);
22: }
1: <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<Mvc3Beta.Models.Component>>" %>
2:
3: <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
4: Show Grid
5: </asp:Content>
6: <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
7: <% var grid = new WebGrid(Model, defaultSort: “Name”); %>
8: <%:9: grid.GetHtml(columns: grid.Columns(
10: grid.Column("Name"),11: grid.Column("ManufacturerCompany", "Manufacturer Company")12: )
13: ) %>
14: </asp:Content>
The output gets rendered as:
Cool! Now when you hover over the header tags, you’ll see something like:
http://localhost:46589/home/showgrid?sort=Name&sortdir=DESC
A thing to note here is that, in the html above, I’ve mentioned the defaultSort attribute to the Name field. If you see the link above the sortdir says ‘DESC’. So MVC intelligently detects the current sorting mechanism of a column and sets the next sorting direction. And yes, if you click on it, it does do the sorting for you. All this is being given to the developer just out-of-the-box. Very neat MVC team!
Coming to rendering a chart on the fly, here’s the code I have:
1: <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<Mvc3Beta.Models.EmployeeSale>>" %>
2:
3: asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
4: Show Chart
5: /asp:Content>
6:
7: asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
8: <%9: new Chart(350, 200)10: .AddSeries("Sales", yValues: new[] {"45", "34", "67"})11: .AddLegend(title: "Sales Predictions")12: .SaveXml("~/Images/Chart1.xml")13: .Save("~/Images/Chart1.jpeg");14: %>
15: <img src="../Images/Chart1.jpeg" alt="chart" />
16: /asp:Content>
So, at run-time, I’m creating a chart with some height and width, adding some data to be plotted on the chart and then saving it as an image. I just have to point to the path and render it as an image. You can also see what the xml looks like as shown above.
I cannot think of a real-world scenario where this example will be useful as I’ve hard-coded the input data. What if I have dynamic data to be plotted on a chart?
1: // model
2: public class EmployeeSale
3: {
4: public int EmployeeId { get; set; }
5: public int SoldUnits { get; set; }
6: }
7: // action method in controller
8: public ActionResult ShowChart()
9: {
10: List<EmployeeSale> employeeSales = new List<EmployeeSale>
11: {
12: new EmployeeSale
13: {
14: EmployeeId = 1,
15: SoldUnits = 100,
16: },
17: new EmployeeSale
18: {
19: EmployeeId = 2,
20: SoldUnits = 40,
21: },
22: new EmployeeSale
23: {
24: EmployeeId = 3,
25: SoldUnits = 293,
26: },
27: new EmployeeSale
28: {
29: EmployeeId = 4,
30: SoldUnits = 178,
31: }
32: };
33: return View(employeeSales);
34: }
1: <%1:
2: new Chart(350, 200)3: .DataBindTable(Model, "EmployeeId")4: .AddTitle("Units sold by employees")5: .SetXAxis("Employee")6: .SetYAxis("Units Sold")7: .Save("~/Images/Chart2.png"); %>
8: <img src="../Images/Chart2.png" alt="chart" />
This renders an image as follows:
These are some of my impressions with regards to MVC3. I’ll post more of my findings later. Here is a complete listing of the release notes of MVC 3. You can download the sample code here.
Verdict: MVC continues to add more features to enable developers to build web application quicker and cleaner.