博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Asp.net web Api源码分析-HttpRequestMessage的创建
阅读量:7088 次
发布时间:2019-06-28

本文共 13558 字,大约阅读时间需要 45 分钟。

紧接着前文我们已经得到了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的一些介绍大家可以参考

其中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
(() => requestBase.IsLocal)); request.Properties.Add(HttpPropertyKeys.IncludeErrorDetailKey, new Lazy
(() => !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
_cacheMulti = new Dictionary
(); private readonly Dictionary
_cacheSingle = new Dictionary
(); private readonly Dictionary
_defaultServicesSingle = new Dictionary
(); private readonly Dictionary
> _defaultServicesMulti = new Dictionary
>(); 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
(new DefaultActionValueBinder()); SetSingle
(new ApiExplorer(configuration)); SetSingle
(new DefaultAssembliesResolver()); SetSingle
(new DefaultBodyModelValidator()); SetSingle
(new DefaultContentNegotiator()); SetSingle
(null); // Missing SetMultiple
(new ConfigurationFilterProvider(), new ActionDescriptorFilterProvider()); SetSingle
(null); SetSingle
(new ApiControllerActionInvoker()); SetSingle
(new ApiControllerActionSelector()); SetSingle
(new DefaultHttpControllerActivator()); SetSingle
(new DefaultHttpControllerSelector(configuration)); SetSingle
(new DefaultHttpControllerTypeResolver()); SetSingle
(new TraceManager()); SetSingle
(null); // This is a priority list. So put the most common binders at the top. SetMultiple
(new TypeConverterModelBinderProvider(), new TypeMatchModelBinderProvider(), new KeyValuePairModelBinderProvider(), new ComplexModelDtoModelBinderProvider(), new ArrayModelBinderProvider(), new DictionaryModelBinderProvider(), new CollectionModelBinderProvider(), new MutableObjectModelBinderProvider()); SetSingle
(new DataAnnotationsModelMetadataProvider()); SetMultiple
(new DataAnnotationsModelValidatorProvider(), new DataMemberModelValidatorProvider(), new InvalidModelValidatorProvider()); // This is an ordered list,so put the most common providers at the top. SetMultiple
(new QueryStringValueProviderFactory(), new RouteDataValueProviderFactory()); ModelValidatorCache validatorCache = new ModelValidatorCache(new Lazy
>(() => this.GetModelValidatorProviders())); configuration.RegisterForDispose(validatorCache); SetSingle
(validatorCache); _serviceTypesSingle = new HashSet
(_defaultServicesSingle.Keys); _serviceTypesMulti = new HashSet
(_defaultServicesMulti.Keys); // Reset the caches and the known dependency scope ResetCache(); } private void SetSingle
(T instance) where T : class { _defaultServicesSingle[typeof(T)] = instance; } private void SetMultiple
(params T[] instances) where T : class { var x = (IEnumerable
)instances; _defaultServicesMulti[typeof(T)] = new List(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 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 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成员

转载地址:http://bxyql.baihongyu.com/

你可能感兴趣的文章
Google LOGO现代舞舞蹈动画
查看>>
有人3见解
查看>>
[python]decimal常用操作和需要注意的地方
查看>>
Ubuntu 网卡信息2
查看>>
android 没有main函数,怎么找到程序执行入口呢?以及activity主要生命周期的方法说明...
查看>>
java中处理字符编码(网页与数据库)(转)
查看>>
[leetcode]Path Sum II
查看>>
NTFS For Mac 如何简单操作
查看>>
django 生成复杂的 PDF 文件(数据较多时)
查看>>
CodeForces 300C 最短路
查看>>
睡觉被憋醒
查看>>
Java 7 Fork/Join 框架
查看>>
c++中冒号(:)和双冒号(::)的用法
查看>>
dubbo工作原理
查看>>
驱动开发利器Microsoft Windows Driver Kit 7.1.0下载
查看>>
maven_项目的依赖、聚合、继承
查看>>
一个C++类的注释:
查看>>
Winsock IO模型之select模型
查看>>
开发规范
查看>>
union和union all的区别
查看>>