Marcin On ASP.NET

Keeping my eye on the dot

Posts
  • Marcin On ASP.NET

    MVC 3 Project Upgrade Tool

    • 24 Comments

    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:

    • If you have a Visual Studio 2008 solution you can simply open it with Visual Studio 2010 to initiate the solution upgrade process.
    • If your projects are targetting .NET 3.5 read how to target .NET 4.
    • If you have a MVC 1.0 project you can use the old version of this tool to convert it to MVC 2.

    MVC upgrade tool screenshot

    The usage of the tool is quite simple:

    1. If you use a source control system make sure your files are checked out and writable
    2. Run the executable
    3. Select your Visual Studio 2010 solution file that contains your project
    4. Review the changes for each item in the Item details pane
    5. Click on the Convert button to initiate the conversion process
    6. Review the results in the Conversion log pane


    During the conversion process the tool will:

    1. Create a backup of the entire solution.
    2. Update all class library projects (including Test projects) that reference System.Web.Mvc.dll to reference version 3.0.
    3. Update all Web Application projects that reference System.Web.Mvc to reference version 3.0 and add references to System.Web.Helpers.dll and System.Web.WebPages.dll.
    4. Change all MVC 2 Web Application projects to be MVC 3 projects (this affects which version of the 'Add View' dialog you get etc) 
    5. Update all MVC Web Application root Web.config files:
      1. Update references to System.Web.Mvc version 3.0.
      2. Add an assembly binding redirect entry for System.Web.Mvc.
      3. Add assembly and namespace references to System.Web.Helpers and System.Web.WebPages.
      4. Add the “ClientValidationEnabled” and “UnobtrusiveJavaScriptEnabled” settings to the <appSettings> element with value “false” if they were not already present (these settings can be used to control the unobtrusive client validation and unobtrusive Ajax features).
    6. Update all MVC Web Application views Web.config files (~\Views\Web.config as well as the views Web.config files for all Areas):
      1. Update references to System.Web.Mvc version 3.0
      2. Add a <configSections> entry required for Razor configuration in MVC
      3. Add the <system.web.webPages.razor> entry required for Razor support in MVC
      4. Add the “webPages:enabled” setting to the <appSettings> element with value “false” (required to prevent .cshtml or .vbhtml files in the Views folder from being directly accessible from a web browser)
    7. Add the following JavaScript libraries to the MVC Web Applications (only if they did not already exist):
      • jQuery 1.4.4 (jquery-1.4.4.js, jquery-1.4.4-vsdoc.js, jquery-1.4.4.min.js)
      • jQuery UI 1.8.7 (jquery-ui.js, jquery-ui.min.js)
      • jQuery Validation 1.7 (jquery-validate.js, jquery-validate-vsdoc.js, jquery-validate.min.js)
      • Microsoft Ajax (MicrosoftAjax.js, Microsoft.Ajax.debug.js)
    8. Overwrite MVC-specific JavaScript files in MVC Web Applications:
      • MicrosoftMvcAjax.js, MicrosoftMvcAjax.debug.js, MicrosoftMvcValidation.js, MicrosoftMvcValidation.debug.js, jquery.unobtrusive-ajax.js, jquery.unobtrusive-ajax.min.js, jquery.validate.unobtrusive.js, jquery.validate.unobtrusive.min.js
    9. Add jQuery UI theme files (stylesheet and images)


    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:

    • Read-only project files are not supported (make sure you check out your solution if you use source control)
    • Very long file paths might cause problems
    • Solutions with project files outside of the solution folder might cause problems
    • The tool will not upgrade your application code to account for any potential runtime breaking changes
    • Non-standard project files (e.g. missing MVC project type GUID) will not be handled correctly
    • Once again, VS 2008 solutions, MVC 1 or .NET 3.5 projects are not supported
    • The tool will also not modify any Web Sites in your solution


    However, if you run into problems let me know and I will see if we can get them addressed.

  • Marcin On ASP.NET

    Razor, Nested Layouts and Redefined Sections

    • 10 Comments

    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.

    Redefining sections

    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.

    Conditionally redefining sections via RedefineSection

    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:

    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.

  • Marcin On ASP.NET

    Optional Razor Sections with Default Content

    • 8 Comments

    Solution quick links:

    1. IsSectionDefined method
    2. Razor inline templates

    RenderSection

    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.

    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?

    Option 1: Use the IsSectionDefined method

    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:

    The following sections have been defined but have not been rendered for the layout page "~/Views/Shared/_Layout.cshtml": "OptionalContent"

    Option 2: Use Razor inline templates

    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.

    If you like this technique read the follow up: Razor, Nested Layouts and Redefined Sections

  • Marcin On ASP.NET

    Building custom LINQ expressions made easy with DynamicQueryable.

    • 0 Comments

    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

    • Dynamic string-based querying of any LINQ provider (late-bound versions of Where, Select, OrderBy, Take, Skip, GroupBy, Any, and Count extension methods)
    • String-based mini expression language (like the “it” identifier in the sample above), including complex conditional statements and all operators
    • Dynamic creation of classes for projections

    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.

  • Marcin On ASP.NET

    ASP.NET MVC Performance Tips

    • 9 Comments

    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.

    Disable unused view engines

    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.

    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());

    Avoid passing null models to views

    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.

    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:

    public ActionResult Insert() {
        // return View(); // here the model instance defaults to null
        return View(new Product());
    }

    Uninstall URL Rewrite if you don’t use it

    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.

    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).

Page 1 of 5 (25 items) 12345