在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
在根据请求解析出匹配的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[0]; 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 == 0) { return _empty; } ParameterInfo[] parameterInfos = ParameterInfos; int parameterCount = parameterInfos.Length; object[] parameterValues = new object[parameterCount]; for (int parameterIndex = 0; 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 > 0) { // 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 = 0; i < _supportedHttpMethodsByConvention.Length; i++) { if (methodInfo.Name.StartsWith(_supportedHttpMethodsByConvention[i].Method, StringComparison.OrdinalIgnoreCase)) { supportedHttpMethods.Add(_supportedHttpMethodsByConvention[i]); break; } } } if (supportedHttpMethods.Count == 0) { // 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 = 0; 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) => { 全部评论
专题导读
上一篇:原创:分享asp.net伪静态成目录形式iis如何设置iis6伪静态iis配置方法图解 ...发布时间:2022-07-10下一篇:一、在ASP.NETCore中使用SignalR发布时间:2022-07-10热门推荐
热门话题
阅读排行榜
|
请发表评论