ASP.NET Web API 框架研究 Action方法介绍

  在根据请求解析出匹配的Controller类型并创建实例后,要在该Controller类型中的众多Action方法中选择与请求匹配的那一个,并执行,然后返回响应。

  Action方法,其元数据,主要包括,ActionName,参数列表,返回类型,支持的方法,应用其上的特性,如过滤器,HttpMethod,自定义特性。

一、涉及的类及源码分析

  类主要都在System.Web.Http.Controllers命名空间下

ASP.NET Web API 框架研究 Action方法介绍

ASP.NET Web API 框架研究 Action方法介绍

1、HttpActionDescriptor

  是一个抽象类用来描述Controller类型中的每个方法的基本元数据,主要有以下成员:

  属性:

    public abstract string ActionName { get; }     Action名称

    public abstract Type ReturnType { get; }  Action方法返回类型

      public HttpControllerDescriptor ControllerDescriptor  { get; set; }  所属Controller类型的描述符

    public virtual Collection<HttpMethod> SupportedHttpMethods { get; }  Action方法支持的HttpMethod集合,用来根据请求的方法来过滤当前Action方法是否在候选范围

    public HttpConfiguration Configuration  { get; set; }   HttpConfiguration

    public virtual ConcurrentDictionary<object, object> Properties { get; }  属性字典,可以附加任何对象到该属性

  方法:

    public abstract Collection<HttpParameterDescriptor> GetParameters() 返回方法的所有参数描述符HttpParameterDescriptor,其是HttpActionDescriptor重要组成部分

    public virtual Collection<T> GetCustomAttributes<T>() where T : class  返回应用在Action方法上的各种类型的特性,特性是反射获取的,所以会缓存,该方法就是从缓存中返回

    public virtual Collection<T> GetCustomAttributes<T>(bool inherit) where T : class  返回应用在Action方法上的各种类型的特性

    public abstract Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken); 执行方法

    public abstract class HttpActionDescriptor
{
private readonly ConcurrentDictionary<object, object> _properties = new ConcurrentDictionary<object, object>(); private IActionResultConverter _converter;
private readonly Lazy<Collection<FilterInfo>> _filterPipeline;
private FilterGrouping _filterGrouping;
private Collection<FilterInfo> _filterPipelineForGrouping; private HttpConfiguration _configuration;
private HttpControllerDescriptor _controllerDescriptor;
private readonly Collection<HttpMethod> _supportedHttpMethods = new Collection<HttpMethod>(); private HttpActionBinding _actionBinding; private static readonly ResponseMessageResultConverter _responseMessageResultConverter = new ResponseMessageResultConverter();
private static readonly VoidResultConverter _voidResultConverter = new VoidResultConverter(); protected HttpActionDescriptor()
{
_filterPipeline = new Lazy<Collection<FilterInfo>>(InitializeFilterPipeline);
} protected HttpActionDescriptor(HttpControllerDescriptor controllerDescriptor)
: this()
{
if (controllerDescriptor == null)
{
throw Error.ArgumentNull("controllerDescriptor");
} _controllerDescriptor = controllerDescriptor;
_configuration = _controllerDescriptor.Configuration;
} public abstract string ActionName { get; } public HttpConfiguration Configuration
{
get { return _configuration; }
set
{
if (value == null)
{
throw Error.PropertyNull();
}
_configuration = value;
}
} public virtual HttpActionBinding ActionBinding
{
get
{
if (_actionBinding == null)
{
ServicesContainer controllerServices = _controllerDescriptor.Configuration.Services;
IActionValueBinder actionValueBinder = controllerServices.GetActionValueBinder();
HttpActionBinding actionBinding = actionValueBinder.GetBinding(this);
_actionBinding = actionBinding;
}
return _actionBinding;
}
set
{
if (value == null)
{
throw Error.PropertyNull();
}
_actionBinding = value;
}
} public HttpControllerDescriptor ControllerDescriptor
{
get { return _controllerDescriptor; }
set
{
if (value == null)
{
throw Error.PropertyNull();
}
_controllerDescriptor = value;
}
} public abstract Type ReturnType { get; } public virtual IActionResultConverter ResultConverter
{
get
{
if (_converter == null)
{
_converter = GetResultConverter(ReturnType);
}
return _converter;
}
} public virtual Collection<HttpMethod> SupportedHttpMethods
{
get { return _supportedHttpMethods; }
} public virtual ConcurrentDictionary<object, object> Properties
{
get { return _properties; }
} public virtual Collection<T> GetCustomAttributes<T>() where T : class
{
return GetCustomAttributes<T>(inherit: true);
} public virtual Collection<T> GetCustomAttributes<T>(bool inherit) where T : class
{
return new Collection<T>();
} public virtual Collection<IFilter> GetFilters()
{
return new Collection<IFilter>();
} public abstract Collection<HttpParameterDescriptor> GetParameters(); internal static IActionResultConverter GetResultConverter(Type type)
{
if (type != null && type.IsGenericParameter)
{
throw Error.InvalidOperation(SRResources.HttpActionDescriptor_NoConverterForGenericParamterTypeExists, type);
} if (type == null)
{
return _voidResultConverter;
}
else if (typeof(HttpResponseMessage).IsAssignableFrom(type))
{
return _responseMessageResultConverter;
}
else if (typeof(IHttpActionResult).IsAssignableFrom(type))
{
return null;
}
else
{
Type valueConverterType = typeof(ValueResultConverter<>).MakeGenericType(type);
return TypeActivator.Create<IActionResultConverter>(valueConverterType).Invoke();
}
} public abstract Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken); public virtual Collection<FilterInfo> GetFilterPipeline()
{
return _filterPipeline.Value;
} internal FilterGrouping GetFilterGrouping()
{
Collection<FilterInfo> currentFilterPipeline = GetFilterPipeline();
if (_filterGrouping == null || _filterPipelineForGrouping != currentFilterPipeline)
{
_filterGrouping = new FilterGrouping(currentFilterPipeline);
_filterPipelineForGrouping = currentFilterPipeline;
}
return _filterGrouping;
} private Collection<FilterInfo> InitializeFilterPipeline()
{
IEnumerable<IFilterProvider> filterProviders = _configuration.Services.GetFilterProviders(); IEnumerable<FilterInfo> filters = filterProviders.SelectMany(fp => fp.GetFilters(_configuration, this)).OrderBy(f => f, FilterInfoComparer.Instance); filters = RemoveDuplicates(filters.Reverse()).Reverse(); return new Collection<FilterInfo>(filters.ToList());
} private static IEnumerable<FilterInfo> RemoveDuplicates(IEnumerable<FilterInfo> filters)
{
Contract.Assert(filters != null); HashSet<Type> visitedTypes = new HashSet<Type>(); foreach (FilterInfo filter in filters)
{
object filterInstance = filter.Instance;
Type filterInstanceType = filterInstance.GetType(); if (!visitedTypes.Contains(filterInstanceType) || AllowMultiple(filterInstance))
{
yield return filter;
visitedTypes.Add(filterInstanceType);
}
}
} private static bool AllowMultiple(object filterInstance)
{
IFilter filter = filterInstance as IFilter;
return filter == null || filter.AllowMultiple;
}
}

2、ReflectedHttpActionDescriptor

  通过对目标Action方法进行反射来获取元数据,是对一个反射获得的MethodInfo对象的封装。

  继承自抽象类HttpActionDescriptor,重写了属性和方法。具体看代码:

    public class ReflectedHttpActionDescriptor : HttpActionDescriptor
{
private static readonly object[] _empty = new object[]; private readonly Lazy<Collection<HttpParameterDescriptor>> _parameters;
private ParameterInfo[] _parameterInfos; private Lazy<ActionExecutor> _actionExecutor;
private MethodInfo _methodInfo;
private Type _returnType;
private string _actionName;
private Collection<HttpMethod> _supportedHttpMethods; //反射,缓冲提高性能
private object[] _attributeCache;
private object[] _declaredOnlyAttributeCache; private static readonly HttpMethod[] _supportedHttpMethodsByConvention =
{
HttpMethod.Get,
HttpMethod.Post,
HttpMethod.Put,
HttpMethod.Delete,
HttpMethod.Head,
HttpMethod.Options,
new HttpMethod("PATCH")
}; public ReflectedHttpActionDescriptor()
{
_parameters = new Lazy<Collection<HttpParameterDescriptor>>(() => InitializeParameterDescriptors());
_supportedHttpMethods = new Collection<HttpMethod>();
} public ReflectedHttpActionDescriptor(HttpControllerDescriptor controllerDescriptor, MethodInfo methodInfo)
: base(controllerDescriptor)
{
if (methodInfo == null)
{
throw Error.ArgumentNull("methodInfo");
} InitializeProperties(methodInfo);
_parameters = new Lazy<Collection<HttpParameterDescriptor>>(() => InitializeParameterDescriptors());
} public override string ActionName
{
get { return _actionName; }
} public override Collection<HttpMethod> SupportedHttpMethods
{
get { return _supportedHttpMethods; }
} public MethodInfo MethodInfo
{
get { return _methodInfo; }
set
{
if (value == null)
{
throw Error.PropertyNull();
} InitializeProperties(value);
}
} private ParameterInfo[] ParameterInfos
{
get
{
if (_parameterInfos == null)
{
_parameterInfos = _methodInfo.GetParameters();
}
return _parameterInfos;
}
} /// <inheritdoc/>
public override Type ReturnType
{
get { return _returnType; }
} /// <inheritdoc/>
public override Collection<T> GetCustomAttributes<T>(bool inherit)
{
object[] attributes = inherit ? _attributeCache : _declaredOnlyAttributeCache;
return new Collection<T>(TypeHelper.OfType<T>(attributes));
} public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
{
if (controllerContext == null)
{
throw Error.ArgumentNull("controllerContext");
} if (arguments == null)
{
throw Error.ArgumentNull("arguments");
} if (cancellationToken.IsCancellationRequested)
{
return TaskHelpers.Canceled<object>();
} try
{
object[] argumentValues = PrepareParameters(arguments, controllerContext);
return _actionExecutor.Value.Execute(controllerContext.Controller, argumentValues);
}
catch (Exception e)
{
return TaskHelpers.FromError<object>(e);
}
} public override Collection<IFilter> GetFilters()
{
return new Collection<IFilter>(GetCustomAttributes<IFilter>().Concat(base.GetFilters()).ToList());
} public override Collection<HttpParameterDescriptor> GetParameters()
{
return _parameters.Value;
} private void InitializeProperties(MethodInfo methodInfo)
{
_methodInfo = methodInfo;
_parameterInfos = null;
_returnType = GetReturnType(methodInfo);
_actionExecutor = new Lazy<ActionExecutor>(() => InitializeActionExecutor(_methodInfo));
_declaredOnlyAttributeCache = _methodInfo.GetCustomAttributes(inherit: false);
_attributeCache = _methodInfo.GetCustomAttributes(inherit: true);
_actionName = GetActionName(_methodInfo, _attributeCache);
_supportedHttpMethods = GetSupportedHttpMethods(_methodInfo, _attributeCache);
} internal static Type GetReturnType(MethodInfo methodInfo)
{
Type result = methodInfo.ReturnType;
if (typeof(Task).IsAssignableFrom(result))
{
result = TypeHelper.GetTaskInnerTypeOrNull(methodInfo.ReturnType);
}
if (result == typeof(void))
{
result = null;
}
return result;
} private Collection<HttpParameterDescriptor> InitializeParameterDescriptors()
{
Contract.Assert(_methodInfo != null); List<HttpParameterDescriptor> parameterInfos = ParameterInfos.Select(
(item) => new ReflectedHttpParameterDescriptor(this, item)).ToList<HttpParameterDescriptor>();
return new Collection<HttpParameterDescriptor>(parameterInfos);
} private object[] PrepareParameters(IDictionary<string, object> parameters, HttpControllerContext controllerContext)
{
// This is on a hotpath, so a quick check to avoid the allocation if we have no parameters.
if (_parameters.Value.Count == )
{
return _empty;
} ParameterInfo[] parameterInfos = ParameterInfos;
int parameterCount = parameterInfos.Length;
object[] parameterValues = new object[parameterCount];
for (int parameterIndex = ; parameterIndex < parameterCount; parameterIndex++)
{
parameterValues[parameterIndex] = ExtractParameterFromDictionary(parameterInfos[parameterIndex], parameters, controllerContext);
}
return parameterValues;
} private object ExtractParameterFromDictionary(ParameterInfo parameterInfo, IDictionary<string, object> parameters, HttpControllerContext controllerContext)
{
object value; if (!parameters.TryGetValue(parameterInfo.Name, out value))
{
// the key should always be present, even if the parameter value is null
throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest,
SRResources.BadRequest,
Error.Format(SRResources.ReflectedActionDescriptor_ParameterNotInDictionary,
parameterInfo.Name, parameterInfo.ParameterType, MethodInfo, MethodInfo.DeclaringType)));
} if (value == null && !TypeHelper.TypeAllowsNullValue(parameterInfo.ParameterType))
{
// tried to pass a null value for a non-nullable parameter type
throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest,
SRResources.BadRequest,
Error.Format(SRResources.ReflectedActionDescriptor_ParameterCannotBeNull,
parameterInfo.Name, parameterInfo.ParameterType, MethodInfo, MethodInfo.DeclaringType)));
} if (value != null && !parameterInfo.ParameterType.IsInstanceOfType(value))
{
// value was supplied but is not of the proper type
throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest,
SRResources.BadRequest,
Error.Format(SRResources.ReflectedActionDescriptor_ParameterValueHasWrongType,
parameterInfo.Name, MethodInfo, MethodInfo.DeclaringType, value.GetType(), parameterInfo.ParameterType)));
} return value;
} private static string GetActionName(MethodInfo methodInfo, object[] actionAttributes)
{
ActionNameAttribute nameAttribute = TypeHelper.OfType<ActionNameAttribute>(actionAttributes).FirstOrDefault();
return nameAttribute != null
? nameAttribute.Name
: methodInfo.Name;
} private static Collection<HttpMethod> GetSupportedHttpMethods(MethodInfo methodInfo, object[] actionAttributes)
{
Collection<HttpMethod> supportedHttpMethods = new Collection<HttpMethod>();
ICollection<IActionHttpMethodProvider> httpMethodProviders = TypeHelper.OfType<IActionHttpMethodProvider>(actionAttributes);
if (httpMethodProviders.Count > )
{
// Get HttpMethod from attributes
foreach (IActionHttpMethodProvider httpMethodSelector in httpMethodProviders)
{
foreach (HttpMethod httpMethod in httpMethodSelector.HttpMethods)
{
supportedHttpMethods.Add(httpMethod);
}
}
}
else
{
// Get HttpMethod from method name convention
for (int i = ; i < _supportedHttpMethodsByConvention.Length; i++)
{
if (methodInfo.Name.StartsWith(_supportedHttpMethodsByConvention[i].Method, StringComparison.OrdinalIgnoreCase))
{
supportedHttpMethods.Add(_supportedHttpMethodsByConvention[i]);
break;
}
}
} if (supportedHttpMethods.Count == )
{
// Use POST as the default HttpMethod
supportedHttpMethods.Add(HttpMethod.Post);
} return supportedHttpMethods;
} public override int GetHashCode()
{
if (_methodInfo != null)
{
return _methodInfo.GetHashCode();
} return base.GetHashCode();
} /// <inheritdoc />
public override bool Equals(object obj)
{
if (_methodInfo != null)
{
ReflectedHttpActionDescriptor otherDescriptor = obj as ReflectedHttpActionDescriptor;
if (otherDescriptor == null)
{
return false;
} return _methodInfo.Equals(otherDescriptor._methodInfo);
} return base.Equals(obj);
} private static ActionExecutor InitializeActionExecutor(MethodInfo methodInfo)
{
if (methodInfo.ContainsGenericParameters)
{
throw Error.InvalidOperation(SRResources.ReflectedHttpActionDescriptor_CannotCallOpenGenericMethods,
methodInfo, methodInfo.ReflectedType.FullName);
} return new ActionExecutor(methodInfo);
}
}

  其还有个内部类,先列出,平时多看看:

 private sealed class ActionExecutor
{
private readonly Func<object, object[], Task<object>> _executor;
private static MethodInfo _convertOfTMethod = typeof(ActionExecutor).GetMethod("Convert", BindingFlags.Static | BindingFlags.NonPublic); public ActionExecutor(MethodInfo methodInfo)
{
Contract.Assert(methodInfo != null);
_executor = GetExecutor(methodInfo);
} public Task<object> Execute(object instance, object[] arguments)
{
return _executor(instance, arguments);
} // Method called via reflection.
private static Task<object> Convert<T>(object taskAsObject)
{
Task<T> task = (Task<T>)taskAsObject;
return task.CastToObject<T>();
} private static Func<object, Task<object>> CompileGenericTaskConversionDelegate(Type taskValueType)
{
Contract.Assert(taskValueType != null); return (Func<object, Task<object>>)Delegate.CreateDelegate(typeof(Func<object, Task<object>>), _convertOfTMethod.MakeGenericMethod(taskValueType));
} private static Func<object, object[], Task<object>> GetExecutor(MethodInfo methodInfo)
{
// Parameters to executor
ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");
ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); // Build parameter list
List<Expression> parameters = new List<Expression>();
ParameterInfo[] paramInfos = methodInfo.GetParameters();
for (int i = ; i < paramInfos.Length; i++)
{
ParameterInfo paramInfo = paramInfos[i];
BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
UnaryExpression valueCast = Expression.Convert(valueObj, paramInfo.ParameterType); // valueCast is "(Ti) parameters[i]"
parameters.Add(valueCast);
} // Call method
UnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(instanceParameter, methodInfo.ReflectedType) : null;
MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters); // methodCall is "((MethodInstanceType) instance).method((T0) parameters[0], (T1) parameters[1], ...)"
// Create function
if (methodCall.Type == typeof(void))
{
// for: public void Action()
Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(methodCall, instanceParameter, parametersParameter);
Action<object, object[]> voidExecutor = lambda.Compile();
return (instance, methodParameters) =>
{
voidExecutor(instance, methodParameters);
return TaskHelpers.NullResult();
};
}
else
{
// must coerce methodCall to match Func<object, object[], object> signature
UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceParameter, parametersParameter);
Func<object, object[], object> compiled = lambda.Compile();
if (methodCall.Type == typeof(Task))
{
// for: public Task Action()
return (instance, methodParameters) =>
{
Task r = (Task)compiled(instance, methodParameters);
ThrowIfWrappedTaskInstance(methodInfo, r.GetType());
return r.CastToObject();
};
}
else if (typeof(Task).IsAssignableFrom(methodCall.Type))
{
// for: public Task<T> Action()
// constructs: return (Task<object>)Convert<T>(((Task<T>)instance).method((T0) param[0], ...))
Type taskValueType = TypeHelper.GetTaskInnerTypeOrNull(methodCall.Type);
var compiledConversion = CompileGenericTaskConversionDelegate(taskValueType); return (instance, methodParameters) =>
{
object callResult = compiled(instance, methodParameters);
Task<object> convertedResult = compiledConversion(callResult);
return convertedResult;
};
}
else
{
// for: public T Action()
return (instance, methodParameters) =>
{
var result = compiled(instance, methodParameters);
// Throw when the result of a method is Task. Asynchronous methods need to declare that they
// return a Task.
Task resultAsTask = result as Task;
if (resultAsTask != null)
{
throw Error.InvalidOperation(SRResources.ActionExecutor_UnexpectedTaskInstance,
methodInfo.Name, methodInfo.DeclaringType.Name);
}
return Task.FromResult(result);
};
}
}
} private static void ThrowIfWrappedTaskInstance(MethodInfo method, Type type)
{
// Throw if a method declares a return type of Task and returns an instance of Task<Task> or Task<Task<T>>
// This most likely indicates that the developer forgot to call Unwrap() somewhere.
Contract.Assert(method.ReturnType == typeof(Task));
// Fast path: check if type is exactly Task first.
if (type != typeof(Task))
{
Type innerTaskType = TypeHelper.GetTaskInnerTypeOrNull(type);
if (innerTaskType != null && typeof(Task).IsAssignableFrom(innerTaskType))
{
throw Error.InvalidOperation(SRResources.ActionExecutor_WrappedTaskInstance,
method.Name, method.DeclaringType.Name, type.FullName);
}
}
}
}

3、ActionNameAttribute

  一般Acton方法的名字默认作为Action名称,其作为路由模板一部分,为了优化,经常要修改方法名,为了方便灵活修改,提供一个ActionNameAttribute自定义特性来定义一个与方法名不同的Action名称。

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class ActionNameAttribute : Attribute
{
public ActionNameAttribute(string name)
{
Name = name;
} public string Name { get; private set; }
}

  使用:

  [ActionName("MyActionName")]

  public void ActionMethod()

4、AcceptVerbsAttribute  IActionHttpMethodProvider

  “Action方法名称决定支持的Http方法“ ----- Action支持的Http方法的默认策略。

  默认情况一个Action方法默认只支持一个HttpMethod,不指定,默认就是Post。

  根据默认策略,Action方法名称前缀是某个HttpMethod(不区分大小写),就默认支持对应的HttpMethod方法,如GetABC,就默认支持Get(唯一),没有这种前缀,就默认是Post,如Action方法名为Other。

  而IActionHttpMethodProvider提供一种自定义支持方法(可多个)的方式,它是通过自定义特性的方式,用在Action方法上。

 public interface IActionHttpMethodProvider
{
Collection<HttpMethod> HttpMethods { get; }
}

  ASP.NET Web API提供了一个默认实现AcceptVerbsAttribute

 public sealed class AcceptVerbsAttribute : Attribute, IActionHttpMethodProvider
{
private readonly Collection<HttpMethod> _httpMethods; public AcceptVerbsAttribute(string method)
: this(new string[] { method })
{
} public AcceptVerbsAttribute(params string[] methods)
{
_httpMethods = methods != null
? new Collection<HttpMethod>(methods.Select(method => HttpMethodHelper.GetHttpMethod(method)).ToArray())
: new Collection<HttpMethod>(new HttpMethod[]);
} internal AcceptVerbsAttribute(params HttpMethod[] methods)
{
_httpMethods = new Collection<HttpMethod>(methods);
} public Collection<HttpMethod> HttpMethods
{
get
{
return _httpMethods;
}
}
}

  使用方式:

  [AcceptVerbsAttribute("PUT","POST")]

  public void ActionMethod()

  为了字符串书写错误,框架里又提供了七种方法对应的特性,HttpGetAtrribute,HttpPostAtrribute,HttpPutAtrribute,HttpDeleteAtrribute,HttpHeadAtrribute,HttpOptionsAtrribute,HttpPatchAtrribute。

  同样可以指定多个:

  [HttpPut]

  [HttpPost]

  public void ActionMethod()

 5、HttpParameterDescriptor  

  是个抽象类,第三个描述对象,前边介绍了HttpControllerDescriptor和HttpActionDescriptor,对Action方法的每个参数都通过HttpParameterDescriptor进行描述,主要成员如下:

  属性:

    public HttpActionDescriptor ActionDescriptor 所在Action方法的描述符

    public HttpConfiguration Configuration  { get; set; }   与HttpActionDescriptor 的HttpActionDescriptor同名属性有相同引用

    public ConcurrentDictionary<object, object> Properties 字典属性,附加任何对象 

    public virtual object DefaultValue { get; }  默认值

    public abstract string ParameterName { get; } 参数名称

    public abstract Type ParameterType { get; } 参数类型

    public virtual bool IsOptional  { get; }  是否可选参数,默认不是

  方法:

     public virtual Collection<T> GetCustomAttributes<T>() where T : class   返回参数上定义的一个或多个特性

 public abstract class HttpParameterDescriptor
{
private readonly ConcurrentDictionary<object, object> _properties = new ConcurrentDictionary<object, object>(); private ParameterBindingAttribute _parameterBindingAttribute;
private bool _searchedModelBinderAttribute;
private HttpConfiguration _configuration;
private HttpActionDescriptor _actionDescriptor; protected HttpParameterDescriptor()
{
} protected HttpParameterDescriptor(HttpActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
{
throw Error.ArgumentNull("actionDescriptor");
} _actionDescriptor = actionDescriptor;
_configuration = _actionDescriptor.Configuration;
} public HttpConfiguration Configuration
{
get { return _configuration; }
set
{
if (value == null)
{
throw Error.PropertyNull();
}
_configuration = value;
}
} public HttpActionDescriptor ActionDescriptor
{
get { return _actionDescriptor; }
set
{
if (value == null)
{
throw Error.PropertyNull();
}
_actionDescriptor = value;
}
} public ConcurrentDictionary<object, object> Properties
{
get { return _properties; }
} public virtual object DefaultValue
{
get { return null; }
} public abstract string ParameterName { get; } public abstract Type ParameterType { get; } public virtual string Prefix
{
get
{
ParameterBindingAttribute attribute = ParameterBinderAttribute;
ModelBinderAttribute modelAttribute = attribute as ModelBinderAttribute;
return modelAttribute != null
? modelAttribute.Name
: null;
}
} public virtual bool IsOptional
{
get { return false; }
} /// <summary>
/// Return a <see cref="ParameterBindingAttribute"/> if present on this parameter's signature or declared type.
/// Returns null if no attribute is specified.
/// </summary>
public virtual ParameterBindingAttribute ParameterBinderAttribute
{
get
{
if (_parameterBindingAttribute == null)
{
if (!_searchedModelBinderAttribute)
{
_searchedModelBinderAttribute = true;
_parameterBindingAttribute = FindParameterBindingAttribute();
}
} return _parameterBindingAttribute;
} set { _parameterBindingAttribute = value; }
} public virtual Collection<T> GetCustomAttributes<T>() where T : class
{
return new Collection<T>();
} private ParameterBindingAttribute FindParameterBindingAttribute()
{
// Can be on parameter itself or on the parameter's type. Nearest wins.
return ChooseAttribute(GetCustomAttributes<ParameterBindingAttribute>())
?? ChooseAttribute(ParameterType.GetCustomAttributes<ParameterBindingAttribute>(false));
} private static ParameterBindingAttribute ChooseAttribute(IList<ParameterBindingAttribute> list)
{
if (list.Count == )
{
return null;
}
if (list.Count > )
{
// Multiple attributes specified at the same level
return new AmbiguousParameterBindingAttribute();
}
return list[];
} private sealed class AmbiguousParameterBindingAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
string message = Error.Format(SRResources.ParameterBindingConflictingAttributes, parameter.ParameterName);
return parameter.BindAsError(message);
}
}
}

6、ReflectedHttpParameterDescriptor

  继承自抽象类HttpParameterDescriptor,通过反射提取描述参数的元数据,主要是通过反射获取的ParameterInfo对象提供,通过构造函数传入。ParameterInfo是关键,参数的基本数据(ParamterName, ParameterType,DefaultValue,IsOptional),以及定义在参数上的特性(GetCustomAttributes<T>)方法都是通过其提供。

  另外,ReflectedHttpActionDescriptor的GetParameters返回的是ReflectedHttpParameterDescriptor列表,且ParameterInfo是通过反射出来的MethodInfo的GetParameters方法获取的。

    public class ReflectedHttpParameterDescriptor : HttpParameterDescriptor
{
private ParameterInfo _parameterInfo; public ReflectedHttpParameterDescriptor(HttpActionDescriptor actionDescriptor, ParameterInfo parameterInfo)
: base(actionDescriptor)
{
if (parameterInfo == null)
{
throw Error.ArgumentNull("parameterInfo");
} ParameterInfo = parameterInfo;
} public ReflectedHttpParameterDescriptor()
{
} public override object DefaultValue
{
get
{
object value;
if (ParameterInfo.TryGetDefaultValue(out value))
{
return value;
}
else
{
return base.DefaultValue;
}
}
} public ParameterInfo ParameterInfo
{
get { return _parameterInfo; }
set
{
if (value == null)
{
throw Error.PropertyNull();
}
_parameterInfo = value;
}
} public override bool IsOptional
{
get { return ParameterInfo.IsOptional; }
} public override string ParameterName
{
get { return ParameterInfo.Name; }
} public override Type ParameterType
{
get { return ParameterInfo.ParameterType; }
} public override Collection<TAttribute> GetCustomAttributes<TAttribute>()
{
return new Collection<TAttribute>((TAttribute[])ParameterInfo.GetCustomAttributes(typeof(TAttribute), inherit: false));
}
}
上一篇:小解系列-自关联对象.Net MVC中 json序列化循环引用问题


下一篇:均方根误差(RMSE),平均绝对误差(MAE),标准差(Standard Deviation)