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成員


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM