Asp.net web Api源码分析-HttpRequestMessage的创建
紧接着前文Asp.net web Api源码分析-如何获取IHttpHandler 我们已经得到了HttpControllerHandler实例,它是一个IHttpAsyncHandler类型,我们来看看它的BeginProcessRequest方法是如何实现:
protected virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContextBase, AsyncCallback callback, object state) { HttpRequestMessage request = httpContextBase.GetHttpRequestMessage() ?? ConvertRequest(httpContextBase); request.Properties[HttpPropertyKeys.HttpRouteDataKey] = _routeData; Task responseBodyTask = _server.Value.SendAsync(request, CancellationToken.None) .Then(response => ConvertResponse(httpContextBase, response, request)); TaskWrapperAsyncResult result = new TaskWrapperAsyncResult(responseBodyTask, state); if (callback != null ) { if (result.IsCompleted) { result.CompletedSynchronously = true ; callback(result); } else { result.CompletedSynchronously = false ; responseBodyTask.ContinueWith(_ => { callback(result); }); } } return result; } |
我想这个方法的大致逻辑大家一看也就明白了,这里我们只关心 HttpRequestMessage request = httpContextBase.GetHttpRequestMessage() ?? ConvertRequest(httpContextBase);这句,创建HttpRequestMessage实例,有关 HttpRequestMessage的一些介绍大家可以参考MVC4 WebAPI(二)——Web API工作方式
其中GetHttpRequestMessage方法的实现非常简单:
internal static readonly string HttpRequestMessageKey = "MS_HttpRequestMessage";
public static HttpRequestMessage GetHttpRequestMessage(this HttpContextBase context)
{
return context.Items[HttpRequestMessageKey] as HttpRequestMessage;
}
public static void SetHttpRequestMessage(this HttpContextBase context, HttpRequestMessage request)
{
context.Items.Add(HttpRequestMessageKey, request);
}
所以这里的GetHttpRequestMessage并没有真正创建HttpRequestMessage,ConvertRequest方法才是真正创建HttpRequestMessage的地方。
internal static HttpRequestMessage ConvertRequest(HttpContextBase httpContextBase) { Contract.Assert(httpContextBase != null ); HttpRequestBase requestBase = httpContextBase.Request; HttpMethod method = HttpMethodHelper.GetHttpMethod(requestBase.HttpMethod); Uri uri = requestBase.Url; HttpRequestMessage request = new HttpRequestMessage(method, uri); IHostBufferPolicySelector policySelector = _bufferPolicySelector.Value; bool isInputBuffered = policySelector == null ? true : policySelector.UseBufferedInputStream(httpContextBase); Stream inputStream = isInputBuffered ? requestBase.InputStream : httpContextBase.ApplicationInstance.Request.GetBufferlessInputStream(); request.Content = new StreamContent(inputStream); foreach ( string headerName in requestBase.Headers) { string [] values = requestBase.Headers.GetValues(headerName); AddHeaderToHttpRequestMessage(request, headerName, values); } request.Properties.Add(HttpContextBaseKey, httpContextBase); request.Properties.Add(HttpPropertyKeys.RetrieveClientCertificateDelegateKey, _retrieveClientCertificate); request.Properties.Add(HttpPropertyKeys.IsLocalKey, new Lazy< bool >(() => requestBase.IsLocal)); request.Properties.Add(HttpPropertyKeys.IncludeErrorDetailKey, new Lazy< bool >(() => !httpContextBase.IsCustomErrorEnabled)); return request; } |
其中
HttpRequestBase requestBase = httpContextBase.Request;
HttpMethod method = HttpMethodHelper.GetHttpMethod(requestBase.HttpMethod);
Uri uri = requestBase.Url;
HttpRequestMessage request = new HttpRequestMessage(method, uri);
这几句代码很简单也很好明白,我想我就不多说了,而下面的几句代码页很好理解
IHostBufferPolicySelector policySelector = _bufferPolicySelector.Value;
bool isInputBuffered = policySelector == null ? true : policySelector.UseBufferedInputStream(httpContextBase);
Stream inputStream = isInputBuffered
? requestBase.InputStream
: httpContextBase.ApplicationInstance.Request.GetBufferlessInputStream();
request.Content = new StreamContent(inputStream);
isInputBuffered是否使用输入缓存,这里默认返回true,这几句主要是 获取请求的输入流isInputBuffered? requestBase.InputStream: httpContextBase.ApplicationInstance.Request.GetBufferlessInputStream();, 然后设置HttpRequestMessage的Content属性,
foreach (string headerName in requestBase.Headers)
{
string[] values = requestBase.Headers.GetValues(headerName);
AddHeaderToHttpRequestMessage(request, headerName, values);
}
这句也很好明白,就是把Request的header信息按需添加到HttpRequestMessage的Content.Headers里面,
最后在HttpRequestMessage的Properties属性中添加一些暂存信息。这里的Properties属性没得说它是
IDictionary<string, object>类型。
现在我们好好分析一下这里面的一些细节的东西。
首先我们来看看 IHostBufferPolicySelector policySelector = _bufferPolicySelector.Value;这一句,这里的_bufferPolicySelector是一个延迟加载对象,其定义如下:
private static readonly Lazy<IHostBufferPolicySelector> _bufferPolicySelector =
new Lazy<IHostBufferPolicySelector>(() =>
GlobalConfiguration.Configuration.Services.GetHostBufferPolicySelector());
在GlobalConfiguration类中有这么一句
config.Services.Replace(typeof(IHostBufferPolicySelector), new WebHostBufferPolicySelector());这里我们可以知道_bufferPolicySelector.Value其实就是一个WebHostBufferPolicySelector实例,该实例的UseBufferedInputStream方法返回true,表示使用输入缓存。
大家应该还记得前面在说HttpConfiguration的构造函数有这么一句吧:
Services = new DefaultServices(this); 其中Services是ServicesContainer类型。
DefaultServices的代码比较多但是还是比较好理解的,
private readonly ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim(); private readonly Dictionary<Type, object []> _cacheMulti = new Dictionary<Type, object []>(); private readonly Dictionary<Type, object > _cacheSingle = new Dictionary<Type, object >(); private readonly Dictionary<Type, object > _defaultServicesSingle = new Dictionary<Type, object >(); private readonly Dictionary<Type, List< object >> _defaultServicesMulti = new Dictionary<Type, List< object >>(); public DefaultServices(HttpConfiguration configuration) { if (configuration == null ) { throw Error.ArgumentNull( "configuration" ); } _configuration = configuration; // Initialize the dictionary with all known service types, even if the list for that service type is // empty, because we will throw if the developer tries to read or write unsupported types. SetSingle<IActionValueBinder>( new DefaultActionValueBinder()); SetSingle<IApiExplorer>( new ApiExplorer(configuration)); SetSingle<IAssembliesResolver>( new DefaultAssembliesResolver()); SetSingle<IBodyModelValidator>( new DefaultBodyModelValidator()); SetSingle<IContentNegotiator>( new DefaultContentNegotiator()); SetSingle<IDocumentationProvider>( null ); // Missing SetMultiple<IFilterProvider>( new ConfigurationFilterProvider(), new ActionDescriptorFilterProvider()); SetSingle<IHostBufferPolicySelector>( null ); SetSingle<IHttpActionInvoker>( new ApiControllerActionInvoker()); SetSingle<IHttpActionSelector>( new ApiControllerActionSelector()); SetSingle<IHttpControllerActivator>( new DefaultHttpControllerActivator()); SetSingle<IHttpControllerSelector>( new DefaultHttpControllerSelector(configuration)); SetSingle<IHttpControllerTypeResolver>( new DefaultHttpControllerTypeResolver()); SetSingle<ITraceManager>( new TraceManager()); SetSingle<ITraceWriter>( null ); // This is a priority list. So put the most common binders at the top. SetMultiple<ModelBinderProvider>( new TypeConverterModelBinderProvider(), new TypeMatchModelBinderProvider(), new KeyValuePairModelBinderProvider(), new ComplexModelDtoModelBinderProvider(), new ArrayModelBinderProvider(), new DictionaryModelBinderProvider(), new CollectionModelBinderProvider(), new MutableObjectModelBinderProvider()); SetSingle<ModelMetadataProvider>( new DataAnnotationsModelMetadataProvider()); SetMultiple<ModelValidatorProvider>( new DataAnnotationsModelValidatorProvider(), new DataMemberModelValidatorProvider(), new InvalidModelValidatorProvider()); // This is an ordered list,so put the most common providers at the top. SetMultiple<ValueProviderFactory>( new QueryStringValueProviderFactory(), new RouteDataValueProviderFactory()); ModelValidatorCache validatorCache = new ModelValidatorCache( new Lazy<IEnumerable<ModelValidatorProvider>>(() => this .GetModelValidatorProviders())); configuration.RegisterForDispose(validatorCache); SetSingle<IModelValidatorCache>(validatorCache); _serviceTypesSingle = new HashSet<Type>(_defaultServicesSingle.Keys); _serviceTypesMulti = new HashSet<Type>(_defaultServicesMulti.Keys); // Reset the caches and the known dependency scope ResetCache(); } private void SetSingle<T>(T instance) where T : class { _defaultServicesSingle[ typeof (T)] = instance; } private void SetMultiple<T>( params T[] instances) where T : class { var x = (IEnumerable< object >)instances; _defaultServicesMulti[ typeof (T)] = new List< object >(x); } private void ResetCache() { _cacheLock.EnterWriteLock(); try { _cacheSingle.Clear(); _cacheMulti.Clear(); _lastKnownDependencyResolver = _configuration.DependencyResolver; } finally { _cacheLock.ExitWriteLock(); } } public override object GetService(Type serviceType) { if (serviceType == null ) { throw Error.ArgumentNull( "serviceType" ); } if (!_serviceTypesSingle.Contains(serviceType)) { throw Error.Argument( "serviceType" , SRResources.DefaultServices_InvalidServiceType, serviceType.Name); } // Invalidate the cache if the dependency scope has switched if (_lastKnownDependencyResolver != _configuration.DependencyResolver) { ResetCache(); } object result; _cacheLock.EnterReadLock(); try { if (_cacheSingle.TryGetValue(serviceType, out result)) { return result; } } finally { _cacheLock.ExitReadLock(); } // Get the service from DI, outside of the lock. If we're coming up hot, this might // mean we end up creating the service more than once. object dependencyService = _configuration.DependencyResolver.GetService(serviceType); _cacheLock.EnterWriteLock(); try { if (!_cacheSingle.TryGetValue(serviceType, out result)) { result = dependencyService ?? _defaultServicesSingle[serviceType]; _cacheSingle[serviceType] = result; } return result; } finally { _cacheLock.ExitWriteLock(); } } public override IEnumerable< object > GetServices(Type serviceType) { if (serviceType == null ) { throw Error.ArgumentNull( "serviceType" ); } if (!_serviceTypesMulti.Contains(serviceType)) { throw Error.Argument( "serviceType" , SRResources.DefaultServices_InvalidServiceType, serviceType.Name); } // Invalidate the cache if the dependency scope has switched if (_lastKnownDependencyResolver != _configuration.DependencyResolver) { ResetCache(); } object [] result; _cacheLock.EnterReadLock(); try { if (_cacheMulti.TryGetValue(serviceType, out result)) { return result; } } finally { _cacheLock.ExitReadLock(); } // Get the service from DI, outside of the lock. If we're coming up hot, this might // mean we end up creating the service more than once. IEnumerable< object > dependencyServices = _configuration.DependencyResolver.GetServices(serviceType); _cacheLock.EnterWriteLock(); try { if (!_cacheMulti.TryGetValue(serviceType, out result)) { result = dependencyServices.Where(s => s != null ) .Concat(_defaultServicesMulti[serviceType]) .ToArray(); _cacheMulti[serviceType] = result; } return result; } finally { _cacheLock.ExitWriteLock(); } } |
在我们的日常开发中会遇到2中情况,一种是一个接口对应着一个具体实现类(Dictionary<Type, object> _defaultServicesSingle),还有一种情况是一个接口对应着多个实现类(Dictionary<Type, List<object>> _defaultServicesMulti),所以这里的DefaultServices实际就是把一个接口和一个或则多个实例关联起来。
现在我们来看看ServicesContainer的GetHostBufferPolicySelector()方法实现,
public static IHostBufferPolicySelector GetHostBufferPolicySelector(this ServicesContainer services)
{
return services.GetService<IHostBufferPolicySelector>();
}
private static TService GetService<TService>(this ServicesContainer services)
{
if (services == null)
{
throw Error.ArgumentNull("services");
}
return (TService)services.GetService(typeof(TService));
}
这里其实还是调用的是DefaultServices的GetService方法,这里的IHostBufferPolicySelector接口 和实例是一一对应的,首先在_cacheSingle中根据type来查找实例,如果找到这直接返回,如果没有找到就根 据 _configuration.DependencyResolver.GetService(serviceType)方法来找实例,如果 _cacheSingle key中不含type,这把该type和实例添加到_cacheSingle中来,
if (!_cacheSingle.TryGetValue(serviceType, out result))
{
result = dependencyService ?? _defaultServicesSingle[serviceType];
_cacheSingle[serviceType] = result;
}
如果前面的 _configuration.DependencyResolver.GetService(serviceType)方法返回null,这里就用默认的_defaultServicesSingle中type对应的实例。
而HttpConfiguration的DependencyResolver属性如下:
private IDependencyResolver _dependencyResolver = EmptyResolver.Instance;
public IDependencyResolver DependencyResolver
{
get { return _dependencyResolver; }
set
{
if (value == null)
{
throw Error.PropertyNull();
}
_dependencyResolver = value;
}
}
看见HttpConfiguration的DependencyResolver默认是EmptyResolver.Instance,其GetService实现如下:
public object GetService(Type serviceType)
{
return null;
}
到这里我们的_bufferPolicySelector的创建就说完了。DependencyResolver这个东东在mvc里面也有,微软做 这个东东,无非就是让我们在需要的时候设置自己的类型实例。可能是自己接触面比较窄,在工作中我还没遇到要设置DependencyResolver这个 属性的需求。
下面我们来看看添加header时候用到一个 AddHeaderToHttpRequestMessage(request, headerName, values);方法,主要的实现代码如下:
private static void
AddHeaderToHttpRequestMessage(HttpRequestMessage httpRequestMessage,
string headerName, string[] headerValues)
{
if (!httpRequestMessage.Headers.TryAddWithoutValidation(headerName, headerValues))
{
httpRequestMessage.Content.Headers.TryAddWithoutValidation(headerName, headerValues);
}
}
这里的HttpRequestHeaders、HttpContentHeaders 都继承于HttpHeaders,TryAddWithoutValidation的实现在HttpHeaders类中
public bool TryAddWithoutValidation(string name, IEnumerable<string> values)
{
if (values == null)
{
throw new ArgumentNullException("values");
}
if (!this.TryCheckHeaderName(name))
{
return false;
}
HeaderStoreItemInfo orCreateHeaderInfo = this.GetOrCreateHeaderInfo(name, false);
foreach (string str in values)
{
AddValue(orCreateHeaderInfo, str ?? string.Empty, StoreLocation.Raw);
}
return true;
}
这里的具体是怎么添加的我们也就忽略它吧。
到这里我想我们大家对HttpRequestMessage的创建应该比较清楚了吧,直接实例
化 HttpRequestMessage request = new HttpRequestMessage(method,
uri);,然后主要设置它的Content属性和添加Content.Headers成员。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构