What’s New in ASP.NET MVC 5.2

by Microsoft

This topic describes what's new for ASP.NET MVC 5.2, Microsoft.AspNet.MVC 5.2.2 and ASP.NET MVC 5.2.3 Beta

Software Requirements

Download

The runtime features are released as NuGet packages on the NuGet gallery. All the runtime packages follow the Semantic Versioning specification. The latest ASP.NET MVC 5.2 package has the following version: "5.2.0". You can install or update these packages through NuGet. The release also includes corresponding localized packages on NuGet.

You can install or update to the released NuGet packages by using the NuGet Package Manager Console:

Install-Package Microsoft.AspNet.Mvc -Version 5.2.0

Documentation

Tutorials and other information about ASP.NET MVC 5.2 are available from the ASP.NET web site (https://www.asp.net/mvc).

New Features in ASP.NET MVC 5.2

Attribute routing improvements

Attribute Routing now provides an extensibility point called IDirectRouteProvider, which allows full control over how attribute routes are discovered and configured. An IDirectRouteProvider is responsible for providing a list of actions and controllers along with associated route information to specify exactly what routing configuration is desired for those actions. An IDirectRouteProvider implementation may be specified when calling MapAttributes/MapHttpAttributeRoutes.

Customizing IDirectRouteProvider will be easiest by extending our default implementation, DefaultDirectRouteProvider. This class provides separate overridable virtual methods to change the logic for discovering attributes, creating route entries, and discovering route prefix and area prefix.

With the new attribute routing extensibility of IDirectRouteProvider, a user could do the following:

  1. Support Inheritance of attribute routes. For example, in the following scenario Blog and Store controllers are using an attribute route convention that is defined by the BaseController.

    [InheritedRoute("attributerouting/{controller}/{action=Index}/{id?}")]
    public abstract class BaseController : Controller
    {
    }
    public class BlogController : BaseController
    {
        public string Index()
        {
            return "Hello from blog!";
        }
    }
    public class StoreController : BaseController
    {
        public string Index()
        {
            return "Hello from store!";
        }
    }
    [AttributeUsage(AttributeTargets.Class, Inherited=true, AllowMultiple=true)]
    public class InheritedRouteAttribute : Attribute, IDirectRouteFactory
    {
        public InheritedRouteAttribute(string template)
        {
            Template=template;
        }
        public string Name { get; set; }
        public int Order { get; set; }
        public string Template { get; private set; }
        public new RouteEntry CreateRoute(DirectRouteFactoryContext context)
        {
            // context.Actions will always contain at least one action - and all of the 
            // actions will always belong to the same controller.
            var controllerDescriptor=context.Actions.First().ControllerDescriptor;
            var template=Template.Replace("{controller}", 
                controllerDescriptor.ControllerName);
            IDirectRouteBuilder builder=context.CreateBuilder(template);
            builder.Name=Name;
            builder.Order=Order;
            return builder.Build();
        }
    }
    // Custom direct route provider which looks for route attributes of type 
    // InheritedRouteAttribute and also supports attribute route inheritance.
    public class InheritedDirectRouteProvider : DefaultDirectRouteProvider
    {
        protected override IReadOnlyList<IDirectRouteFactory> 
             GetControllerRouteFactories(ControllerDescriptor controllerDescriptor)
        {
            return controllerDescriptor
                .GetCustomAttributes(typeof(InheritedRouteAttribute), inherit: true)
                .Cast<IDirectRouteFactory>()
                .ToArray();
        }
    }
    
  2. Automatically generate route names for attribute routes.

    protected override IReadOnlyList<IDirectRouteFactory> 
             GetActionRouteFactories(ActionDescriptor actionDescriptor)
    {
        // Get all the route attributes decorated directly on the actions
        IReadOnlyList<IDirectRouteFactory> actionRouteFactories=base.GetActionRouteFactories(actionDescriptor);
        // Check if the route attribute on each action already has a route name and if no, 
        // generate a route name automatically
        // based on the convention: <ControllerName>_<ActionName> (ex: Customers_GetById)
        foreach (IDirectRouteFactory routeFactory in actionRouteFactories)
        {
            RouteAttribute routeAttr=routeFactory as RouteAttribute;
            if (string.IsNullOrEmpty(routeAttr.Name))
            {
                routeAttr.Name=actionDescriptor.ControllerDescriptor.ControllerName + "_" 
                      + actionDescriptor.ActionName;
            }
        }
        return actionRouteFactories;
    }
    protected override IReadOnlyList<IDirectRouteFactory> 
          GetControllerRouteFactories(ControllerDescriptor controllerDescriptor)
    {
        // Get all the route attributes decorated directly on the controllers
        IReadOnlyList<IDirectRouteFactory> controllerRouteFactories=base.GetControllerRouteFactories(controllerDescriptor);
        // Check if the route attribute on each controller already has a route name and if no, 
        // generate a route name automatically
        // based on the convention: <ControllerName>Route (ex: CustomersRoute)
        foreach (IDirectRouteFactory routeFactory in controllerRouteFactories)
        {
            RouteAttribute routeAttr=routeFactory as RouteAttribute;
            if (string.IsNullOrEmpty(routeAttr.Name))
            {
                routeAttr.Name=controllerDescriptor.ControllerName + "Route";
            }
        }
        return controllerRouteFactories;
    }
    
  3. Modify route prefixes in one central place before the routes get added to the route table.

  4. Filter out the controllers on which you want the attribute routing to look for. We hope to blog on 3 and 4 soon.

Facebook fixes for changed API surface

The MVC Facebook package was broken due to few API changes made by Facebook. We are also releasing a new Facebook package (Microsoft.AspNet.Facebook 1.0.0) to fix these issues.

Known Issues and Breaking Changes

Scaffolding MVC/Web API into a project with 5.2.0 packages results in 5.1.2 packages for ones that don't already exist in the project

Updating NuGet packages for ASP.NET MVC 5.2.0 does not update the Visual Studio tools such as ASP.NET scaffolding or the ASP.NET Web Application project template. They use the previous version of the ASP.NET runtime packages (e.g. 5.1.2 in Update 2). As a result, the ASP.NET scaffolding will install the previous version (e.g. 5.1.2 in Update 2) of the required packages, if they are not already available in your projects. However, the ASP.NET scaffolding in Visual Studio 2013 RTM or Update 1 does not overwrite the latest packages in your projects. If you use ASP.NET scaffolding after updating the packages of your projects to Web API 2.2 or ASP.NET MVC 5.2, make sure the versions of Web API and ASP.NET MVC are consistent.

Microsoft.jQuery.Unobtrusive.Validation NuGet package installation fails because it is unable to find a version of Microsoft.jQuery.Unobtrusive.Validation compatible to jQuery 1.4.1

Microsoft.jQuery.Unobtrusive.Validation requires jQuery >=1.8 and jQuery.Validation >=1.8. But,jQuery.Validation (1.8) needs jQuery (≥ 1.3.2 && ≤ 1.6). Because of this, when NuGet installs the JQuery 1.8 and jQuery.Validation 1.8 at the same time, it fails. When you see this issue, you can simply update the version of jQuery.Validation to >= 1.8.0.1 which has the jQuery cap fixed first, you should be able to install Microsoft.jQuery.Unobtrusive.Validation.

The jquery.Validation nuget package version 1.13.0 does not recognize some international email addresses

jQuery.Validation nuget package version 1.11.1 is the last known version which recognizes following valid email addresses. Any later versions might not be able to recognize them. For example:

E-Mail Address Internationalization (EAI) standard (e.g., 用户@domain.com)
EAI + Internationalized Resource Identifiers (IRIs) (eg., 用户@домен.рф)

The issue is reported at https://github.com/jzaefferer/jquery-validation/issues/1222

Syntax Highlighting for Razor Views in Visual Studio 2013

If you update to ASP.NET MVC 5.2 without updating Visual Studio 2013, you will not get Visual Studio editor support for syntax highlighting while editing the Razor views. You will need to update Visual Studio 2013 to get this support.