当前位置: 首页 > news >正文

网站的建设费 账务处理WordPress注册不提示

网站的建设费 账务处理,WordPress注册不提示,百度推广方式有哪些,企业组网配置实例今天#xff0c;我们深度研究一下IHttpClientFactory。一、前言最早#xff0c;我们是在Dotnet Framework中接触到HttpClient。HttpClient给我们提供了与HTTP交互的基本方式。但这个HttpClient在大量频繁使用时#xff0c;也会给我们抛出两个大坑#xff1a;一方面#xf… 今天我们深度研究一下IHttpClientFactory。 一、前言最早我们是在Dotnet Framework中接触到HttpClient。HttpClient给我们提供了与HTTP交互的基本方式。但这个HttpClient在大量频繁使用时也会给我们抛出两个大坑一方面如果我们频繁创建和释放HttpClient实例会导致Socket套接字资源耗尽原因是因为Socket关闭后的TIME_WAIT时间。这个问题不展开说如果需要可以去查TCP的生命周期。而另一方面如果我们创建一个HttpClient单例那当被访问的HTTP的DNS记录发生改变时会抛出异常因为HttpClient并不会允许这种改变。现在对于这个内容有了更优的解决方案。从Dotnet Core 2.1开始框架提供了一个新的内容IHttpClientFactory。IHttpClientFactory用来创建HTTP交互的HttpClient实例。它通过将HttpClient的管理和用于发送内容的HttpMessageHandler链分离出来来解决上面提到的两个问题。这里面重要的是管理管道终端HttpClientHandler的生命周期而这个就是实际连接的处理程序。除此之外IHttpClientFactory还可以使用IHttpClientBuilder方便地来定制HttpClient和内容处理管道通过前置配置创建出的HttpClient实现诸如设置基地址或添加HTTP头等操作。先来看一个简单的例子public void ConfigureServices(IServiceCollection services) {services.AddHttpClient(WangPlus, c {c.BaseAddress  new Uri(https://github.com/humornif);}).ConfigureHttpClient(c {c.DefaultRequestHeaders.Add(Accept, application/vnd.github.v3json);c.DefaultRequestHeaders.Add(User-Agent, HttpClientFactory-Sample);}); } 在这个例子中当调用ConfigureHttpClient()或AddHttpMessageHandler()来配置HttpClient时实际上是在向IOptions的实例HttpClientFactoryOptions添加配置。这个方法提供了非常多的配置选项具体可以去看微软的文档这儿不多说。 在类中使用IHttpClientFactory时也是同样的方式创建一个IHttpClientFactory的单例实例然后调用CreateClient(name)创建一个具有名称WangPlus的HttpClient。看下面的例子public class MyService {private readonly IHttpClientFactory _factory;public MyService(IHttpClientFactory factory){_factory  factory;}public async Task DoSomething(){HttpClient client  _factory.CreateClient(WangPlus);} } 用法很简单。 下面我们会针对CreateClient()进行剖析来深入理解IHttpClientFactory背后的内容。二、HttpClient HttpMessageHandler的创建过程CreateClient()方法是与IHttpClientFactory交互的主要方法。看一下CreateClient()的代码实现private readonly IOptionsMonitorHttpClientFactoryOptions _optionsMonitorpublic HttpClient CreateClient(string name) {HttpMessageHandler handler  CreateHandler(name);var client  new HttpClient(handler, disposeHandler: false);HttpClientFactoryOptions options  _optionsMonitor.Get(name);for (int i  0; i  options.HttpClientActions.Count; i){options.HttpClientActions[i](client);}return client; } 代码看上去很简单。首先通过CreateHandler()创建了一个HttpMessageHandler的处理管道并传入要创建的HttpClient的名称。有了这个处理管道就可以创建HttpClient并传递给处理管道。这儿需要注意的是disposeHandler:false这个参数用来保证当我们释放HttpClient的时候处理管理不会被释放掉因为IHttpClientFactory会自己完成这个管道的处理。然后从IOptionsMonitor的实例中获取已命名的客户机的HttpClientFactoryOptions。它来自Startup.ConfigureServices()中添加的HttpClient配置函数并设置了BaseAddress和Header等内容。最后将HttpClient返回给调用者。 理解了这个内容下面我们来看看CreateHandler(name)方法研究一下HttpMessageHandler管道是如何创建的。readonly ConcurrentDictionarystring, LazyActiveHandlerTrackingEntry _activeHandlers;;readonly Funcstring, LazyActiveHandlerTrackingEntry _entryFactory  (name) {return new LazyActiveHandlerTrackingEntry(() {return CreateHandlerEntry(name);}, LazyThreadSafetyMode.ExecutionAndPublication);};public HttpMessageHandler CreateHandler(string name) {ActiveHandlerTrackingEntry entry  _activeHandlers.GetOrAdd(name, _entryFactory).Value;entry.StartExpiryTimer(_expiryCallback);return entry.Handler; } 看这段代码CreateHandler()做了两件事创建或获取ActiveHandlerTrackingEntry开始一个计时器。_activeHandlers是一个ConcurrentDictionary里面保存的是HttpClient的名称例如上面代码中的WangPlus。这里使用Lazy是一个使GetOrAdd()方法保持线程安全的技巧。实际创建处理管道的工作在CreateHandlerEntry中它创建了一个ActiveHandlerTrackingEntry。ActiveHandlerTrackingEntry是一个不可变的对象包含HttpMessageHandler和IServiceScope注入。此外它还包含一个与StartExpiryTimer()一起使用的内部计时器用于在计时器过期时调用回调函数。看一下ActiveHandlerTrackingEntry的定义internal class ActiveHandlerTrackingEntry {public LifetimeTrackingHttpMessageHandler Handler { get; private set; }public TimeSpan Lifetime { get; }public string Name { get; }public IServiceScope Scope { get; }public void StartExpiryTimer(TimerCallback callback){// Starts the internal timer// Executes the callback after Lifetime has expired.// If the timer has already started, is noop} } 因此CreateHandler方法要么创建一个新的ActiveHandlerTrackingEntry要么从字典中检索条目然后启动计时器。 下一节我们来看看CreateHandlerEntry()方法如何创建ActiveHandlerTrackingEntry实例。三、在CreateHandlerEntry中创建和跟踪HttpMessageHandlerCreateHandlerEntry方法是创建HttpClient处理管道的地方。这个部分代码有点复杂我们简化一下以研究过程为主private readonly IServiceProvider _services;private readonly IHttpMessageHandlerBuilderFilter[] _filters;private ActiveHandlerTrackingEntry CreateHandlerEntry(string name) {IServiceScope scope  _services.CreateScope(); IServiceProvider services  scope.ServiceProvider;HttpClientFactoryOptions options  _optionsMonitor.Get(name);HttpMessageHandlerBuilder builder  services.GetRequiredServiceHttpMessageHandlerBuilder();builder.Name  name;ActionHttpMessageHandlerBuilder configure  Configure;for (int i  _filters.Length - 1; i  0; i--){configure  _filters[i].Configure(configure);}configure(builder);var handler  new LifetimeTrackingHttpMessageHandler(builder.Build());return new ActiveHandlerTrackingEntry(name, handler, scope, options.HandlerLifetime);void Configure(HttpMessageHandlerBuilder b){for (int i  0; i  options.HttpMessageHandlerBuilderActions.Count; i){options.HttpMessageHandlerBuilderActions[i](b);}} } 先用根DI容器创建一个IServiceScope从关联的IServiceProvider中获取关联的服务再从HttpClientFactoryOptions中找到对应名称的HttpClient和它的配置。从容器中查找的下一项是HttpMessageHandlerBuilder默认值是DefaultHttpMessageHandlerBuilder这个值通过创建一个主处理程序负责建立Socket套接字和发送请求的HttpClientHandler来构建处理管道。我们可以通过添加附加的委托来包装这个主处理程序来为请求和响应创建自定义管理。 附加的委托DelegatingHandlers类似于Core的中间件管道Configure()根据Startup.ConfigureServices()提供的配置构建DelegatingHandlers管道IHttpMessageHandlerBuilderFilter是注入到IHttpClientFactory构造函数中的过滤器用于在委托处理管道中添加额外的处理程序。 IHttpMessageHandlerBuilderFilter类似于IStartupFilters默认注册的是LoggingHttpMessageHandlerBuilderFilter。这个过滤器向委托管道添加了两个额外的处理程序管道开始位置的LoggingScopeHttpMessageHandler会启动一个新的日志Scope管道末端的LoggingHttpMessageHandler在请求被发送到主HttpClientHandler之前记录有关请求和响应的日志 最后整个管道被包装在一个LifetimeTrackingHttpMessageHandler中。管道处理完成后将与用于创建它的IServiceScope一起保存在一个新的ActiveHandlerTrackingEntry实例中并给定HttpClientFactoryOptions中定义的生存期(默认为两分钟)。该条目返回给调用者CreateHandler()方法添加到处理程序的ConcurrentDictionary中添加到新的HttpClient实例中在CreateClient()方法中并返回给原始调用者。在接下来的生存期两分钟内每当您调用CreateClient()时您将获得一个新的HttpClient实例但是它具有与最初创建时相同的处理程序管道。每个命名或类型化的HttpClient都有自己的消息处理程序管道。例如名称为WangPlus的两个HttpClient实例将拥有相同的处理程序链但名为api的HttpClient将拥有不同的处理程序链。 下一节我们研究下计时器过期后的清理处理。三、过期清理以默认时间来说两分钟后存储在ActiveHandlerTrackingEntry中的计时器将过期并触发StartExpiryTimer()的回调方法ExpiryTimer_Tick()。ExpiryTimer_Tick负责从ConcurrentDictionary池中删除处理程序记录并将其添加到过期处理程序队列中readonly ConcurrentQueueExpiredHandlerTrackingEntry _expiredHandlers;internal void ExpiryTimer_Tick(object state) {var active  (ActiveHandlerTrackingEntry)state;_activeHandlers.TryRemove(active.Name, out LazyActiveHandlerTrackingEntry found);var expired  new ExpiredHandlerTrackingEntry(active);_expiredHandlers.Enqueue(expired);StartCleanupTimer(); } 当一个处理程序从_activeHandlers集合中删除后当调用CreateClient()时它将不再与新的HttpClient一起分发但会保持在内存存直到引用此处理程序的所有HttpClient实例全部被清除后IHttpClientFactory才会最终释放这个处理程序管道。 IHttpClientFactory使用LifetimeTrackingHttpMessageHandler和ExpiredHandlerTrackingEntry来跟踪处理程序是否不再被引用。看下面的代码internal class ExpiredHandlerTrackingEntry {private readonly WeakReference _livenessTracker;public ExpiredHandlerTrackingEntry(ActiveHandlerTrackingEntry other){Name  other.Name;Scope  other.Scope;_livenessTracker  new WeakReference(other.Handler);InnerHandler  other.Handler.InnerHandler;}public bool CanDispose  !_livenessTracker.IsAlive;public HttpMessageHandler InnerHandler { get; }public string Name { get; }public IServiceScope Scope { get; } } 根据这段代码ExpiredHandlerTrackingEntry创建了对LifetimeTrackingHttpMessageHandler的弱引用。根据上一节所写的LifetimeTrackingHttpMessageHandler是管道中的“最外层”处理程序因此它是HttpClient直接引用的处理程序。对LifetimeTrackingHttpMessageHandler使用WeakReference意味着对管道中最外层处理程序的直接引用只有在HttpClient中。一旦垃圾收集器收集了所有这些HttpClientLifetimeTrackingHttpMessageHandler将没有引用因此也将被释放。ExpiredHandlerTrackingEntry可以通过WeakReference.IsAlive检测到。在将一个记录添加到_expiredHandlers队列之后StartCleanupTimer()将启动一个计时器该计时器将在10秒后触发。触发后调用CleanupTimer_Tick()方法检查是否对处理程序的所有引用都已过期。如果是处理程序和IServiceScope将被释放。如果没有它们被添加回队列清理计时器再次启动internal void CleanupTimer_Tick() {StopCleanupTimer();int initialCount  _expiredHandlers.Count;for (int i  0; i  initialCount; i){_expiredHandlers.TryDequeue(out ExpiredHandlerTrackingEntry entry);if (entry.CanDispose){try{entry.InnerHandler.Dispose();entry.Scope?.Dispose();}catch (Exception ex){}}else{_expiredHandlers.Enqueue(entry);}}if (_expiredHandlers.Count  0){StartCleanupTimer();} } 为了看清代码的流程这个代码我简单了。原始的代码中还有日志记录和线程锁相关的内容。这个方法比较简单遍历ExpiredHandlerTrackingEntry记录并检查是否删除了对LifetimeTrackingHttpMessageHandler处理程序的所有引用。如果有处理程序和IServiceScope就会被释放。如果仍然有对任何LifetimeTrackingHttpMessageHandler处理程序的活动引用则将条目放回队列并再次启动清理计时器。四、总结如果你看到了这儿那说明你还是很有耐心的。这篇文章是一个对源代码的研究能够帮我们理解IHttpClientFactory的运行方式以及它是以什么样的方式填补了旧的HttpClient的坑。有些时候看看源代码还是很有益处的。喜欢就来个三连让更多人因你而受益
http://wiki.neutronadmin.com/news/159549/

相关文章:

  • 哈尔滨企业建站系统模板wordpress admin改名
  • 网站分页需要前端做还是后端网站建站 宝
  • 网站静态代码检查 站长工具容桂均安网站建设
  • 域名历史记录查询网站高端装修公司怎么获客
  • 实木餐桌椅网站建设h5跟传统网站有啥区别
  • 重庆企业网站制作网站开发 图片储存
  • 滨海网站建设找哪家好深圳建设工程项目网站
  • 部门网站建设存在的问题wordpress实现投稿功能
  • 网站自己做还是用程序四川宜宾建设局官方网站
  • 精品课程网站建设wordpress云盘视频
  • 兰西网站建设整合营销传播经典案例
  • 深圳市建设网络有限公司网站建设局招标网站
  • 贵州做网站找谁wordpress获得链接地址
  • phpcms建设网站东莞哪家网站建设好
  • 做淘宝店和做网站广东企业信息查询系统
  • 网站开发好克拉玛依网站建设公司
  • icp网站域名怎么填写网站设计分辨率
  • 开源手机建站系统四平公司做网站
  • 南山商城网站建设哪家便宜服务器打不开网站
  • 做网站最主要北京餐饮品牌设计公司
  • 网站 租用服务器价格在自己电脑上建设网站
  • 个人asp网站模板下载jquery上传wordpress
  • 怎么建设批量模板网站高端品牌女装有哪些
  • 网站开发用百度快照优化
  • 域名注册服务商网站手机设计软件有哪些软件
  • 网站栏目英文wordpress剑侠情缘主题
  • 做网站做网站自己在线制作logo免费图片
  • 微信做明天展现网站要多少钱传统网站建设架构
  • 建设网站需要那些技术人员闵行北京网站建设
  • 百度网站免费电话最牛的设计网站建设