经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
ASP.NET Core MVC应用模型的构建[3]: Controller的收集
来源:cnblogs  作者:Artech  时间:2024/3/1 8:45:17  对本文有异议

从编程的角度来看,一个MVC应用是由一系列Controller类型构建而成的,所以对于一个代表应用模型的ApplicationModel对象来说,它的核心就是Controllers属性返回的一组ControllerModel对象,每个ControllerModel对象是应用模型针对Controller类型的描述。

一、ControllerModel
二、 实例演示:Controller模型的构建
三、实例演示:定制Controller模型

一、ControllerModel

描述Controller类型的ControllerModel具有如下定义。该类型的Application属性返回作为当前应用模型的ApplicationModel对象。它的Actions属性返回的ActionModel是对所有定义在当前Controller类型中的Action方法的描述。描述Controller类型属性的PropertyModel对象则存放在ControllerProperties属性中,由于PropertyModel和描述Action方法参数的ParameterModel对象承载的都是服务于模型绑定的元数据,所以我们会将这两个类型的介绍放在一起。ControllerModel类型的Selectors属性返回的一组SelectorModel对象是对应用在Controller级别上的Action选择器的描述,我们会在后续内容中对SelectorModel对象进行单独介绍。

  1. public class ControllerModel : ICommonModel, IFilterModel, IApiExplorerModel
  2. {
  3. public ApplicationModel Application { get; set; }
  4.  
  5. public IList<ActionModel> Actions { get; }
  6. public IList<PropertyModel> ControllerProperties { get; }
  7. public IList<SelectorModel> Selectors { get; }
  8.  
  9. public IDictionary<object, object> Properties { get; }
  10. public IList<IFilterMetadata> Filters { get; }
  11. public ApiExplorerModel ApiExplorer { get; set; }
  12.  
  13. public TypeInfo ControllerType { get; }
  14. public IReadOnlyList<object> Attributes { get; }
  15. public string ControllerName { get; set; }
  16. public string DisplayName { get; }
  17. public IDictionary<string, string> RouteValues { get; }
  18.  
  19. MemberInfo ICommonModel.MemberInfo { get; }
  20. string ICommonModel.Name { get; }
  21. }

ControllerModel类型同时实现了ICommonModel、IFilterModel和IApiExplorerModel接口。默认注册的DefaultApplicationModelProvider会对ControllerModel对象做如下的设置:ControllerType和MemberInfo属性会设置为当前Controller的类型,该类型名称去除“Controller”后缀的字符串会作为Name和ControllerName的属性值。通过标注的特性注册到Controller类型上的过滤器会被提取出来,对应的元数据会添加到Filters属性中。ApiExplorer属性返回的ApiExplorerModel对象由标注在Controller类型上实现了IApiDescriptionGroupNameProvider和IApiDescriptionVisibilityProvider接口的特性构建而成。

DefaultApplicationModelProvider还会将标注到Controller类型上的所有特性提取出来,并将它们添加到Attributes属性中。如果特性类型实现了IRouteTemplateProvider接口,它们将专门用来构建特性路由信息或者路由约束,所以它们会从此列表中移除。DisplayName属性返回的显示名称通过对类型名称作相应格式化生成。DefaultApplicationModelProvider还会提取标注在Controller类型上实现了IRouteValueProvider接口的特性,并利用对应的设置来填充RouteValues属性返回的路由参数。目前唯一实现了该接口的是如下这个用来设置Area名称的AreaAttribute特性,设置的路由参数名称为“area”。

  1. public interface IRouteValueProvider
  2. {
  3. string RouteKey { get; }
  4. string RouteValue { get; }
  5. }
  6. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true, Inherited=true)]
  7. public abstract class RouteValueAttribute : Attribute, IRouteValueProvider
  8. {
  9. public string RouteKey { get; }
  10. public string RouteValue { get; }
  11. protected RouteValueAttribute(string routeKey, string routeValue);
  12. }
  13. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
  14. public class AreaAttribute : RouteValueAttribute
  15. {
  16. public AreaAttribute(string areaName) : base("area", areaName)
  17. {}
  18. }

二、 实例演示:Controller模型的构建

我们照例通过一个简单的实例来演示应用模型中用以描述Controller的元数据采用的默认构建规则。我们在前面演示程序中定义如下这个测试Controller类型FoobarController。如代码片段所示,FoobarController类型上标注了三个特性,分别是用来指定Area的AreaAttribute、过滤器特性FoobarAttribute和设置ApiExplorer的ApiExplorerSettingsAttribute。FoobarController类型中定义了两个属性(A和B)和两个Action方法(Foo和Bar)。

  1. [Area("test")]
  2. [Foobar]
  3. [ApiExplorerSettings(GroupName = "test")]
  4. public class FoobarController
  5. {
  6. public string A { get; set; }
  7. public string B { get; set; }
  8.  
  9. [HttpGet("foo")]
  10. public void Foo() => throw new NotImplementedException();
  11. [HttpGet("bar")]
  12. public void Bar() => throw new NotImplementedException();
  13. }

为了在页面上呈现描述FoobarController类型的ControllerModel对象的相关信息,我们对定义在HomeControllere中的Action方法Index作了相应的修改。如下面的代码片段所示,我们利用在方法中注入的ApplicationModelProducer对象根据FoobarController类型创建一个ApplicationModel对象,并将包含在该对象中用来描述FoobarController的ControllerModel作为Model呈现成默认的View中。

  1. public class HomeController: Controller
  2. {
  3. [HttpGet("/")]
  4. public IActionResult Index([FromServices]ApplicationModelProducer producer)
  5. {
  6. var applicationModel = producer.Create(typeof(FoobarController));
  7. return View(applicationModel.Controllers.Single());
  8. }
  9. }

我们最后对Action方法Index对应的View文件作相应的修改。如下面的代码片段所示,这是一个Model类型为ControllerModel的强类型View,,它将ControllerModel承载的元数据呈现在一个表格中。

  1. @using Microsoft.AspNetCore.Mvc.ApplicationModels;
  2. @model ControllerModel
  3. @{
  4. var commonModel = (ICommonModel)Model;
  5. var actions = Model.Actions;
  6. var filters = Model.Filters;
  7. var properties = Model.ControllerProperties;
  8. var attributes = Model.Attributes;
  9. var routeValues = Model.RouteValues.ToArray();
  10. }
  11. <html>
  12. <head>
  13. <title>Controller</title>
  14. </head>
  15. <body>
  16. <table border="1" cellpadding="0" cellspacing="0">
  17. <tr><td>ControllerType </td><td>@Model.ControllerType.Name</td></tr>
  18. <tr><td>ControllerName </td><td>@Model.ControllerName</td></tr>
  19. <tr><td>Name </td><td>@commonModel.Name</td></tr>
  20. <tr><td>DisplayName </td><td>@Model.DisplayName</td></tr>
  21. <tr><td rowspan="@actions.Count">Actions</td><td>@actions[0].ActionName</td></tr>
  22. @for (int index = 1; index < actions.Count; index++)
  23. {
  24. <tr><td>@actions[index].ActionName</td></tr>
  25. }
  26. <tr>
  27. <td rowspan="@filters.Count">Filters</td><td>@filters[0].GetType().Name</td>
  28. </tr>
  29. @for (int index = 1; index < filters.Count; index++)
  30. {
  31. <tr><td>@filters[index].GetType().Name</td></tr>
  32. }
  33. <tr>
  34. <td rowspan="@properties.Count">ControllerProperties</td>
  35. <td>@properties[0].PropertyName</td>
  36. </tr>
  37. @for (int index = 1; index < properties.Count; index++)
  38. {
  39. <tr><td>@properties[index].PropertyName</td></tr>
  40. }
  41. <tr>
  42. <td rowspan="@attributes.Count">Attributes</td>
  43. <td>@attributes[0].GetType().Name</td>
  44. </tr>
  45. @for (int index = 1; index < attributes.Count; index++)
  46. {
  47. <tr><td>@attributes[index].GetType().Name</td></tr>
  48. }
  49. <tr>
  50. <td rowspan="@routeValues.Length">RouteVlues</td>
  51. <td>@routeValues[0].Key = @routeValues[0].Value</td>
  52. </tr>
  53. @for (int index = 1; index < routeValues.Length; index++)
  54. {
  55. <tr><td>@routeValues[index].Key = @routeValues[index].Value</td></tr>
  56. }
  57. <tr>
  58. <td rowspan="2">ApiExplorer</td>
  59. <td>IsVisible = @Model.ApiExplorer.IsVisible </td>
  60. </tr>
  61. <tr><td>GroupName = @Model.ApiExplorer.GroupName </td></tr>
  62. </table>
  63. </body>
  64. </html>

改动后的演示程序启动后,我们利用浏览器访问应用的主页,可以得到如图1所示的输出结果。正如上面我们所说的,去除“Controller”字符后缀的类型名称成为了ControllerModel对象的Name和ControllerName的属性值(“Foobar”)。两个属性(A和B)和Action方法(Foo和Bar)转换成相应的PropertyModel和ActionModel对象并分别添加到ControllerModel对象的ControllerProperties和Actions属性中。通过标注特性注册的过滤器(FoobarAttribute)被添加到ControllerModel对象的Filters属性中。通过标注的AreaAttribute设置的Area名称最终转移到ControllerModel对象对象RouteValues属性中。ControllerModel对象的ApiExplorer属性返回的ApiExplorerModel对象很明显是通过标注在类型上的ApiExplorerSettingsAttribute特性创建的,而它的Attributes属性中包含了我们标注的三个特性。

clip_image002

图1Controller模型默认的构建规则

三、实例演示:定制Controller模型

通过前面介绍的针对应用模型的总体设计,我们知道针对Controller模型的定制可以通过自定义的IControllerModelConvention实现类型来实现,我们接下来利用这种方式来改变Controller默认的命名规则。我们在上面演示的程序中定义了如下这个ControllerNameAttribute特性,该特性类型实现了IControllerModelConvention接口,在实现的Apply方法中,我们将构造函数中设置的Controller名称应用到提供的ControllerModel对象上。我们将该特性标注到FoobarController类型上并将名称设置为“Baz”。

  1. [AttributeUsage(AttributeTargets.Class)]
  2. public class ControllerNameAttribute : Attribute, IControllerModelConvention
  3. {
  4. public string ControllerName { get; }
  5. public ControllerNameAttribute(string name) => ControllerName = name;
  6. public void Apply(ControllerModel controller) => controller.ControllerName = ControllerName;
  7. }
  8.  
  9. [Area("test")]
  10. [Foobar]
  11. [ApiExplorerSettings(GroupName = "test")]
  12. [ControllerName("Baz")]
  13. public class FoobarController
  14. {
  15. }

改动后的演示程序启动后,我们利用浏览器访问应用的主页,可以得到如图2所示的输出结果。我们从图中可以看出,对于最终生成的用来描述FoobarController类型的ControllerModel对象来说,它的ControllerName属性被设置成我们指定的名称“Baz”,它的Name属性(ControllerModel类型针对ICommonModel接口的实现)返回的就是ControllerName属性值。

clip_image004

图2 自定义IControllerModelConvention实现类型定制Controller模型

ASP.NET Core MVC应用模型的构建[1]: 应用的蓝图
ASP.NET Core MVC应用模型的构建[2]: 应用模型
ASP.NET Core MVC应用模型的构建[3]: Controller模型
ASP.NET Core MVC应用模型的构建[4]: Action模型

原文链接:https://www.cnblogs.com/artech/p/18031075/mvc_app_model_3

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号