作者:似是故人来 | 来源:互联网 | 2024-12-27 15:26
在前两篇文章中,我们探讨了ControllerDescriptor和ActionDescriptor这两个描述对象,分别对应控制器和操作方法。本文将基于MVC3源码进一步分析ParameterDescriptor,即用于描述Action方法参数的对象,并详细介绍其工作原理。
在之前的讨论中,我们已经初步了解了 ControllerDescriptor 和 ActionDescriptor 的功能和结构。接下来,我们将继续深入探讨 MVC3 源码中的 ParameterDescriptor,重点分析它如何处理 Action 方法的参数。
在 ControllerActionInvoker 类的 InvokeAction 方法中,通过 FindAction 获取到 ActionDescriptor 后,紧接着会调用 GetParameterValues 方法来获取参数值。以下是关键代码片段:
```csharp
IDictionary
parameters = GetParameterValues(controllerContext, actionDescriptor);
```
`GetParameterValues` 方法的具体实现如下:
```csharp
protected virtual IDictionary GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
Dictionary parametersDict = new Dictionary(StringComparer.OrdinalIgnoreCase);
ParameterDescriptor[] parameterDescriptors = actionDescriptor.GetParameters();
foreach (ParameterDescriptor parameterDescriptor in parameterDescriptors) {
parametersDict[parameterDescriptor.ParameterName] = GetParameterValue(controllerContext, parameterDescriptor);
}
return parametersDict;
}
```
`GetParameters` 方法返回一个 `ParameterDescriptor` 对象数组。该方法最终调用的是 ReflectedActionDescriptor 类中的 `LazilyFetchParametersCollection` 方法:
```csharp
private ParameterDescriptor[] LazilyFetchParametersCollection() {
return DescriptorUtil.LazilyFetchOrCreateDescriptors(
ref _parametersCache,
MethodInfo.GetParameters,
parameterInfo => new ReflectedParameterDescriptor(parameterInfo, this));
}
```
ReflectedParameterDescriptor 的构造函数定义如下:
```csharp
public ReflectedParameterDescriptor(ParameterInfo parameterInfo, ActionDescriptor actionDescriptor) {
ParameterInfo = parameterInfo;
_actiOnDescriptor= actionDescriptor;
_bindingInfo = new ReflectedParameterBindingInfo(parameterInfo);
}
```
其中涉及到的 ReflectedParameterBindingInfo 类用于处理参数绑定信息,其构造函数如下:
```csharp
public ReflectedParameterBindingInfo(ParameterInfo parameterInfo) {
_parameterInfo = parameterInfo;
ReadSettingsFromBindAttribute();
}
```
`ReadSettingsFromBindAttribute` 方法读取并解析 `BindAttribute` 特性:
```csharp
private void ReadSettingsFromBindAttribute() {
BindAttribute attr = (BindAttribute)Attribute.GetCustomAttribute(_parameterInfo, typeof(BindAttribute));
if (attr == null) { return; }
_exclude = new ReadOnlyCollection(AuthorizeAttribute.SplitString(attr.Exclude));
_include = new ReadOnlyCollection(AuthorizeAttribute.SplitString(attr.Include));
_prefix = attr.Prefix;
}
```
`BindAttribute` 是一个密封类,继承自 Attribute,用于指定哪些属性应包含或排除在模型绑定之外。它的主要成员包括 `Exclude`、`Include` 和 `Prefix` 属性。
`IsPropertyAllowed` 方法用于判断指定的属性是否应参与绑定:
```csharp
internal static bool IsPropertyAllowed(string propertyName, string[] includeProperties, string[] excludeProperties) {
bool includeProperty = (includeProperties == null) || (includeProperties.Length == 0) || includeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
bool excludeProperty = (excludeProperties != null) && excludeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
return includeProperty && !excludeProperty;
}
```
回到 ReflectedParameterDescriptor 类的 BindingInfo 属性,它返回一个 ReflectedParameterBindingInfo 实例,后者重写了父类 ParameterBindingInfo 中的 Exclude、Include 和 Prefix 属性。
```csharp
private readonly ReflectedParameterBindingInfo _bindingInfo;
public override ParameterBindingInfo BindingInfo {
get { return _bindingInfo; }
}
```
`ParameterBindingInfo` 是一个抽象类,定义了模型绑定的基本属性和行为。子类 `ReflectedParameterBindingInfo` 重写了这些属性,提供了具体的实现。
最后,`IModelBinder` 接口定义了模型绑定的核心方法 `BindModel`,它是 MVC 模型绑定机制的关键部分。
```csharp
public interface IModelBinder {
object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
}
```
通过以上分析可以看出,无论是 ControllerDescriptor、ActionDescriptor 还是 ParameterDescriptor,它们都是为了支持模型绑定而设计的,为 MVC 框架中的数据绑定提供了必要的基础。