上一篇介绍了HttpController的一些细节,接下来说下HttpController 类型解析、选择和创建。生产HttpController实例的生产线如下图:

  

一、涉及的类及源码分析

  涉及的类主要在程序集System.Web.Http中的Dispatcher下边,类如下图:

  

1、IAssembliesResolver DefaultAssembliesResolver

  AssembliesResolver为HttpController类型的解析提供了可选的程序集,即提供了实现了IHttpController接口的候选HttpController类型的程序集范围;所有AssembliesResolver都实现IAssembliesResolver,接口只有一个方法,如下

  public interface IAssembliesResolver
{
//提供解析的程序集范围,返回应用程序可用的程序集列表
ICollection<Assembly> GetAssemblies();
}

  默认实现是DefauItAssembliesResolver,DefauItAssembliesResolver在实现的GetAssembIies方法中直接返回当前应用程序域加载的所有程序集列表,代码如下

  public class DefaultAssembliesResolver : IAssembliesResolver
{
public virtual ICollection<Assembly> GetAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies().ToList();
}
}

  而服务接口IAssembliesResolver的服务实例DefauItAssembliesResolver,是在服务容器里注册的

  获取可以用扩展方法直接获取:

  

 

 2、IHttpControllerTypeResolver DefaultHttpControllerTypeResolver

  返回可供选择的HttpControllerType列表。

  前边的AssembIiesResolver对象为HttpController类型的解析提供了可供选择的程序集,而HttpControllerTypeResolver具体进行类型解析,其均实现了接口IHttpControllerTypeResolver,其只有一个方法GetControllerTypes,而且以IAssembIiesResolver为参数,提供类型程序集。如下:

   public interface IHttpControllerTypeResolver
{
//参数IAssembliesResolver提供解析的程序集
ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver);
}

  即根据提供的程序集参数,获取所有符合条件的HttpControllerType列表,现在还没解析完,后续还要从其中选择一个合适的,只是返回可供选择的列表,默认实现是DefaultHttpControllerTypeResolver。

  注意点:

  • 委托 Predicate<Type>,Func<Assembly, Type[]>这种函数式编程用法,把函数当属性和参数
  • 只是从多个指定程序集中返回可供选择的HttpControllerType列表,还不是最后解析出的类型
  • 判断HttpController类型有效规则,即外部可见 (IsVisibIe=true)的实例 (IsAbstract=false)类 (IsClass=true),直接或耆间接实现了接口IHttpController,类型名称必须以“Controller” 为后缀,但是不区分大小写 (即 可以使用 “controIler” 作为后缀 )。
public class DefaultHttpControllerTypeResolver : IHttpControllerTypeResolver
{
//判断是否为有效Controller的委托,默认指定了IsControllerType,也可以在构造函数指定
private readonly Predicate<Type> _isControllerTypePredicate;
//从程序集获取Type[]的委托,可以直接属性设置
private Func<Assembly, Type[]> _getTypesFunc = GetTypes; //构造函数,可以指定一个委托来判断是不是控制器类型,默认使用下边的IsControllerType
public DefaultHttpControllerTypeResolver()
: this(IsControllerType)
{
} //构造函数,可以指定一个委托来判断是不是控制器类型
public DefaultHttpControllerTypeResolver(Predicate<Type> predicate)
{
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
} _isControllerTypePredicate = predicate;
} //只读,否为有效Controller的委托
protected internal virtual Predicate<Type> IsControllerTypePredicate
{
get { return _isControllerTypePredicate; }
} //默认的用来判断是否是控制器的委托predicate
internal static bool IsControllerType(Type t)
{
Contract.Assert(t != null);
return
t != null &&
t.IsClass &&
t.IsVisible &&
!t.IsAbstract &&
typeof(IHttpController).IsAssignableFrom(t) &&
HasValidControllerName(t);
} //返回可用的控制器列表
public virtual ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
{
if (assembliesResolver == null)
{
throw Error.ArgumentNull("assembliesResolver");
} List<Type> result = new List<Type>(); // 从assembliesResolver获取所有程序集
ICollection<Assembly> assemblies = assembliesResolver.GetAssemblies();
//遍历每个程序集
foreach (Assembly assembly in assemblies)
{
Type[] exportedTypes = null;
if (assembly == null || assembly.IsDynamic)
{
// 空或动态程序集就继续下个程序集,不操作当前程序集
continue;
} try
{
//从程序集中获取Type[]
exportedTypes = _getTypesFunc(assembly);
}
catch (ReflectionTypeLoadException ex)
{
exportedTypes = ex.Types;
}
catch
{
//忽略异常,继续解析,不影响最后结果,除非找不到NOT FOUND
continue;
} if (exportedTypes != null)
{
//从Type[]中把有效的ControllerType存放到结果列表中
result.AddRange(exportedTypes.Where(x => TypeIsVisible(x) && IsControllerTypePredicate(x)));
}
} return result;
} //默认使用的从程序集获取Type[]
internal static Type[] GetTypes(Assembly assembly)
{
return assembly.GetTypes();
} // 要以Controller结尾,但不能就是Controller,因为路由解析的控制器也不会为空
internal static bool HasValidControllerName(Type controllerType)
{
Contract.Assert(controllerType != null);
string controllerSuffix = DefaultHttpControllerSelector.ControllerSuffix;
return controllerType.Name.Length > controllerSuffix.Length && controllerType.Name.EndsWith(controllerSuffix, StringComparison.OrdinalIgnoreCase);
} //设置从程序集获取Type[]的委托
internal void SetGetTypesFunc(Func<Assembly, Type[]> getTypesFunc)
{
_getTypesFunc = getTypesFunc;
} private static bool TypeIsVisible(Type type)
{
//IsVisible是不是可以由程序集代码外访问
return (type != null && type.IsVisible);
}
}

  

  其也可以通过ServicesContainer扩展方法直接获取:

  

3、HttpControllerTypeCache

  用来缓存反射出来的HttpControllerType,提高性能,是对HttpControllerTypeResolver解析出来的HttpController类型列表的缓存。

  缓存是一个Dictionary<string, ILookup<string, Type>>字典类型,Key为去除Controller后的部分,不区分大小写,如ProductController,Key为"Producct",Value为一个 ILookup<string, Type>类型,其Key可以重复,Key为控制器所在的命名空间,如ProductController所在命名空间"MyNameSpace",Value为具体的控制器类型如"ProductController"。

  注意:

  相同名称的控制器可能存在不同程序集和不同命名空间下

internal sealed class HttpControllerTypeCache
{
private readonly HttpConfiguration _configuration;
//惰性加载,缓存,Key为控制器名称出去Controller的部分(不区分大小写),
//Value为一个ILookup<string, Type>,其Key可以重复,为控制所在的命名空间,Value为对应的控制器类型
//相同名称的控制器可能存在不同程序集和不同命名空间下
private readonly Lazy<Dictionary<string, ILookup<string, Type>>> _cache; public HttpControllerTypeCache(HttpConfiguration configuration)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
} _configuration = configuration;
_cache = new Lazy<Dictionary<string, ILookup<string, Type>>>(InitializeCache);
} //由于使用Lazy,调用该属性时候,才调用下边的InitializeCache
internal Dictionary<string, ILookup<string, Type>> Cache
{
get { return _cache.Value; }
} //根据控制器名称获取可选的ControllerType列表,从缓存读取
public ICollection<Type> GetControllerTypes(string controllerName)
{
if (String.IsNullOrEmpty(controllerName))
{
throw Error.ArgumentNullOrEmpty("controllerName");
} HashSet<Type> matchingTypes = new HashSet<Type>(); ILookup<string, Type> namespaceLookup;
if (_cache.Value.TryGetValue(controllerName, out namespaceLookup))
{
foreach (var namespaceGroup in namespaceLookup)
{
matchingTypes.UnionWith(namespaceGroup);
}
} return matchingTypes;
} //初始化缓存
private Dictionary<string, ILookup<string, Type>> InitializeCache()
{
//获取AssembliesResolver服务实例
IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver();
//获取ControllersResolver服务实例
IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();
//调用ControllersResolver.GetControllerTypes以assembliesResolver为参数获取ControllerType列表
ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
//先对解析出来的ControllerType列表按照ControllerType去除Controller后的名称分组,不区分大小写(OrdinalIgnoreCase)
var groupedByName = controllerTypes.GroupBy(
t => t.Name.Substring(, t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length),
StringComparer.OrdinalIgnoreCase);
//再转换成Dictionary<string, ILookup<string, Type>>缓存结构
return groupedByName.ToDictionary(
g => g.Key,
g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
StringComparer.OrdinalIgnoreCase);
}
}

4、IHttpControllerSelector DefaultHttpControllerSelector

  HttpControllerTypeResolver只是解析出所有合法的ControllerType列表,接下来要根据请求选择出匹配的HttpController类型。

  通过HttpControllerSelector来完成,其都实现接口IHttpControllerSelector,其主要有两个方法,如下:

 public interface IHttpControllerSelector
{
//根据请求选择一个匹配的控制器对应的描述符
HttpControllerDescriptor SelectController(HttpRequestMessage request); //返回描述所有HttpController类型的HttpControllerDescriptor对象与对应的HttpController名称之间的映射夫系
IDictionary<string, HttpControllerDescriptor> GetControllerMapping();
}

  同前边,默认实现DefaultHttpControllerSelector,也是是在服务容器里注册的,且同

  

  

  主要逻辑:

  • 控制器名称获取,不管Web Host还是Self Host路由解析数据最后都是放在HttpRequestMessage的属性字典中,所以先从请求中获取路由数据,再得到controller名称。如果路由变量中不存在名为controller的数据,或者程序集不存在或存在多个ControllerType,都会抛出异常
  • 丢弃在不同命名空间有多个匹配结果的控制器,比如,对于product名称的控制器,在A名称空间和B命名空间都有ProductController,由于系统不知道激活哪一个,所以采用的策略是两个都丢弃。这个逻辑在方法GetControllerMapping()
  • 系统会对GetControllerMapping结果缓存,我们在HttpControllerTypeResolver阶段解析出来的ControllerType在不同命名空间中存在多个匹配的控制器,所以采用Dictionary<string, ILookup<string, Type>>缓存,而GetControllerMapping返回的是IDictionary<string, HttpControllerDescriptor>类型,会丢弃上一点中的重复的控制器,返回的都是唯一的结果
  • 有两个缓存结构,一个是HttpControllerTypeCache 存放了所有合法的ControllerType,另一个是Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache,它是根据前者构建出来的
  • 编程技巧,使用Lazy,Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache,在从缓存_controllerInfoCache里读取数据时候,才去构建缓存内容,详细见代码注释
public class DefaultHttpControllerSelector : IHttpControllerSelector
{
public static readonly string ControllerSuffix = "Controller"; private const string ControllerKey = "controller"; private readonly HttpConfiguration _configuration;
//ControllerType缓存
private readonly HttpControllerTypeCache _controllerTypeCache;
private readonly Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache; public DefaultHttpControllerSelector(HttpConfiguration configuration)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
}
//Lazy惰性加载,用到_controllerInfoCache时候才去执行InitializeControllerInfoCache,进行缓存数据构建
_controllerInfoCache = new Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>>(InitializeControllerInfoCache);
_configuration = configuration;
_controllerTypeCache = new HttpControllerTypeCache(_configuration);
} //从请求中匹配指定控制器名称的控制器描述符号,从缓存中读取,缓存构建时机是在读取缓存时候,使用Lazy实现
public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
} IHttpRouteData routeData = request.GetRouteData();
HttpControllerDescriptor controllerDescriptor;
if (routeData != null)
{
//先按特性路由(以后再说)解析,如果解析出数据,就直接返回
controllerDescriptor = GetDirectRouteController(routeData);
if (controllerDescriptor != null)
{
return controllerDescriptor;
}
}
//非特性路由则
//从HttpRequestMessage属性字典中获取控制器名称,获取不到就NotFound
string controllerName = GetControllerName(request);
if (String.IsNullOrEmpty(controllerName))
{
throw new HttpResponseException(request.CreateErrorResponse(
HttpStatusCode.NotFound,
Error.Format(SRResources.ResourceNotFound, request.RequestUri),
Error.Format(SRResources.ControllerNameNotFound, request.RequestUri)));
}
//从控制器描述符缓存中获取,找到就直接返回,在此Lazy惰性加载,才去执行InitializeControllerInfoCache,进行缓存数据构建
if (_controllerInfoCache.Value.TryGetValue(controllerName, out controllerDescriptor))
{
return controllerDescriptor;
} //找不到就根据实际情况,抛出不同异常
ICollection<Type> matchingTypes = _controllerTypeCache.GetControllerTypes(controllerName); // ControllerInfoCache is already initialized.
Contract.Assert(matchingTypes.Count != );
//根据不同原因创建不同类型异常
if (matchingTypes.Count == )
{
// 没有匹配
throw new HttpResponseException(request.CreateErrorResponse(
HttpStatusCode.NotFound,
Error.Format(SRResources.ResourceNotFound, request.RequestUri),
Error.Format(SRResources.DefaultControllerFactory_ControllerNameNotFound, controllerName)));
}
else
{
// 匹配多个类型
throw CreateAmbiguousControllerException(request.GetRouteData().Route, controllerName, matchingTypes);
}
} public virtual IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
return _controllerInfoCache.Value.ToDictionary(c => c.Key, c => c.Value, StringComparer.OrdinalIgnoreCase);
} //从HttpRequestMessage的属性字典中获取控制器名称
public virtual string GetControllerName(HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
//先从HttpRequestMessage的属性字典中获取路由数据
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
{
return null;
} // TryGetValue获取key为controller的路由变量值
string controllerName = null;
routeData.Values.TryGetValue(ControllerKey, out controllerName);
return controllerName;
} //特性路由逻辑以后再说
private static HttpControllerDescriptor GetDirectRouteController(IHttpRouteData routeData)
{
CandidateAction[] candidates = routeData.GetDirectRouteCandidates();
if (candidates != null)
{
// Set the controller descriptor for the first action descriptor
Contract.Assert(candidates.Length > );
Contract.Assert(candidates[].ActionDescriptor != null); HttpControllerDescriptor controllerDescriptor = candidates[].ActionDescriptor.ControllerDescriptor; // Check that all other candidate action descriptors share the same controller descriptor
for (int i = ; i < candidates.Length; i++)
{
CandidateAction candidate = candidates[i];
if (candidate.ActionDescriptor.ControllerDescriptor != controllerDescriptor)
{
// We've found an ambiguity (multiple controllers matched)
throw CreateDirectRouteAmbiguousControllerException(candidates);
}
} return controllerDescriptor;
} return null;
} private static Exception CreateDirectRouteAmbiguousControllerException(CandidateAction[] candidates)
{
Contract.Assert(candidates != null);
Contract.Assert(candidates.Length > ); HashSet<Type> matchingTypes = new HashSet<Type>();
for (int i = ; i < candidates.Length; i++)
{
matchingTypes.Add(candidates[i].ActionDescriptor.ControllerDescriptor.ControllerType);
} // we need to generate an exception containing all the controller types
StringBuilder typeList = new StringBuilder();
foreach (Type matchedType in matchingTypes)
{
typeList.AppendLine();
typeList.Append(matchedType.FullName);
} return Error.InvalidOperation(SRResources.DirectRoute_AmbiguousController, typeList, Environment.NewLine);
} private static Exception CreateAmbiguousControllerException(IHttpRoute route, string controllerName, ICollection<Type> matchingTypes)
{
Contract.Assert(route != null);
Contract.Assert(controllerName != null);
Contract.Assert(matchingTypes != null); // Generate an exception containing all the controller types
StringBuilder typeList = new StringBuilder();
foreach (Type matchedType in matchingTypes)
{
typeList.AppendLine();
typeList.Append(matchedType.FullName);
} string errorMessage = Error.Format(SRResources.DefaultControllerFactory_ControllerNameAmbiguous_WithRouteTemplate, controllerName, route.RouteTemplate, typeList, Environment.NewLine);
return new InvalidOperationException(errorMessage);
} //初始化构建ConcurrentDictionary<string, HttpControllerDescriptor>缓存,根据Dictionary<string, ILookup<string, Type>>类型 列表缓存
private ConcurrentDictionary<string, HttpControllerDescriptor> InitializeControllerInfoCache()
{
var result = new ConcurrentDictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
//由于同一控制器名称在不同命名空间中存在多个控制器类型,所以要去掉重复的,用来记录重复的Key
var duplicateControllers = new HashSet<string>();
//先从控制器类型列表中缓存中获取控制器类型列表
Dictionary<string, ILookup<string, Type>> controllerTypeGroups = _controllerTypeCache.Cache; //遍历
foreach (KeyValuePair<string, ILookup<string, Type>> controllerTypeGroup in controllerTypeGroups)
{
string controllerName = controllerTypeGroup.Key; foreach (IGrouping<string, Type> controllerTypesGroupedByNs in controllerTypeGroup.Value)
{
foreach (Type controllerType in controllerTypesGroupedByNs)
{
if (result.Keys.Contains(controllerName))
{
//有重复就记录在重复集合里,待移除处理
duplicateControllers.Add(controllerName);
break;
}
else
{
//new HttpControllerDescriptor
result.TryAdd(controllerName, new HttpControllerDescriptor(_configuration, controllerName, controllerType));
}
}
}
}
//去掉有重复的匹配控制器的数据
foreach (string duplicateController in duplicateControllers)
{
HttpControllerDescriptor descriptor;
result.TryRemove(duplicateController, out descriptor);
} return result;
}
}

 5、IHttpControllerActivator DefaultHttpControllerActivator

  通过HttpControllerTypeResolver解析得到请求(controller名称)对应的控制器描述符(HttpControllerDescriptor)后,通过HttpControllerActivator根据控制器描述符最终创建出HttpController实例,其都实现接口IHttpControllerActivator ,其定义如下:

  public interface IHttpControllerActivator
{
//根据HttpControllerDescriptor创建出IHttpController
IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType);
}

  DefaultHttpControllerActivator是默认实现,其配置同前边几个,不再赘述

  主要逻辑:

  • 在Create方法中,如果dependency resolver可以解析返回,就直接返回,否则就用创建委托activator来执行创建,而创建委托activator可以缓存到本地缓存和controllerDescriptor.Properties cache缓存,由上一篇可以知道,默认的IoC容器是EmptyResolver,所以dependency resolver都是返回空,所以每次都是通过反射创建实例。
  • activator通过反射来创建,在第一点中缓存的是创建对象的委托,而不是HttpController实例,其每次都是重新创建,所以对于多个针对相同的HttpControlIer类型的请求来说,最终创建的HttpController实例都是不同的
 public class DefaultHttpControllerActivator : IHttpControllerActivator
{
//缓存HttpControllerDescriptor对应的创建委托
private Tuple<HttpControllerDescriptor, Func<IHttpController>> _fastCache;
private object _cacheKey = new object(); //核心创建方法,如果dependency resolver可以解析返回,就直接返回,否则就用创建委托activator来执行创建,
//而创建委托activator可以缓存到本地缓存和controllerDescriptor.Properties cache缓存
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
if (request == null)
{
throw Error.ArgumentNull("request");
} if (controllerDescriptor == null)
{
throw Error.ArgumentNull("controllerDescriptor");
} if (controllerType == null)
{
throw Error.ArgumentNull("controllerType");
} try
{
Func<IHttpController> activator; //如果没有定义本地快速缓存
if (_fastCache == null)
{
IHttpController controller = GetInstanceOrActivator(request, controllerType, out activator);
if (controller != null)
{
//这里返回的是dependency resolver中有定义时候,定义的Controller实例
return controller;
}
else
{
//初始化创建一个本地缓存cacheItem
Tuple<HttpControllerDescriptor, Func<IHttpController>> cacheItem = Tuple.Create(controllerDescriptor, activator);
Interlocked.CompareExchange(ref _fastCache, cacheItem, null);
}
}
else if (_fastCache.Item1 == controllerDescriptor)
{
// 如果有定义本地快速缓存,而且匹配controllerDescriptor key就直接返回
activator = _fastCache.Item2;
}
else
{
// 如果有定义本地快速缓存,没有匹配controllerDescriptor key,就从controllerDescriptor.Properties cache中获取创建委托
object value;
if (controllerDescriptor.Properties.TryGetValue(_cacheKey, out value))
{
activator = (Func<IHttpController>)value;
}
else
{
IHttpController controller = GetInstanceOrActivator(request, controllerType, out activator);
if (controller != null)
{
//这里返回的是dependency resolver中有定义时候,定义的Controller实例
return controller;
}
else
{
//添加进HttpControllerDescriptor.Properties cache
controllerDescriptor.Properties.TryAdd(_cacheKey, activator);
}
}
}
//执行创建委托,创建实例
return activator();
}
catch (Exception ex)
{
throw Error.InvalidOperation(ex, SRResources.DefaultControllerFactory_ErrorCreatingController, controllerType.Name);
}
} // 返回控制器实例如果在dependency resolver得到就直接返回,否则通过反射创建
private static IHttpController GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, out Func<IHttpController> activator)
{
Contract.Assert(request != null);
Contract.Assert(controllerType != null); // 如果dependency resolver可以直接返回controller就直接返回使用
IHttpController instance = (IHttpController)request.GetDependencyScope().GetService(controllerType);
if (instance != null)
{
activator = null;
return instance;
} //如果dependency resolver没有定义,就返回通过反射直接创建的委托
activator = TypeActivator.Create<IHttpController>(controllerType);
return null;
}
}

 二、自定义扩展组件HttpControllerActivator

  从前边IHttpControllerActivator那节知道,每次创建实例都是通过反射完成的,因为默认情况下的IoC容器是EmptyResolver,所以dependency resolver都是返回空,根据代码可以知道,都是通过反射来完成,我们可以通过重新实现IHttpControllerActivator,把服务容器里默认定义的DefaultHttpControllerActivator替换掉,替换掉EmptyResolver的方式,上一篇已经说过。

   public class UnityHttpControllerActivator : IHttpControllerActivator
{
public IUnityContainer UnityContainer { get; private set; } public UnityHttpControllerActivator(IUnityContainer unityContainer)
{
this.UnityContainer = unityContainer;
} public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
return (IHttpController)this.UnityContainer.Resolve(controllerType);
}
}

  注册:

 UnityContainer unityContainer = new UnityContainer();
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator),new UnityHttpControllerActivator(unityContainer));

ASP.NET Web API 框架研究 Controller创建 HttpController 类型解析 选择 创建的更多相关文章

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

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

  2. ASP.NET Web API 框架研究 Controller创建 HttpController介绍

    对请求进行路由解析以及消息处理管道进行处理后,最后可以从HttpRequestMessage对象的属性字典中获取解析的路由数据,后边我们就可以根据其进行HttpController的创建,从前边几篇可 ...

  3. ASP.NET Web API 框架研究 Controller创建过程与消息处理管道

    现在我们从代码角度来看下,从消息处理管道末尾是怎么创建出Controller实例的.消息处理管道末端是一个叫HttpRoutingDispatcher的处理器,其内部完成路由后 ,会把消息派送给其内部 ...

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

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

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

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

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

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

  7. ASP.NET Web API 框架研究 IoC容器 DependencyResolver

    一.概念 1.IoC(Inversion of Control),控制反转 即将依赖对象的创建和维护交给一个外部容器来负责,而不是应用本身.如,在类型A中需要使用类型B的实例,而B的实例的创建不是由A ...

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

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

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

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

随机推荐

  1. sFlow-rt安装部署

      sFlow技术是一种以设备端口为基本单元的数据流随机采样的流量监控技术,不仅可以提供完整的第二层到第四层甚至全网范围内的实时流量信息,而且可以适应超大网络流量(如大于10Gbit/s)环境下的流量 ...

  2. linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)

      IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...

  3. CODE[VS]4228 小猫爬山 小猫爬山

    原题链接 第一眼还以为是贪心,然后随便找了几组例子瞬间推翻贪心的想法.发现\(n\leqslant18\),显然是用爆搜+剪枝. 爆搜主体我是对小猫进行枚举,判断增添缆车,其实这是一个比较慢的搜法,而 ...

  4. Yii2-设置和获取、删除Cookies空值分析(有代码)

    Yii2-设置和获取,删除Cookies空值或值没有变化 原因: 1.不要使用相同的request url, 否则需要刷新才能获取值 可在不同的动作中设置和调用 2.不要在函数中使用exit来中止脚本 ...

  5. 担心后端代码泄露?用delphi做后端,模板扣出来,随时可以变化。

    担心后端代码泄露?用delphi做后端,模板扣出来,随时可以变化. 本项目不是intraweb, unigui等类似的拖拉项目,只是一个简单 的模板引擎,理论上可以结合任何后端. 要就下载源码,作者保 ...

  6. 10个办法让设计小白迅速get海报设计要点!

    对于设计师而言,海报和宣传单的设计,几乎是每一个设计师的必修课.如今网页上的 Banner.宣传和促销的数字海报,大多脱胎于我们所熟知的海报设计. 对于推销产品.连接客户,海报始终是一种最为有趣和实用 ...

  7. office 2007,SQL Server 2008,VS2010安装步骤

    office 2007,SQL Server 2008,VS2010的安装顺序是不是office 2007,SQL Server 2008,VS2010呢? 前几天先安装了SQL Server 200 ...

  8. Fibonacci Number LT509

    The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci sequence, such th ...

  9. [C#.NET]最简单的实现文本框的水印效果

    C#项目开发中在设计登录界面时,经常会遇到TextBox的水印提示要求.这里简单描述一下项目在实现水印提示的过程设置.如下图图1所示. 图1  窗体布局 一.窗体布局(如图1所示) 1.  在窗体中放 ...

  10. [cmd]如何设置 Windows 默认命令行窗口大小和缓冲区大小

    Windows 命令行 cmd 窗口系统默认的大小(80*40)对于现在的屏幕配置已经跟不上时代了,我们总是要把它改大些,而且缓冲区大小也想改得大大的.单纯的为当前的 Windows 命令行窗口修改显 ...