Message
WebAPI作为通信架构必定包含包含请求与响应两个方法上的报文,在WebAPI它们分别是HttpRequestMessage,HttpResponseMessage。对于HttpResponseMessage之前在中有应用。
HttpRequestMessage
请求报文包含请求地址(RequestUri),请求方法(Method),头信息(Headers),报文信息(Content)以及Http版本(Versions)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class HttpRequestMessage : IDisposable { public HttpRequestMessage(); public HttpRequestMessage(HttpMethod method, string requestUri); public HttpRequestMessage(HttpMethod method, Uri requestUri); public HttpContent Content { get ; set ; } public HttpRequestHeaders Headers { get ; } public HttpMethod Method { get ; set ; } public IDictionary< string , object > Properties { get ; } public Uri RequestUri { get ; set ; } public Version Version { get ; set ; } public void Dispose(); protected virtual void Dispose( bool disposing); public override string ToString(); } |
另外,WebAPI提供了一个类型为IDictionary<string,object>的属性Properties。我们可以将做任意对象作为附加属性添加到HttpRequestMessage.
HttpResponseMessage
请求报文包含状态码(StatusCode),原因短句(ReasonPhrase),头信息(Headers),报文信息(Content)以及Http版本(Versions)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class HttpRequestMessage : IDisposable { public HttpRequestMessage(); public HttpRequestMessage(HttpMethod method, string requestUri); public HttpRequestMessage(HttpMethod method, Uri requestUri); public HttpContent Content { get ; set ; } public HttpRequestHeaders Headers { get ; } public HttpMethod Method { get ; set ; } public IDictionary< string , object > Properties { get ; } public Uri RequestUri { get ; set ; } public Version Version { get ; set ; } public void Dispose(); protected virtual void Dispose( bool disposing); public override string ToString(); } |
HttpConfiguration
HttpConfiguration在WebAPI大概有如下几个作用:
- 设置通信管道
- 存储全局信息(比如Filter,Route,Formatter)
- 提供一个Ioc架构,用于WebAPI的扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class HttpConfiguration : IDisposable { public HttpConfiguration(); public HttpConfiguration(HttpRouteCollection routes); public IDependencyResolver DependencyResolver { get ; set ; } public HttpFilterCollection Filters { get ; } public MediaTypeFormatterCollection Formatters { get ; } public IncludeErrorDetailPolicy IncludeErrorDetailPolicy { get ; set ; } public Action<HttpConfiguration> Initializer { get ; set ; } public Collection<System.Net.Http.DelegatingHandler> MessageHandlers { get ; } public ParameterBindingRulesCollection ParameterBindingRules { get ; internal set ; } public ConcurrentDictionary< object , object > Properties { get ; } public HttpRouteCollection Routes { get ; } public ServicesContainer Services { get ; internal set ; } public string VirtualPathRoot { get ; } public void Dispose(); protected virtual void Dispose( bool disposing); public void EnsureInitialized(); } |
对于第1 点我们在每6篇已经用到。第2点后面会陆续讲到,本篇只重点讲下第3点。这一功能主要是通过ServicesContainer来完成,即HttpConfiguration中的Services属性。
WebAPI对ServicesContainer的提供的派生类是DefaultServices,在DefaultServices,包含了两种依赖注入方法:1,单一派生类型注入(multi),2,多派生类型注入(single),即在注入派生类型的数量有区别。比如在获取url参数的时候有QueryString,RouteData两种方式,而这两种方式是通过QueryStringValueProvider与RouteDataValueProvider两种类型来实现的(实际在DefaultServices注入是这人两个类对应的Factory类),这两种类型属于平行关系,所以这个时候能需要采用multi方法注入。
这些类型都是在DefaultServces的构造中注入的。
1 2 3 4 5 6 7 8 9 10 11 12 | public class DefaultServices : ServicesContainer { protected DefaultServices(); public DefaultServices(HttpConfiguration configuration); protected override void ClearSingle(Type serviceType); public override object GetService(Type serviceType); protected override List< object > GetServiceInstances(Type serviceType); public override IEnumerable< object > GetServices(Type serviceType); public override bool IsSingleService(Type serviceType); protected override void ReplaceSingle(Type serviceType, object service); protected override void ResetCache(Type serviceType); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public abstract class ServicesContainer : IDisposable { protected ServicesContainer(); public void Add(Type serviceType, object service); public void AddRange(Type serviceType, IEnumerable< object > services); public virtual void Clear(Type serviceType); public virtual void Dispose(); public int FindIndex(Type serviceType, Predicate< object > match); public abstract object GetService(Type serviceType); public abstract IEnumerable< object > GetServices(Type serviceType); public void Insert(Type serviceType, int index, object service); viceType, int index, IEnumerable< object > services); public abstract bool IsSingleService(Type serviceType); public bool Remove(Type serviceType, object service); public int RemoveAll(Type serviceType, Predicate< object > match); public void RemoveAt(Type serviceType, int index); public void Replace(Type serviceType, object service); public void ReplaceRange(Type serviceType, IEnumerable< object > services); } |
ServicesContainer只提供的了替换与获取的公共方法。因为ServicesContainer只提供了WebAPI中的标准组件,并不想作为一个公共的Ioc容器,而这些标准的组件是WebAPI进行扩展的基础。
下面我写的四个Action分别是获取所有multiServices,获取所有singleServices,向multiServices中添加一个自定义的ValueProviderFactory,向singleServices中添加自定义的IExceptionHandler.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | public Dictionary<Type, List<Type>> GetAllMultiServices() { Dictionary<Type, List<Type>> result = new Dictionary<Type, List<Type>>(); FieldInfo field = RequestContext.Configuration.Services.GetType().GetField( "_defaultServicesMulti" , BindingFlags.NonPublic|BindingFlags.Instance); Dictionary<Type, List< object >> multiServices = (Dictionary<Type, List< object >>)field.GetValue(RequestContext.Configuration.Services); foreach ( var s in multiServices) { List<Type> items = new List<Type>(); foreach ( var item in s.Value) { items.Add(item.GetType()); } result[s.Key] = items; } return result; } public Dictionary<Type, Type> GetAllSingleServices() { Dictionary<Type, Type> result = new Dictionary<Type, Type>(); FieldInfo field = RequestContext.Configuration.Services.GetType().GetField( "_defaultServicesSingle" , BindingFlags.NonPublic | BindingFlags.Instance); Dictionary<Type, object > services = (Dictionary<Type, object >)field.GetValue(RequestContext.Configuration.Services); foreach ( var s in services) { result.Add(s.Key, s.Value== null ? null :s.Value.GetType()); } return result; } public Dictionary<Type, List<Type>> AddMultiService() { List<ValueProviderFactory> valueProviderFactories= new List<ValueProviderFactory>(){ new QueryStringValueProviderFactory(), new RouteDataValueProviderFactory(), new MyValueProviderFactory() }; RequestContext.Configuration.Services.ReplaceRange( typeof (ValueProviderFactory), valueProviderFactories); return GetAllMultiServices(); } public Dictionary<Type, Type> ReplaceSingleService() { RequestContext.Configuration.Services.Replace( typeof (IExceptionHandler), new MyExceptionHandler()); return GetAllSingleServices(); } |
因为ServicesContainer中的类型注入都是固定的,所以WebAPI给ServicesContainer扩展了一组获取Service的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public static class ServicesExtensions { public static IHttpActionInvoker GetActionInvoker( this ServicesContainer services); public static IHttpActionSelector GetActionSelector( this ServicesContainer services); public static IActionValueBinder GetActionValueBinder( this ServicesContainer services); public static IApiExplorer GetApiExplorer( this ServicesContainer services); public static IAssembliesResolver GetAssembliesResolver( this ServicesContainer services); public static IBodyModelValidator GetBodyModelValidator( this ServicesContainer services); public static IContentNegotiator GetContentNegotiator( this ServicesContainer services); public static IDocumentationProvider GetDocumentationProvider( this ServicesContainer services); public static IExceptionHandler GetExceptionHandler( this ServicesContainer services); public static IEnumerable<IExceptionLogger> GetExceptionLoggers( this ServicesContainer services); public static IEnumerable<System.Web.Http.Filters.IFilterProvider> GetFilterProviders( this ServicesContainer services); public static IHostBufferPolicySelector GetHostBufferPolicySelector( this ServicesContainer services); public static IHttpControllerActivator GetHttpControllerActivator( this ServicesContainer services); public static IHttpControllerSelector GetHttpControllerSelector( this ServicesContainer services); public static IHttpControllerTypeResolver GetHttpControllerTypeResolver( this ServicesContainer services); public static IEnumerable<System.Web.Http.ModelBinding.ModelBinderProvider> GetModelBinderProviders( this ServicesContainer services); public static ModelMetadataProvider GetModelMetadataProvider( this ServicesContainer services); public static IEnumerable<ModelValidatorProvider> GetModelValidatorProviders( this ServicesContainer services); public static ITraceManager GetTraceManager( this ServicesContainer services); public static ITraceWriter GetTraceWriter( this ServicesContainer services); public static IEnumerable<System.Web.Http.ValueProviders.ValueProviderFactory> GetValueProviderFactories( this ServicesContainer services); } |
在ASP.NET WebAPI中有一个GlobalConfiguration,其实它并不是WebAPI的一部分。WebAPI只是一个独立的框架。它需要寄宿在别的应用程序下才能运行。寄宿模式则分为两种WebHost,SelfHost,WebHost是针对Web程序的寄宿。因为本系列只讨论ASP.Net下的WebAPI,所以只简单讲一下WebHost模式。
ASP.NET WebAPI中引用了程序集System.Web.Http.WebHost,GlobalConfiguration就在该程序集下.它包含了一个HttpConfiguration属性.还一个配置HttpConfiguration的方法
另外还有一个HttServer
另外在ApiController的很多属性都能找到HttpConfiguraiton
ConfigurationControllerContext.Configuration
RequestContext.Configuration
这些HttpConfiguration都来自对GlobalConfiguration.Configuration的引用.
DependencyResolver
WebAPI为我们提供了一个Ioc框架,即DependencyResolver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public interface IDependencyResolver : IDependencyScope, IDisposable { IDependencyScope BeginScope(); } public interface IDependencyScope : IDisposable { object GetService(Type serviceType); IEnumerable< object > GetServices(Type serviceType); } |
IDependencyResolver也继承了IDependencyScope,所以我们可以将IDependencyScope视为依赖的上下文.
在WebAPI中DependencyResolver并没有像其它组件一样注册在ServicesContainer中,而是直接注册在HttpConfiguration中(DependencyResolver属性).
别个HttpRequestMessage中也有一扩展方法GetDependencyScope来获取DependencyScope,该方法获取的是HttpRequestMessage的Properties的DependencyResolver,这里的DependencyResolver也来自HttpConfiguration.
在WebAPI中也定义了一个EmptyResolver,它只是一个空的Resolver,所以在WebAPI默认就是采用直接反射方式.
源码
Github: (API_8)