We have just released the final version of ASP.NET MVC 3. Read the official MVC 3 release information or download MVC 3.
To help you upgrade your MVC 2 projects to MVC 3 we have released an upgrade tool. You can download it here: http://aspnet.codeplex.com/releases/view/59008. (This is an update of the tool that Eilon Lipton previously previewed on his blog and now we are giving it a more permanent home on our CodePlex site).
April 11 Update: We made a small update to the tool that allows you to skip the backup step. You might want to consider skipping the backup step if you use source control or if your solution is very big.
January 14 Update: We have updated the file on codeplex to fix an issue with converting solutions that had Web Sites or other solution items. If you are having problems please make sure you download the tool again from the codeplex site.
The upgrade tool only supports Visual Studio 2010 projects targeting .NET 4. Upgrading both MVC 2 and MVC 3 Beta (or RC) projects is supported.
The tool does not support Visual Studio 2008 solutions, MVC 1 projects, or projects targeting .NET 3.5. Those projects will first have to be upgraded using Visual Studio 2010 and/or retargeted for .NET 4:
The usage of the tool is quite simple:
During the conversion process the tool will:
This is an unsupported utility and there is a possibility that it might not work correctly for your solution. Specifically, the tool has the following limitations:
However, if you run into problems let me know and I will see if we can get them addressed.
In a recent post I introduced a technique for dealing with optional Razor sections and default content. In this post I will expand upon that technique and describe a way of working with sections across nested layout hierarchies. If you are not familiar with sections, layout pages, or my technique then go ahead and read that post to catch up.
One aspect of the relationship between layout pages and sections in Razor that a fair number of people might find surprising is that a section defined in a content page can only be used in its immediate layout. There is implicit scoping going on that prevents certain use cases. Take the following example:
<!DOCTYPE html> <html> <body> @RenderSection("SubSection") @RenderBody() </body> </html>
@{ Layout = "~/Views/_MasterLayout.cshtml"; } <div> @section SubSection { <h1>Title</h1> } @RenderBody() @RenderSection("ContentSection") </div>
@{ Layout = "~/Views/_SubLayout.cshtml"; } <div> <p>Main content</p> @section ContentSection { <div>Footer</div> } </div>
In the above example you can certainly call RenderSection("SubSection") in _MasterLayout.cshtml, as well as call RenderSection("ContentSection") in _SubLayout.cshtml. However, it is impossible to call RenderSection("ContentSection") from _MasterLayout.cshtml because the file rendering the section and the file defining the section are not directly related. Essentially sections are limited to the Content-Layout scope and are not accessible to other layout pages outside of that scope.
RenderSection("SubSection")
RenderSection("ContentSection")
You can work around this by essentially redefining the section in the intermediate layout.
@{ Layout = "~/Views/_MasterLayout.cshtml"; } <div> @section SubSection { <h1>Title</h1> } @RenderBody() @section ContentSection { @RenderSection("ContentSection", required: false) } </div>
Now you are able to reference “ContentSection” from _MasterLayout.cshtml. However you should be aware that you are not overriding “ContentSection" in the same sense as overriding methods in a child class. You are actually defining a new section named “ContentSection” in the SubLayout-MasterLayout scope that renders the section named “ContentSection” from the Content-SubLayout scope. The fact that the names match is incidental. The names certainly do not have to match.
Things get even more complicated when you want to use the IsSectionDefined method to conditionally provide default content for optional sections. Because it’s necessary to propagate “ContentSection” by redefining the section in _SubLayout.cshtml you can no longer depend on IsSectionDefined returning the expected result.
IsSectionDefined
Fortunately not everything is lost. What you want to do is to conditionally redefine a section. Building on the RenderSection helper method from my previous post I created the RedefineSection more helper methods to aid in this scenario:
RedefineSection
public static class SectionExtensions { private static readonly object _o = new object(); public static HelperResult RenderSection(this WebPageBase page, string sectionName, Func<object, HelperResult> defaultContent) { if (page.IsSectionDefined(sectionName)) { return page.RenderSection(sectionName); } else { return defaultContent(_o); } } public static HelperResult RedefineSection(this WebPageBase page, string sectionName) { return RedefineSection(page, sectionName, defaultContent: null); } public static HelperResult RedefineSection(this WebPageBase page, string sectionName, Func<object, HelperResult> defaultContent) { if (page.IsSectionDefined(sectionName)) { page.DefineSection(sectionName, () => page.Write(page.RenderSection(sectionName))); } else if (defaultContent != null) { page.DefineSection(sectionName, () => page.Write(defaultContent(_o))); } return new HelperResult(_ => { }); } }
The RedefineSection method conditionally redefines a section (that is it redefines in only if a section was already defined in a content page). The second overload also allows you to provide a default content template that will be used if the content page did not define the section. Using this code you can write the following pages:
<!DOCTYPE html> <html> <body> @RenderSection("TitleSection", required: false) @RenderBody() </body> </html>
@{ Layout = "~/Views/_MasterLayout.cshtml"; } <div> @this.RedefineSection("TitleSection", @<h1>Default SubLayout title</h1>) @RenderBody() </div>
@{ Layout = "~/Views/_SubLayout.cshtml"; } @section TitleContent { <h1>Title</h1> } <p>Main content</p>
In the above example Content.cshtml defines the “TitleContent” section. _SubLayout.cshtml redefines that section but also provides some default markup in case the content page does not have the “TitleContent” section defined. Finally, _MasterLayout.cshtml consumes the section indicating that it is optional – this means that the entire site will still work even if the content page does not define the section and the intermediate layout does not provide a default value.
Hope you find the above technique useful in your complex layout pages. Please let me know if you encounter any issues and whether these methods are valuable enough that they should be added to the framework for the next version.
Solution quick links:
The new ASP.NET page framework built on Razor (which is available in MVC 3) provides a facility for content pages to contribute named fragments of markup to their layout pages which the layout page can then render in an arbitrary location using the RenderSection method.
RenderSection
For example, the following content page declares an "ExtraContent" section:
@{ Layout = "~/Views/Shared/_Layout.cshtml"; } @section ExtraContent { <div>Some extra content</div> } <div>The main content</div>
And the following layout page renders it:
<!DOCTYPE html> <html> <head></head> <body> @RenderBody() @RenderSection("ExtraContent") @RenderSection("OptionalContent", required: false) </body> </html>
You can even declare that a section is not required like the “OptionalContent” section in the example above.
But what if you want to have some default content for your optional sections?
The IsSectionDefined method returns true if a child content page defined a section. You can use that to decide whether to render a section or some other content:
<!DOCTYPE html> <html> <body> @RenderBody() @if (IsSectionDefined("OptionalContent")) { @RenderSection("OptionalContent") } else { <div>Default content</div> } </body> </html>
Just remember that you need to use the @RenderSection() syntax (you need the @ character) so that the contents of the section is actually printed to the output. Without that character you will get an exception with the following message:
@RenderSection()
The following sections have been defined but have not been rendered for the layout page "~/Views/Shared/_Layout.cshtml": "OptionalContent"
Razor provides a way to pass inline markup templates into function calls. This is a powerful mechanism that allows you to combine custom markup fragments with general purpose display logic. In order to make the following example work you will need to drop the following code into your project:
using System.Web.WebPages; using System; public static class SectionExtensions { private static readonly object _o = new object(); public static HelperResult RenderSection(this WebPageBase page, string sectionName, Func<object, HelperResult> defaultContent) { if (page.IsSectionDefined(sectionName)) { return page.RenderSection(sectionName); } else { return defaultContent(_o); } } }
This code essentially wraps the previous example in a reusable extension method. All you need now is to provide the default content markup. With it you can write views like the following:
<!DOCTYPE html> <html> <body> @RenderBody() @this.RenderSection("OptionalContent", @<div>Default content</div>) </body> </html>
For the second parameter you need to use the @ character to trigger the Razor parser to go into markup mode. Once in markup mode you can do anything that you do in the main body of the page.
Just remember that since this is an extension method you need to call it off the this object. Otherwise the C# compiler will not be able to locate it and you will get a compilation error.
this
If you like this technique read the follow up: Razor, Nested Layouts and Redefined Sections
Database access is usually the largest performance bottleneck of web applications. But once you’ve optimized and cached your database queries as much as possible here are 3 quick tips that might help you squeeze out a few more requests out of your ASP.NET MVC applications and web servers.
Depending on which features you are using they might not always apply to your application and their benefit will not be that significant (a few % points improvement at most - sorry I don't have more specific numbers as I'm writing this from memory). I can't guarantee how much improvement you will see as it depends so much on what your application does. But I hope this will provide some leads for you to investigate. Just remember to always measure for your specific scenario.
When: Your application is using built-in display/editor templates (via the Html.EditorFor or Html.DisplayFor methods) and you are using only one type of view engine.
Html.EditorFor
Html.DisplayFor
Why: ASP.NET MVC is generally very good about caching file lookup hits (views, partials, display/editor templates). However one scenario that is not cached is the use of the built-in (default) display/editor templates (where all file lookups are misses).
Any time you use the Html.EditorFor or Html.DisplayFor methods and you do not have a matching template file MVC will generate the appropriate markup for you based on the model’s metadata. However, before that happens it checks all the view engines to find a template file. The more view engines you have registered the longer this will take and since the miss is not cached the process will have to be repeated the next time a page is requested. If you are using only one view engine in your project you should remove the other ones in Global.asax. The easies way to do that is with the following code:
ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new RazorViewEngine());
When: You pass in a null model to a view that uses strongly-typed html helpers (such as Html.TextBoxFor). This frequently happens in Insert scenarios.
Html.TextBoxFor
Why: Strongly-typed html helpers such as Html.TextBoxFor(m => m.Name) will try to emit the value of the model using the provided expression. However when something along the expression chain is null a NullReferenceException will be thrown when the expression gets evaluated. MVC’s expression evaluator catches the exception but on a page with multiple such html helpers the cost of the exception adds up. You can avoid that cost by always passing an instance of the model to the view:
Html.TextBoxFor(m => m.Name)
public ActionResult Insert() { // return View(); // here the model instance defaults to null return View(new Product()); }
When: Your IIS server has the URL Rewrite module installed but none of the applications on the server are using it and you are running ASP.NET MVC 3.
Why: When performing URL generation (for example via a method like Html.ActionLink) in some cases MVC checks to see if the currently requested URL has been rewritten by the URL Rewrite module. If that is the case the result is processed so that it correctly matches the URL requested by the client.
Html.ActionLink
The act of checking if a URL has been rewritten has a non-trivial cost (because it involves checking server variables). ASP.NET MVC 3 checks to see if URL Rewrite is turned off and can cache that fact thus avoiding the need to inspect server variables for each request. If URL Rewrite is turned on MVC will have to check server variables even if no rewriting happened for a particular request so if you are not using URL Rewrite you should turn it off (Note that MVC 2 always performs this check so turning URL Rewrite off will not make a difference).
A colleague of mine recently called me out on the fact that I haven't blogged in … oh about a year and a half. Well it’s 2010 now and resolution season is in full swing so here’s my attempt at getting back on the ball (no promises though).
In a recent post Scott Hanselman described writing custom filters for ASP.NET Dynamic Data. Scott provides a nice overview of the Dynamic Data architecture and then gets his hands dirty with some custom filters using the advanced capabilities available in Dynamic Data Futures. However, he soon realizes that writing custom late-bound LINQ expressions is definitely not a trifle.
I started thinking about how this experience could be improved and so started writing some code. Things were going great and I was well on my way towards providing the “magic” code that would make Scott’s task that much easier when I started getting this déjà vu feeling that I had already seen something very similar. I scratched my head a bit and then remembered a long-lost sample for dynamically building LINQ queries written back when the original Visual Studio 2008 shipped.
It’s available as a download but it also comes bundled with your VS (both 2008 and 2010) installation under the following path in your VS installation directory:
Samples\1033\CSharpSamples.zip\LinqSamples\DynamicQuery\DynamicQuery
This sample implements a subset of the LINQ extension methods in a late-bound, string-based manner. So for example (using Scott’s model classes) instead of writing this:
IQueryable<Brick> bricks; // strongly-typed collection of bricks var result = bricks.Select(p => p.Year).Distinct().OrderBy(i => i);
you can write this “magic” code:
using System.Linq.Dynamic; // you need to include this namespace // for the extension methods to kick in IQueryable bricks; // weakly-typed collection of bricks var result = bricks.Select("Year").Distinct().OrderBy("it");
DynamicQueryable is quite powerful and includes the following
The only custom code that I had to write to support Scott’s scenario was the Distinct method, which is missing from what’s provided. Fortunately this was not that difficult:
public static class DynamicQueryableExtras { public static IQueryable Distinct(this IQueryable q) { var call = Expression.Call(typeof(Queryable), "Distinct", new Type[] { q.ElementType }, q.Expression); return q.Provider.CreateQuery(call); } }
Other missing LINQ APIs could be added quite easily too.
Once I had the Distinct extension method it was easy to rewrite Scott’s code:
protected void Page_Init(object sender, EventArgs e) { var items = Column.Table.GetQuery(); var entityParam = Expression.Parameter(Column.Table.EntityType, "row"); // row => row.Property var columnLambda = Expression.Lambda(Expression.Property(entityParam, Column.EntityTypeProperty), entityParam); // Items.Select(row => row.Property) var selectCall = Expression.Call(typeof(Queryable), "Select", new Type[] { items.ElementType, columnLambda.Body.Type }, items.Expression, columnLambda); // Items.Select(row => row.Property).Distinct var distinctCall = Expression.Call(typeof(Queryable), "Distinct", new Type[] { Column.EntityTypeProperty.PropertyType }, selectCall); // colvalue => colvalue var sortParam = Expression.Parameter(Column.EntityTypeProperty.PropertyType, "sortValue"); var columnResultLambda = Expression.Lambda(sortParam, sortParam); // Items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue) var ordercall = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { Column.EntityTypeProperty.PropertyType, columnResultLambda.Body.Type }, distinctCall, columnResultLambda); var result = items.Provider.CreateQuery(ordercall); foreach (var item in result) { if (item != null) DropDownList1.Items.Add(item.ToString()); } }
as:
protected void Page_Init(object sender, EventArgs e) { var items = Column.Table.GetQuery(); var result = items.Select(Column.EntityTypeProperty.Name) .Distinct() .OrderBy("it"); foreach (var item in result) { if (item != null) DropDownList1.Items.Add(item.ToString()); } }
Much simpler, wouldn’t you agree?
I hope this technique will save you time trying to figure out how to dynamically build LINQ expressions. The sample contains a detailed document describing all of the APIs and the features available in the expression language. You should definitely check it out because it is very powerful. Oh, and if this also looks familiar to you, that’s because it’s almost the same as the querying features in LinqDataSource.