ASP.NET MVC 5 新特性






4.65/5 (73投票s)
ASP.NET MVC 5 新特性
引言
正如你们大多数人可能已经有ASP.NET MVC的经验,让我们来看看ASP.NET MVC 5引入的一些新特性。在之前的MVC版本中,我们也可能实现了其中一些新特性所提供的功能,但现在这些特性已成为MVC框架的一部分,使用它们比以往任何时候都更简单,因为无需进行任何配置更改或引入外部组件。在我们讨论新特性的过程中,我们也会回顾这些新特性引入之前,先前版本所提供功能的知识。
对我们特别有用的第一个特性是基于特性的路由。要理解基于特性的路由,我们将看看MVC以前版本中路由的实现方式。
MVC 中的路由
由于MVC的宗旨是创建松耦合的应用程序,MVC中的大多数特性都致力于支持创建松耦合的架构。路由就是这样一个MVC特性,它将应用程序的URL模式与其其余部分解耦。为了理解路由的用途,让我们看看几十年前请求是如何处理的。
在ASP.NET Web Forms和以前的Web技术中,每当我们向Web服务器请求一个资源(如网页)时,Web服务器会期望该资源在服务器上是物理存在的,然后将其返回给浏览器,无论是执行该资源并返回HTML(对于aspx页面等动态页面),还是直接返回(如果是html页面)。换句话说,URL与请求的资源(如Web窗体或html页面)之间必须存在一对一的映射。
传统Web Forms应用程序中的请求处理
这是ASP.NET MVC之前的正常场景。在ASP.NET MVC中,由于请求由Action方法处理,因此必须有一种方法将URL映射到适当的Action方法,因为没有物理文件来处理请求的URL。这种映射由路由系统提供。
MVC应用程序中的请求处理
应用程序中使用的所有路由都添加到RouteCollection中。因此,路由系统充当请求和请求处理程序之间的接口。这意味着我们可以根据自己的需求来构建URL,例如创建用户友好且搜索引擎优化的URL。此外,URL可以随时更改,而无需更改应用程序逻辑,因为应用程序逻辑与应用程序中使用的URL模式是解耦的。
以下是路由系统理解的请求URL的基本结构。
请注意,分段是URL中由斜杠字符(“/”)分隔的部分,不包括主机名。我们可以在RouteConfig.cs文件中的RegisterRoutes方法中定义一个路由来处理上述URL,如下所示:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Ecommerce",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "About", id = UrlParameter.Optional }
);
}
这里的url是用于确定传入url是否应由路由处理的url模式,因为MVC应用程序可以有多个路由。url模式中花括号{}内的分段称为分段变量,例如{controller}、{action}和{id}。这些分段变量的值将从url中提取。虽然我们在这里使用了变量,但分段也可以是字面量,如字符串。
当应用程序初始化时,上述路由会被添加到routes路由集合中,因为该方法是从global.asax中的Application_Start方法调用的。
现在,如果我们想更改由控制器中特定Action方法处理的url模式,我们需要在通用的RegisterRoutes方法中进行更改。这有以下缺点:
- 由于RegisterRoutes是定义应用程序中所有路由的通用方法,我们的更改可能会破坏应用程序的URL处理。
- 由于路由在应用程序启动时进行设置,因此我们无法轻松更改应用程序的路由模式而不影响现有路由,因为我们需要考虑添加路由的顺序(路由是从上到下评估的)。这需要仔细测试以验证新添加的路由是否引入了新错误。
- 另外,将路由定义与作为请求处理程序的控制器和Action方法分开,并不是很直观。
基于特性的路由提供了一种优雅的方式来解决这个问题。
MVC 5中的基于特性的路由
这就是基于特性的路由的作用。使用基于特性的路由,我们可以在定义Action方法的相同位置定义路由。以下是使用Route特性定义的路由的示例。如您所见,路由直接附加到Action方法上。
[Route("Products/Electronics/{id}")]
public ActionResult GetElectronicItems(string id)
{
ViewBag.Id = id;
return View();
}
要启用基于特性的路由,我们需要在RouteConfig文件中添加以下内容。
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcAttributeRoutes();
}
所以,现在我们将Route特性附加到我们的Action方法上,我们的Action方法将能够处理与Route特性定义的URL模式匹配的请求。
可选参数
我们还可以使用“?”字符指定Route特性定义的URL模式中是否有可选参数。
如果调用上述Action方法但未提供“id”参数的值,我们将收到一个异常,因为id是必需参数。我们可以通过进行以下更改来使其成为可选参数。
[Route("Products/Electronics/{id?}")]
public ActionResult GetElectronicItems(int? id) {
ViewBag.Id = id; return View();
}
请注意,我们通过使用“?”使id成为可选参数。另外,由于id是值类型,我们必须使其成为可空类型,因为我们总是需要为值类型参数提供值,因为它们不能为null。
路由约束
我们还可以通过将约束名称放在参数名称之后,用冒号分隔来指定参数约束。例如,我们可以使用以下方法指定参数类型应为整数。
[Route("Products/Electronics/{id:int}")]
现在,如果我们不指定整数参数,即使其他分段匹配,路由也不会匹配。我们可以在Route特性中使用的一些其他有用的约束是:
路由约束 | 用于 |
x:bool | 匹配布尔参数 |
x:maxlength(n) | 匹配长度最多为n个字符的字符串参数 |
x:minlength(n) | 匹配长度至少为n个字符的字符串参数 |
x:max | 匹配最大值为n的整数参数。 |
x:min | 匹配最小值为n的整数参数。 |
x:range | 匹配一个值范围内的整数参数。 |
x:float | 匹配浮点数参数。 |
x:alpha | 匹配大写或小写字母字符 |
x:regex | 匹配正则表达式。 |
x:datetime | 匹配DateTime参数。 |
路由前缀
如果一个控制器中有多个Action方法都使用相同的URL前缀,我们可以将RoutePrefix特性应用于控制器,而不是在每个Action方法上都添加该前缀。
例如,我们可以将以下特性附加到控制器上:
[RoutePrefix("Products")]
所以现在我们Action方法上的Route特性不需要指定公共前缀了。
[Route("Electronics/{id}")]
MVC中的过滤器
MVC中的过滤器提供了一种优雅的方式来实现横切关注点。横切关注点是在应用程序的不同层中使用的功能。这种功能的常见示例包括缓存、异常处理和日志记录。
横切关注点应该集中在一个位置,而不是分散和重复地出现在整个应用程序中。这使得更新这类功能非常容易,因为它们集中在一个位置。过滤器提供了这种优势,因为它们用于实现横切关注点,使用可以应用于不同Action方法和控制器的通用逻辑。过滤器被实现为类,其中包含在Action方法执行之前或之后执行的代码。我们可以在MVC 4中创建全局或控制器过滤器。全局过滤器是应用于应用程序中所有Action方法的过滤器,而控制器过滤器则应用于控制器中所有Action方法的过滤器。
我们可以通过创建一个类并将其注册为全局过滤器来创建一个全局过滤器。
public class TestGlobalFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
context.RequestContext.HttpContext.Response.Write("Global filter's in MVC are cool...");
}
}
//Register our global filter
GlobalFilters.Filters.Add(new TestGlobalFilterAttribute());
由于我们已将过滤器注册为全局操作过滤器,因此该过滤器将自动为任何Action方法执行。下面我们可以看到全局过滤器正在生效。
现在,假设我们希望我们的一项Action方法不执行过滤器逻辑。在MVC 4中,没有直接的方法来实现这一点。
MVC 5中的过滤器覆盖
MVC 5提供了一个过滤器覆盖功能,我们可以将其应用于Action方法或控制器,以选择性地排除指定Action方法或控制器的全局过滤器或控制器过滤器。
现在,如果我们想覆盖我们Action方法中的全局操作过滤器,我们只需要应用OverrideActionFilters特性。下面我们将该特性应用于HomeController中的默认About方法。
[OverrideActionFilters]
public ActionResult About(){
ViewBag.Message = "Your application description page.";
return View();
}
这是一个非常简单的例子来理解过滤器覆盖。但它们在许多不同的场景中都可能很有用。一个有用的场景是
[Authorize(Users="ashish")][RoutePrefix("Products")]
public class ProductsController : Controller
{
[Route("Electronics/{categoryId:maxlength(3)}")]
[OverrideAuthorization]
public ActionResult GetElectronics(string categoryId)
{
ViewBag.categoryId= t;
return View();
}
这里我们将Authorize过滤器应用于控制器,然后选择性地覆盖了HomeController中的GetElectronics Action方法。
由于过滤器有四种类型:
- ActionFilter
- AuthenticationFilter
- AuthorizationFilter
- Exception Filter
所以我们可以有四种对应的过滤器覆盖:
- OverrideActionFiltersAttribute
- OverrideAuthenticationAttribute
- OverrideAuthorizationAttribute
- OverrideExceptionAttribute
以上所有特性都实现了 IOverrideFilter 接口。事实上,这就是MVC框架如何确定是否为Action方法或控制器排除任何类型过滤器的方式。
我觉得这是在许多不同场景下都有用的一个特性。
ASP.NET 会员系统
在ASP.NET MVC 5之前,ASP.NET Membership是处理身份验证的常用方法。这意味着身份验证和管理用户凭据的任务由ASP.NET自动处理。使用ASP.NET Membership,用户凭据存储在数据库中,通常是像SQL Server这样的关系数据库。
但随着技术的发展,今天的用户通过社交网络和便携式设备相互连接。因此,需要对期望用户凭据存储在本地数据库中的ASP.NET Membership系统进行检修。ASP.NET提供了一个非常需要的改变,这个新系统叫做ASP.NET Identity。
ASP.NET IDENTITY
ASP.NET Identity的一些主要特性是:
- 任何ASP.NET框架都可以使用它,例如ASP.NET MVC和WebForms。
- 我们可以轻松添加第三方身份验证提供商,如Google、Facebook。
- 我们可以控制持久化存储。所以我们现在不仅可以将凭据存储在
- SQL Server数据库中,还可以使用Azure和NoSQL数据库等其他持久化存储。
通过使用第三方身份验证提供商,可以将用户身份验证的任务委托给第三方网站,如Google。有许多网站支持OpenID协议,如Google。在MVC 5中,我们可以将其用作新创建项目的一部分。
让我们看看如何创建一个使用ASP.NET Identity来通过Google等社交网站验证用户的MVC项目。
当我们选择Visual Studio中的“创建新项目”选项时,我们首先注意到的是,只有一个ASP.NET选项模板,而不是ASP.NET WebForms、MVC和其他ASP.NET框架的多个模板。这个通用窗口是新引入的“一个ASP.NET”的一部分,这意味着像脚手架这样的服务可用于所有ASP.NET框架,如WebForms和MVC。
选择ASP.NET Web应用程序模板选项后,会打开一个新窗口。它提供了选择和自定义MVC和Web Forms等不同框架以及选择身份验证系统的选项。
运行应用程序,在主页上,当您点击右上角的登录链接时,您将导航到登录页面。请注意,这里有一个使用其他服务登录的选项。
我们可以通过转到Startup.Auth文件中的ConfigureAuth方法并取消注释最后一行来启用使用其他服务。
现在,如果我们运行应用程序并转到登录页面,我们将看到以下页面。
点击Google按钮后,我们会被重定向到以下屏幕,可以在其中输入用户名和密码。
Google身份验证已启用,因为我们使用了UseGoogleAuthentication()方法。同样,我们可以对Microsoft和其他社交网站使用身份验证方法。所以,使用ASP.NET Identity,只需调用一个方法即可使用第三方身份验证。
使用脚手架生成代码
脚手架意味着从模型自动生成代码。假设我们有一些模型,我们想为其生成基本的创建、读取、更新和删除操作的骨架代码,那么我们就可以使用MVC 5的脚手架功能,而不是编写通用代码。
有一个针对MVC应用程序的代码生成器,可以根据模型自动生成代码。我们有一个ElectronicItems类,可以用来自动生成控制器代码和视图。使用脚手架的优点是,我们可以使用模型非常轻松快速地生成代码。
public class ElectronicItems
{
public string Name { get; set; }
public string Description { get; set; }
public int Id { get; set; }
}
要使用脚手架,请右键单击项目中的一个项,然后选择“新建脚手架项”。
从打开的对话框中选择“MVC 5 Controller..”选项。
输入控制器名称,并选择要生成控制器的模型。点击“添加”,我们将为您生成控制器和视图。
正如您所见,以下控制器已被生成,其中包含您在以前版本中必须手动编写的基本CRUD操作。
所以您可能会感受到脚手架可以减少您在早期MVC版本中必须手动编写的代码量。
所以,这些是MVC 5中引入的一些新特性。我相信它们会让您作为开发者的生活更轻松。
对于常见的C#问题,您会发现以下资源很有帮助:C# 常见问题解答