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

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

一、涉及的类及源码分析

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

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));
}
}

ASP.NET Web API 框架研究 Action方法介绍的更多相关文章

  1. ASP.NET Web API 框架研究 Action的选择

    如何从HttpController众多方法里如何选择出有效的Action方法?主要分一下几个步骤: 首先,获取候选HttpActionDescriptor列表(ILookup(string,HttpA ...

  2. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  3. ASP.NET Web API 框架研究 服务容器 ServicesContainer

    ServicesContainer是一个服务的容器,可以理解为—个轻量级的IoC容器,其维护着一个服务接口类型与服务实例之间的映射关系,可以根据服务接口类型获取对应的服务实例.构成ASP.NET We ...

  4. ASP.NET Web API 框架研究 核心的消息处理管道

    ASP.NET Web API 的核心框架是一个由一组HttpMessageHandler有序组成的双工消息处理管道:寄宿监听到请求接受后,把消息传入该管道经过所有HttpMessageHandler ...

  5. ASP.NET Web API 框架研究 Controller实例的销毁

    我们知道项目中创建的Controller,如ProductController都继承自ApiController抽象类,其又实现了接口IDisposable,所以,框架中自动调用Dispose方法来释 ...

  6. ASP.NET Web API 框架研究 Self Host模式下的消息处理管道

    Self Host模式下的ASP.NET Web API与WCF非常相似,都可以寄宿在任意类型的托管应用程序中,宿主可以是Windows Form .WPF.控制台应用以及Windows Servic ...

  7. ASP.NET Web API 框架研究 Web Host模式下的消息处理管道

    寄宿的作用是开启一个进程为Web API提供一个运行环境以解决持续监听.请求监听和响应回复,即将接收到的请求转换成HttpRequestMessage对象传入管道,并将管道生成并经过处理后的HttpR ...

  8. ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道

    Web Host 模式下的路由本质上还是通过ASP.NET 路由系统来进行路由的,只是通过继承和组合的方式对ASP.NET路由系统的内部的类进行了一些封装,产生自己专用一套类结构,功能逻辑基本都是一样 ...

  9. ASP.NET Web API 框架研究 ASP.NET 路由

    ASP.NET Web API 如果采用Web Host方式来寄宿,在请求进入Web API 消息处理管道之前,就会用ASP.NET 自身的路由系统根据注册的路由表,解析出当前请求的HttpContr ...

随机推荐

  1. Two Sum LT1

    Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...

  2. Minimum Window Substring LT76

    Given a string S and a string T, find the minimum window in S which will contain all the characters ...

  3. zookeeper相关

    1.zookeeper应用:集群节点间的数据同步(资源管理),分布式锁(主要是利用客户端在一个会话中在zookeeper中创建一个znode节点,然后再去执行自己的业务代码,比如去更新数据库,其他客户 ...

  4. java学习第六周

    这是暑假学习的第六周,在这周我练习了老师给的例题,还是有一些地方看不懂,这周我对那些不懂的地方用看视频来进行解答,以及进行第二次复习. 下周我会对Java进行更加详细的复习,做好笔记,在LeetCod ...

  5. kbmmw 中JSON 中使用SQL 查询

    前面讲到了kbmmw 的JSON 对象操作,如何快速的查找JSON 中的值? 一种办法就是通过遍历的方法,其实在kbmmw 还有一种灵活的查询方式, 就是通过SQL 方式查询JSON 中的值.也就是说 ...

  6. AOP的异常通知

      一.配置异常通知的步骤 (Aspectj方式) 1.只有当切点报异常才能触发异常通知 2.在spring中有Aspectj 方式提供了异常通知方法 2.1 如果希望通过 schema-base 实 ...

  7. 219.01.19 bzoj3252: 攻略(长链剖分+贪心)

    传送门 长链剖分好题. 题意:给一棵带点权的树,可以从根节点到任一叶节点走kkk次,走过的点只能计算一次,问kkk次走过的点点权值和最大值. 思路: 考虑将整棵树带权长链剖分,这样链与链之间是不会重复 ...

  8. SVD(6.5.1定理证明观察3)

  9. python,函数

    numpy.tile():参考https://www.jianshu.com/p/4b74a367833c numpy.argsort:argsort()里面传入参数只有数组时,返回的是数组值从小到大 ...

  10. 乌龙之MySQL slave IO status:connecting

    搭建了一个主从,状态一直如下: 检查错误日志报错如下: review搭建过程,语法并没有问题. 检查用户及网络,也没有问题: so?what is the cause ? 等等....貌似上面搭建用的 ...