ControllerModel类型的Actions属性包含一组描述有效Action方法的ActionModel对象。对于定义在Controller类型中的所有方法,究竟哪些方法才能成为有效的Action方法呢?所以在正式介绍ActionModel类型之前,我们先来聊聊Action方法的选择规则。

一、Action方法的选择

二、ActionModel

三、PropertyModel与ParameterModel

四、SelectorModel

五、实例演示:选择器模型的构建

一、 Action方法的选择

当DefaultApplicationModelProvider对象根据某个具体的Controller类型创建对应ControllerModel对象的时候,它会提取出定义在该类型中的方法,并按照预定义的规则选择出有效的Action方法。有效的Action方法必须满足如下条件:

  • 公共方法:私有(Private)、内部(Internal)和受保护(Protected)方法均为无效Action方法。
  • 非抽象方法:抽象方法为无效的Action方法(这个限制可以忽略,因为Controller不会是抽象类型)。
  • 非泛型方法:Action方法不能定义成泛型方法。
  • 非静态方法:静态方法为无效Action方法。
  • 不是从Object类型上继承的方法:Action方法支持继承,但是从Object类型上继承的方法不能成为Action方法。
  • 不是对IDisposable接口的实现:如果Controller类型实现了IDisposable接口,实现的Dispose方法不是有效的Action方法。

二、ActionModel

如下面的代码片段所示,ActionModel类型实现了ICommonModel、IFilterModel和IApiExplorerModel三个接口。默认注册的DefaultApplicationModelProvider会对ActionModel对象做如下的设置:MemberInfo和ActionMethod属性都将设置为描述当前Action方法的MethodInfo对象。通过标注的特性注册到Action方法上的过滤器会被提取出来,对应的元数据会添加到Filters属性中。ApiExplorer属性返回的ApiExplorerModel对象由标注在Action方法上实现了IApiDescriptionGroupNameProvider和IApiDescriptionVisibilityProvider接口的特性构建而成。

  1. public class ActionModel : ICommonModel, IFilterModel, IApiExplorerModel
  2. {
  3. public ControllerModel Controller { get; set; }
  4.  
  5. public IList<IFilterMetadata> Filters { get; }
  6. public ApiExplorerModel ApiExplorer { get; set; }
  7. public IDictionary<object, object> Properties { get; }
  8.  
  9. public IList<ParameterModel> Parameters { get; }
  10. public IList<SelectorModel> Selectors { get; }
  11.  
  12. public MethodInfo ActionMethod { get; }
  13. public string DisplayName { get; }
  14. public string ActionName { get; set; }
  15. public IReadOnlyList<object> Attributes { get; }
  16.  
  17. public IOutboundParameterTransformer RouteParameterTransformer { get; set; }
  18. public IDictionary<string, string> RouteValues { get; }
  19.  
  20. MemberInfo ICommonModel.MemberInfo { get; }
  21. string ICommonModel.Name { get; }
  22. }

DefaultApplicationModelProvider会为Action方法的每个参数创建一个ParameterModel对象,并添加到Parameters属性中。应用在Action方法上的用于封装路由信息(特性路由、约束和终结点元数据)的SelectorModel对象会按照上述的方式构建出来,并添加到Selectors属性中。标注在Action方法上的特性会被提取出来并添加到Attributes属性返回的列表中。表示Action名称的ActionName与Name属性具有相同的值,DefaultApplicationModelProvider会默认将它们设置为方法的名称,但是我们可以在方法上通过标注如下这个ActionNameAttribute特性对该属性进行设置。

  1. [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
  2. public sealed class ActionNameAttribute : Attribute
  3. {
  4. public string Name { get; }
  5. public ActionNameAttribute(string name);
  6. }

我们照例通过一个简单的示例来演示一下DefaultApplicationModelProvider对象针对ActionModel的构建规则。我们依然沿用前面创建的演示实例,这次我们将FoobarController定义成如下的形式。如代码片段所示,我们为Action方法定义了三个参数,并在上面标注了四个特性,其中FoobarAttribute特性是我们应用在该Action方法上的过滤器,ApiExplorerSettingsAttribute特性针对ApiExplorer作了相应设置,HttpGetAttribute特性完成了针对路由和HTTP方法约束的定义,ActionNameAttribute特性则将Action名称设置为“Baz”。

  1. public class FoobarController
  2. {
  3. [Foobar]
  4. [ApiExplorerSettings(GroupName ="test")]
  5. [HttpGet("/foobar/baz")]
  6. [ActionName("Baz")]
  7. public void Index(string foo, string bar, string baz) => throw new NotImplementedException();
  8. }

我们需要修改定义在HomeController中的Action方法Index。如下面的代码片段所示,在利用通过参数注入的ApplicationModelProducer对象根据提供的FoobarController类型创建出对应ApplicationModel对象之后,我们提取出描述Action方法Index的ActionModel对象,并将其作为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().Actions.Single());
  8. }
  9. }

我们将按照如下的形式重新定义了Action方法Index对应的View。如下面的代码片段所示,这是一个Model类型为ActionModel的强类型View,,它将ActionModel承载的元数据呈现在一个表格中。

  1. @model Microsoft.AspNetCore.Mvc.ApplicationModels.ActionModel
  2. @{
  3. var filters = Model.Filters;
  4. var routeValues = Model.RouteValues.ToArray();
  5. var parameters = Model.Parameters;
  6. var attributes = Model.Attributes;
  7. }
  8. <html>
  9. <head>
  10. <title>Action</title>
  11. </head>
  12. <body>
  13. <table border="1" cellpadding="0" cellspacing="0">
  14. <tr><td>Method</td><td>@Model.ActionMethod.Name</td></tr>
  15. <tr><td>ActionName</td><td>@Model.ActionName</td></tr>
  16. <tr><td>DisplayName</td><td>@Model.DisplayName</td></tr>
  17. <tr>
  18. <td rowspan="@parameters.Count">Parameters</td>
  19. <td>@parameters[0].Name</td>
  20. </tr>
  21. @for (int index = 1; index < parameters.Count; index++)
  22. {
  23. <tr><td>@parameters[index].Name</td></tr>
  24. }
  25. <tr>
  26. <td rowspan="@filters.Count">Filters</td>
  27. <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="@attributes.Count">Attributes</td>
  35. <td>@attributes[0].GetType().Name</td>
  36. </tr>
  37. @for (int index = 1; index < attributes.Count; index++)
  38. {
  39. <tr><td>@attributes[index].GetType().Name</td></tr>
  40. }
  41. @if (routeValues.Length == 0)
  42. {
  43. <tr><td>RouteValues</td><td>N/A</td></tr>
  44. }
  45. else
  46. {
  47. <tr>
  48. <td rowspan="@routeValues.Length">RouteValues</td>
  49. <td>@routeValues[0].Key = @routeValues[0].Value</td>
  50. </tr>
  51. }
  52. @for (int index = 1; index < routeValues.Length; index++)
  53. {
  54. <tr><td>@routeValues[index].Key = @routeValues[index].Value</td></tr>
  55. }
  56. <tr>
  57. <td rowspan="2">ApiExplorer</td>
  58. <td>IsVisible = @Model.ApiExplorer.IsVisible </td>
  59. </tr>
  60. <tr>
  61. <td>GroupName = @Model.ApiExplorer.GroupName </td>
  62. </tr>
  63. </table>
  64. </body>
  65. </html>

改动后的演示程序启动后,我们利用浏览器访问应用的主页,可以得到如图1所示的输出结果。我们从图中可以看出,Action名称来源于标注在方法上的ActionNameAttribute特性。DefaultApplicationModelProvider会为方法的每个参数创建一个ParameterModel对象并添加到ActionModel对象的Properties属性中。通过特性标注注册到Action方法上的FoobarAttribute过滤器被添加到ActionModel对象的Filters属性中。Action方法标注的四个特性全部被添加到ActionModel对象的Attributes属性中。ActionModel对象的ApiExplorer属性返回的ApiExplorerModel对象是由标注在方法上的ApiExplorerSettingsAttribute特性构建的。值得一提的是,Controller和Action的名称此时并没有作为路由参数添加到RouteValues属性中。

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

三、PropertyModel与ParameterModel

默认注册的DefaultApplicationModelProvider会将定义在Controller类型的公共属性(包括从基类继承的属性)提取创建,然后创建相应的PropertyModel对象并添加到ControllerModel对象的ControllerProperties属性中。描述属性的PropertyModel对象和描述参数的ParameterModel对象都是为了提供模型绑定的元数据,所以它们具有相同的基类ParameterModelBase。

  1. public abstract class ParameterModelBase : IBindingModel
  2. {
  3. public string Name { get; protected set; }
  4. public Type ParameterType { get; }
  5. public IReadOnlyList<object> Attributes { get; }
  6. public BindingInfo BindingInfo { get; set; }
  7. public IDictionary<object, object> Properties { get; }
  8. }

如上面的代码片段所示,抽象类ParameterModelBase实现了IBindingModel,所以它需要利用实现的BindingInfo书信提供模型绑定信息。ParameterModelBase并没有实现IPropertyModel接口,但是其自身提供了一个Properties属性。ParameterModelBase的Name和ParameterType属性分别表示对应参数/属性的名称和类型。标注到属性上的特性会添加到Attributes属性中。如下所示的是描述Controller属性的PropertyModel类型,和描述Action方法参数的ParameterModel类型的定义。

  1. public class PropertyModel : ParameterModelBase, ICommonModel, IBindingModel
  2. {
  3. public ControllerModel Controller { get; set; }
  4. public PropertyInfo PropertyInfo { get; }
  5. public string PropertyName { get; set; }
  6. public IReadOnlyList<object> Attributes { get; }
  7. public IDictionary<object, object> Properties { get; }
  8. MemberInfo ICommonModel.MemberInfo { get; }
  9. }
  10.  
  11. public class ParameterModel : ParameterModelBase, ICommonModel
  12. {
  13. public ActionModel Action { get; set; }
  14. public ParameterInfo ParameterInfo { get; }
  15. public string ParameterName { get; set; }
  16. public string DisplayName { get; }
  17. public IReadOnlyList<object> Attributes { get; }
  18. public IDictionary<object, object> Properties { get; }
  19. MemberInfo ICommonModel.MemberInfo { get; }
  20. }

四、SelectorModel

SelectorModel类型是对Action选择器(Selector)的描述,这里的选择器旨在解决如何为请求选择匹配Action的问题,所以它承载的其实针对路由的原始定义。如下面的代码片段所示,SelectorModel类型通过AttributeRouteModel、ActionConstraints和EndpointMetadata分别存储了特性路由信息、约束和终结点元数据。

  1. public class SelectorModel
  2. {
  3. public AttributeRouteModel AttributeRouteModel { get; set; }
  4. public IList<IActionConstraintMetadata> ActionConstraints { get; }
  5. public IList<object> EndpointMetadata { get; }
  6. }
  7.  
  8. public class AttributeRouteModel
  9. {
  10. public IRouteTemplateProvider Attribute { get; }
  11. public string Template { get; set; }
  12. public int? Order { get; set; }
  13. public string Name { get; set; }
  14. public bool SuppressLinkGeneration { get; set; }
  15. public bool SuppressPathMatching { get; set; }
  16. public bool IsAbsoluteTemplate { get; }
  17. }

由于路由可以通过标注到Controller类型或者Action方法上相应的特性来定义,所以描述Controller类型和Action方法的ControllerModel和ActionModel类型都具有一个Selectors属性来保存各自的选择器,DefaultApplicationModelProvider针对它们的解析方式也是一致的。这里用来定义路由的特性实现了如下所示的IRouteTemplateProvider特性。

  1. public interface IRouteTemplateProvider
  2. {
  3. string Template { get; }
  4. int? Order { get; }
  5. string Name { get; }
  6. }

顾名思义,实现IRouteTemplateProvider接口的特性旨在定义一个针对指定模板的路由。除此之外,针对SelectorModel的构建还涉及另一个名为IActionHttpMethodProvider的接口,实现该接口的特性为目标Action定义针对HTTP方法的约束。

  1. public interface IActionHttpMethodProvider
  2. {
  3. IEnumerable<string> HttpMethods { get; }
  4. }

对于目前提供的实现了IActionHttpMethodProvider接口的特性来说,它们无一例外都同时实现了IRouteTemplateProvider接口。比如下面这个AcceptVerbsAttribute特性可以标注到Action方法上指定一组支持的HTTP方法,同时也可以利用三个属性(Route、Name和Order)对路由作相应的定义(显式实现的Template和Order属性与自身Route和Order属性具有相同的值)。顺便提一下,我们在AcceptVerbsAttribute特性构造函数以字符串指定的HTTP方法名称会一律转换成大写形式。

  1. [AttributeUsage( AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
  2. public sealed class AcceptVerbsAttribute : Attribute, IActionHttpMethodProvider, IRouteTemplateProvider
  3. {
  4. public IEnumerable<string> HttpMethods { get; }
  5. public string Route { get; set; }
  6. public int Order { get; set; }
  7. public string Name { get; set; }
  8.  
  9. string IRouteTemplateProvider.Template { get; }
  10. int? IRouteTemplateProvider.Order { get; }
  11.  
  12. public AcceptVerbsAttribute(string method);
  13. public AcceptVerbsAttribute(params string[] methods);
  14. }

虽然AcceptVerbsAttribute特性可以为我们指定多个支持的HTTP方法,但是我们似乎更倾向于使用针对具有某种HTTP方法的特性,比如HttpGetAttribute、HttpPostAttribute、HttpPutAttribute、HttpDeleteAttribute、HttpHeadAttribute、HttpPatchAttribute和HttpOptionsAttribute特性,它们都派生于如下这个抽象的HttpMethodAttribute特性类型。

  1. [AttributeUsage( AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
  2. public abstract class HttpMethodAttribute : Attribute, IActionHttpMethodProvider, IRouteTemplateProvider
  3. {
  4. public IEnumerable<string> HttpMethods { get; }
  5. public string Template { get; }
  6. public int Order { get; set; }
  7. public string Name { get; set; }
  8.  
  9. int? IRouteTemplateProvider.Order { get; }
  10.  
  11. public HttpMethodAttribute(IEnumerable<string> httpMethods);
  12. public HttpMethodAttribute(IEnumerable<string> httpMethods, string template);
  13. }

IRouteTemplateProvider接口除了上述这些实现类型之外,如下这个专门用来定义路由的RouteAttribute特性单独实现了该接口。从提供的代码片段可以看出,RouteAttribute特性可以标注在Controller类型或者具体的Action方法上。

  1. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true, Inherited=true)]
  2. public class RouteAttribute : Attribute, IRouteTemplateProvider
  3. {
  4. public string Template { get; }
  5. public int Order { get; set; }
  6. public string Name { get; set; }
  7.  
  8. public RouteAttribute(string template);
  9. int? IRouteTemplateProvider.Order { get; }
  10. }

DefaultApplicationModelProvider针对SelectorModel对象的构建逻辑分为两种情况。如果标注在当前Controller类型或者Action方法上的特性没有提供任何路由信息,这种情况由分为两种场景:其一,根本没有标注任何实现了IRouteTemplateProvider接口的特性;其二,所有的特性并没有对定义在该接口的三个属性(Template、Name和Order)做任何设置,比如我们经常在Action方法上标注一个没有提供任何参数的HttpGetAttribute特性,其目的只是限制支持的HTTP方法,而不是定义路由。

在这种情况下,DefaultApplicationModelProvider会创建一个唯一的SelectorModel对象。由于没有任何路由被定义,所以该对象的AttributeRouteModel属性会返回Null。标注在Controller类型或者Action方法上实现了IActionConstraintMetadata接口的特性会作为约束添加到ActionConstraints属性中。如果标注了实现IActionHttpMethodProvider接口的特性对HTTP方法做了限制,一个对应的HttpMethodActionConstraint对象会额外创建出来并添加到ActionConstraints属性中。与此同时,一个针对HTTP方法列表的HttpMethodMetada对象会被创建出来并作为终结点元数据被添加到EndpointMetadata属性中。除此之外,所有特性都会作为终结点元数据添加到EndpointMetadata属性中。

如果当前Controller类型或者Action方法上标注了实现IRouteTemplateProvider接口的特性,并且作了具体的路由设置,DefaultApplicationModelProvider会为每个IRouteTemplateProvider对象创建一个SelectorModel对象。对于每一个针对IRouteTemplateProvider对象创建的SelectorModel对象来说,设置的路由信息会被提取出来用于创建对应的AttributeRouteModel对象。如果当前特性是一个IActionHttpMethodProvider对象,一个对应的HttpMethodActionConstraint对象会额外创建出来并添加到ActionConstraints属性中。与此同时一个针对HTTP方法列表的HttpMethodMetada对象会被创建出来,当前特性和这个对象都将作为终结点元数据被添加到EndpointMetadata属性中。

如果当前IRouteTemplateProvider对象类型为RouteAttribute,那些没有提供路由信息的实现了IActionHttpMethodProvider接口的特性(即只定义了HTTP方法约束的特性)会被提取出来,一个根据它们提供的HTTP方法列表创建的HttpMethodActionConstraint对象并添加到ActionConstraints属性中。与此同时,一个针对HTTP方法列表的HttpMethodMetada对象会被创建出来并作为终结点元数据被添加到EndpointMetadata属性中。EndpointMetadata属性最终包含的终结点元数据还包括当前RouteAttribute特性和这些单纯定义约束的特性。

五、实例演示:选择器模型的构建

对于DefaultApplicationModelProvider为Controller类型或者Action方法构建SelectorModel的逻辑,我想针对具体的场景会更好理解一点,为此我们来演示几个简单的实例。我们依然沿用前面的演示程序,并将FoobarController类型改写成如下的形式。FoobarController类型中定义了三个Action方法,接下来我们看看DefaultApplicationModelProvider对象会为它们创建出怎样的选择器。

  1. public class FoobarController
  2. {
  3. [HttpGet]
  4. [HttpPost]
  5. public void Foo()=>throw new NotImplementedException();
  6.  
  7. [HttpGet("bar")]
  8. [HttpPost("bar")]
  9. public void Bar() => throw new NotImplementedException();
  10.  
  11. [HttpGet()]
  12. [HttpPost("bar")]
  13. [Route("bar")]
  14. public void Baz() => throw new NotImplementedException();
  15. }

我们对定义在HomeController中的Action方法Index作如下的修改。如代码片段所示,在该方法中,我们利用通过参数注入的ApplicationModelProducer对象根据FoobarController类型创建出对应的ApplicationModel对象,然后利用查询字符串绑定的actionName参数提取出描述对应Action的ActionModel对象。我们将ActionModel对象的Selectors属性提取的选择器列表作为Model呈现在View中。

  1. public class HomeController : Controller
  2. {
  3. [HttpGet("/")]
  4. public IActionResult Index([FromServices]ApplicationModelProducer producer, [FromQuery]string actionName)
  5. {
  6. var applicationModel = producer.Create(typeof(FoobarController));
  7. var actionModel = applicationModel.Controllers.Single().Actions.Single(it=>string.Compare(it.ActionName, actionName, true) == 0);
  8. return View(actionModel.Selectors);
  9. }
  10. }

如下所示的是修改后的View。如代码片段所示,这个是一个Model类型为IList<SelectorModel>的强类型View,我们将提供的用于描述选择器的每个SelectorModel对象的元数据信息呈现在表格中。

  1. @using Microsoft.AspNetCore.Mvc.ApplicationModels;
  2. @model IList<SelectorModel>
  3. <html>
  4. <head>
  5. <title>Selectors</title>
  6. </head>
  7. <body>
  8. <table border="1" cellpadding="0" cellspacing="0">
  9. @for (int i = 0; i < Model.Count; i++)
  10. {
  11. var selector = Model[i];
  12. var constraints = selector.ActionConstraints;
  13. var metadata = selector.EndpointMetadata;
  14. <tr><td colspan="2">Selector @(i+1)</td></tr>
  15. <tr>
  16. <td>AttributeRouteModel</td>
  17. <td>@selector.AttributeRouteModel?.Template</td>
  18. </tr>
  19. <tr>
  20. <td rowspan="@constraints.Count">ActionConstraints</td>
  21. <td>@constraints[0].GetType().Name</td>
  22. </tr>
  23. @for (int j = 1; j < constraints.Count; j++)
  24. {
  25. <tr><td>@constraints[j].GetType().Name</td></tr>
  26. }
  27. <tr>
  28. <td rowspan="@metadata.Count">EndpointMetadata</td>
  29. <td>@metadata[0].GetType().Name</td>
  30. </tr>
  31. @for (int j = 1; j < metadata.Count; j++)
  32. {
  33. <tr><td>@metadata[j].GetType().Name</td></tr>
  34. }
  35. }
  36. </table>
  37. </body>
  38. </html>

由于第一个Action方法Foo上的两个IActionHttpMethodProvider特性并没有提供任何的路由信息,所以它只具有一个AttributeRouteModel属性为Null的SelectorModel对象。这两个特性提供的针对HTTP方法(GET和POST)的约束会转换成一个HttpMethodActionConstraint对象并添加到SelectorModel对象的ActionConstraints属性中。除此之外,这两个特性会直接作为终结点元数据被添加到SelectorModel对象的EndpointMetadata属性中,该属性还会包含一个针对HTTP方法约束的HttpMethodMetada对象。图2所示的就是演示应用返回的针对Action方法Foo的选择器信息。

图2 Action方法Foo的选择器

第二个Action方法Bar上的两个特性均指定了路由模板,所以DefaultApplicationModelProvider会为它创建两个针对性的SelectorModel对象。DefaultApplicationModelProvider会根据特性(HttpGetAttribute和HttpPostAttribute)提供的路由信息来创建对应的AttributeRouteModel对象。SelectorModel对象ActionConstraints属性会包含根据各自提供的HTTP方法约束创建的HttpMethodActionConstraint对象。EndpointMetadata属性将会包含两个终结点元数据对象,分别是当前的特性和根据HTTP方法约束创建的HttpMethodMetada对象。图3所示的就是演示应用返回的针对Action方法Bar的选择器列表。

图3  Action方法Bar的选择器

第三个Action方法方法上标注了三个特性,但是其中只有两个特性提供了路由信息,所以DefaultApplicationModelProvider最终会根据标注的HttpPostAttribute和RouteAttribute特性创建出两个对应的SelectorModel对象。根据标注的HttpPostAttribute特性针对SelectorModel对象的创建与上面一致,所以我们现在只关注针对RouteAttribute特性创建的SelectorModel对象。该对象提供的AttributeRouteModel对象自然由RouteAttribute特性提供的路由信息来创建。

该方法上没有提供路由信息的HttpGetAttribute特性将被用来提供当前路由的约束,所以这个SelectorModel对象的ActionConstraints属性中会包含一个根据这个特性创建的HttpMethodActionConstraint对象。这个SelectorModel对象的EndpointMetadata属性中最终会包含三个终结点元数据,分别是标注的RouteAttribute和HttpGetAttribute特性,以及根据HTTP方法约束创建的HttpMethodMetada对象。图4所示的就是演示应用返回的针对Action方法Baz的选择器列表。

图4  Action方法Bar的选择器

ASP.NET Core MVC应用模型的构建[4]: Action的选择的更多相关文章

  1. ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  2. ASP.NET Core MVC 之模型(Model)

    1.模型绑定 ASP.NET Core MVC 中的模型绑定将数据从HTTP请求映射到操作方法参数.参数既可以是简单类型,也可以是复杂类型.MVC 通过抽象绑定解决了这个问题. 2.使用模型绑定 当 ...

  3. ASP.NET Core MVC/WebAPi 模型绑定探索 转载https://www.cnblogs.com/CreateMyself/p/6246977.html

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  4. 【转】ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  5. ASP.NET MVC和ASP.NET Core MVC中获取当前URL/Controller/Action (转载)

    ASP.NET MVC 一.获取URL(ASP.NET通用): [1]获取完整url(协议名+域名+虚拟目录名+文件名+参数) string url=Request.Url.ToString(); [ ...

  6. ASP.NET Core MVC/WebAPi 模型绑定

    public class Person { public string Name { get; set; } public string Address { get; set; } public in ...

  7. ASP.NET Core MVC 模型绑定用法及原理

    前言 查询了一下关于 MVC 中的模型绑定,大部分都是关于如何使用的,以及模型绑定过程中的一些用法和概念,很少有关于模型绑定的内部机制实现的文章,本文就来讲解一下在 ASP.NET Core MVC ...

  8. Pro ASP.NET Core MVC 第6版 第一章

    目录 第一章 ASP.NET Core MVC 的前世今生 ASP.NET Core MVC 是一个微软公司开发的Web应用程序开发框架,它结合了MVC架构的高效性和简洁性,敏捷开发的思想和技术和.N ...

  9. ASP.NET Core MVC学习笔记

    最近由于疫情紧张,遂在家办公,在领导的带领下,学习了一下.Net Core MVC. 一,构建web应用 1.选择c#-所有平台-web  找到ASP.NET Core web应用程序 2.项目命名之 ...

  10. ASP.NET Core MVC中URL和数据模型的匹配

    Http GET方法 首先我们来看看GET方法的Http请求,URL参数和ASP.NET Core MVC中Controller的Action方法参数匹配情况. 我定义一个UserController ...

随机推荐

  1. [转帖]银河麒麟高级服务器操作系统V10SP1安装Docker管理工具(Portainer+DockerUI)

    文章目录 一.系统环境配置 二.安装Docker 三.安装Docker管理工具 Docker管理工具之Portainer Portainer简介 Portainer安装 Portainer访问测试 D ...

  2. [转贴]英特尔Sapphire Rapids至强可扩展CPU完整型号爆料与路线图展望

    2022-10-13 15:15· 稿源: cnbeta   腾讯云服务器促销:2核2G首年仅需40元 历史新低   @结城安穗-YuuKi_AnS 刚刚在社交媒体上,分享了与英特尔下一代 Sapph ...

  3. 【译文】IEEE白皮书 6G 太赫兹技术的基本原理 2023版

    第一章 简介 太赫兹波是介于微波和光波之间的光谱区域,频率从 0.1THz ~ 10THz 之间,波长在 3mm ~ 30μm 之间.提供大块连续的频带范围以满足对 Tbit/s 内极高数据传输速率的 ...

  4. Redis数据倾斜与JD开源hotkey源码分析揭秘

    1 前言 之前旁边的小伙伴问我热点数据相关问题,在给他粗略地讲解一波redis数据倾斜的案例之后,自己也顺道回顾了一些关于热点数据处理的方法论,同时也想起去年所学习JD开源项目hotkey--专门用来 ...

  5. 【小实验】golang中的字节对齐

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 使用golang来调用SIMD指令,发现程序崩溃了: __ ...

  6. MySQL数据库精选(从入门使用到底层结构)

    基本使用MySQL 通用语法及分类 DDL: 数据定义语言,用来定义数据库对象(数据库.表.字段) DML: 数据操作语言,用来对数据库表中的数据进行增删改 DQL: 数据查询语言,用来查询数据库中表 ...

  7. 从零开始配置 vim(7)——自动命令

    这篇我们来谈论vim一个相当重要的东西--自动命令. 从编程的角度来看,自动命令有点类似于事件响应,或者回调函数之类.当外部发生某些事件的时候,自动执行事先定义好的一组命令. 定义一个自动命令的格式如 ...

  8. 【SpringBoot】AOP默认的动态代理

    分析: 当引入AOP相关依赖后 <dependency> <groupId>org.springframework</groupId> <artifactId ...

  9. 2.6 CE修改器:代码注入功能

    从本关开始,各位会初步接触到CE的反汇编功能,这也是CE最强大的功能之一.在第6关的时候我们说到指针的找法,用基址定位动态地址.但这一关不用指针也可以进行修改,即使对方是动态地址,且功能更加强大.代码 ...

  10. C/C++ Npcap包实现数据嗅探

    npcap 是Nmap自带的一个数据包处理工具,Nmap底层就是使用这个包进行收发包的,该库,是可以进行二次开发的,不过使用C语言开发费劲,在进行渗透任务时,还是使用Python构建数据包高效,这东西 ...