目錄 1. HttpController 2. 創建HttpController IAssembliesResolver IHttpControllerTypeResolver HttpControllerTypeCache IHttpControllerSelector 3. ServicesCo ...
目錄
HttpController
- 創建HttpController
- IAssembliesResolver
- IHttpControllerTypeResolver
- HttpControllerTypeCache
- IHttpControllerSelector
ServicesContainer
從上節我們知道,在消息管道中,最終在HttpControllerDispatcher的SendAsync方法中會創建IHttpController.
HttpController
我們先看看IHttpController
public interface IHttpController
{
Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken);
}
IHttpController設計很像HttpMessageHandler,只不過參數由HttpRequestMessage變成了HttpControllerContext
public public class HttpControllerContext
{
HttpControllerContext(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor)
}
可以看出HttpControllerContext實際就是包裝了一下HttpRequestMessage和HttpControllerDescriptor
而HttpControllerDescriptor則是真正創建IHttpController的對象
public class HttpControllerDescriptor
{
public virtual IHttpController CreateController(HttpRequestMessage request)
{
//通過內置的輕量級容器創建
return this.Configuration.Services.GetHttpControllerActivator().Create(request, this, this.ControllerType);
}
}
本節重點就是介紹HttpControllerDescriptor的CreateController方法
創建HttpController
在談創建HttpController前,我們需要瞭解HttpControllerDescriptor是如何被創建的
整個創建過程需要經歷以下步驟
IAssembliesResolver
首先通過IAssembliesResolver找出符合的程式集
預設的實現是找出當前應用程式域中的程式集
public class DefaultAssembliesResolver : IAssembliesResolver
{
public virtual ICollection<Assembly> GetAssemblies()
{
return (ICollection<Assembly>) ((IEnumerable<Assembly>) AppDomain.CurrentDomain.GetAssemblies()).ToList<Assembly>();
}
}
而在WebHost下,在HttpConfiguration的創建過程中替換為WebHostAssembliesResolver
internal sealed class WebHostAssembliesResolver : IAssembliesResolver
{
ICollection<Assembly> IAssembliesResolver.GetAssemblies()
{
//所有引用的程式集
return (ICollection<Assembly>) BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToList<Assembly>();
}
}
IHttpControllerTypeResolver
在列出可用的Assemblies後,會通過IHttpControllerTypeResolver找出所有的IHttpController
預設實現為DefaultHttpControllerTypeResolver
public class DefaultHttpControllerTypeResolver : IHttpControllerTypeResolver
{
public virtual ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
{
foreach (Assembly assembly in (IEnumerable<Assembly>) assembliesResolver.GetAssemblies())
{
typeArray = assembly.GetTypes();
return typeArray.Where<Type>(x => this.IsControllerTypePredicate(x));
}
}
internal static bool IsControllerType(Type t)
{
//IsClass IsVisible !IsAbstract IHttpController
if (t != (Type) null && t.IsClass && (t.IsVisible && !t.IsAbstract) && typeof (IHttpController).IsAssignableFrom(t))
return DefaultHttpControllerTypeResolver.HasValidControllerName(t);
return false;
}
}
IHttpControllerSelector
當找到所有HttpController後,IHttpControllerSelector用來選擇能夠生成HttpControllerDescriptor(當同一個Controller名在不同的命名空間下,這時是WebAPI會拋棄這2個Controller)
預設實現為DefaultHttpControllerSelector
public class DefaultHttpControllerSelector : IHttpControllerSelector
{
//根據請求 選擇對應的HttpControllerDescriptor
public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
string controllerName = this.GetControllerName(request);
HttpControllerDescriptor controllerDescriptor;
if (GetControllerDescriptor(controllerName, out controllerDescriptor))
return controllerDescriptor;
return null;
}
//從路由變數controller中獲取ControllerName
public virtual string GetControllerName(HttpRequestMessage request)
{
string str;
request.GetRouteData().Values.TryGetValue<string>("controller", out str);
return str;
}
public HttpControllerDescriptor GetControllerDescriptor(string controllerName,out HttpControllerDescriptor controllerDescriptor)
{
//去除同名Controller
var keys = ControllerTypeCache.Cache.Where(x=>x.Value.Count == 1).Select(x=>x.Key);
foreach(var key in keys){
//...
return new HttpControllerDescriptor(...);
}
}
}
HttpControllerTypeCache
這裡再補充一點:
在DefaultHttpControllerSelector的代碼中,我們使用ControllerTypeCache.Cache
實際上由於頻繁的反射創建Controller,WebAPI通過緩存Controller避免了不必要的損失.
同時在DefaultHttpControllerSelector代碼中也存在相應的緩存措施(文中的代碼為了便於理解).
internal sealed class HttpControllerTypeCache
{
public HttpControllerTypeCache(HttpConfiguration configuration)
{
Cache = GetCache(configuration);//該處同樣為偽代碼
}
internal Dictionary<string, ILookup<string, Type>> Cache {get;}
}
通過上面的流程,我們清楚了HttpControllerDescriptor是如何創建的,同時創建完HttpControllerDescriptor後,調用CreateController即可創建 public virtual IHttpController CreateController(HttpRequestMessage request)
ServicesContainer
在Web API消息管道中,定義了很多介面,對應的也有很多實現類.
WebAPI自定義了一套DI容器ServicesContainer.而這個容器直接掛在HttpConfiguration上
public class HttpConfiguration : IDisposable
{
public ServicesContainer Services { get; internal set; }
public HttpConfiguration(HttpRouteCollection routes)
{
this.Services = (ServicesContainer) new DefaultServices(this);
}
}
在預設的實現DefaultServices 則定義了WebAPI 預設對應的實現
public class DefaultServices : ServicesContainer
{
private readonly Dictionary<Type, object> _defaultServicesSingle = new Dictionary<Type, object>();
public DefaultServices(HttpConfiguration configuration)
{
//...
this.SetSingle<IAssembliesResolver>((IAssembliesResolver) new DefaultAssembliesResolver());
this.SetSingle<IHttpControllerActivator>((IHttpControllerActivator) new DefaultHttpControllerActivator());
this.SetSingle<IHttpControllerSelector>((IHttpControllerSelector) new DefaultHttpControllerSelector(configuration));
this.SetSingle<IHttpControllerTypeResolver>((IHttpControllerTypeResolver) new DefaultHttpControllerTypeResolver());
}
//設置介面實現
private void SetSingle<T>(T instance) where T : class
{
this._defaultServicesSingle[typeof (T)] = (object) instance;
}
//獲取介面實現
public override object GetService(Type serviceType)
{
return this._defaultServicesSingle[serviceType];
}
}
備註:
文章中的代碼並非完整WebAPI代碼,一般是經過自己精簡後的.
本篇內容使用MarkDown語法編輯
首發地址:http://neverc.cnblogs.com/p/5952821.html