HttpClientHelper

//--------------------------------------------------------------------------
//
//  Copyright (c) BUSHUOSX.  All rights reserved.
//
//  File: HttpClientHelper.cs
//
//  Version:1.0.0.1
//
//  Datetime:20170815
//
//-------------------------------------------------------------------------- 

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace BUSHUOSX.HTTP
{
    class HttpClientHelper
    {
        /// <summary>
        /// http task state
        /// </summary>
        class TASKSTATE
        {
            public object userState;
            public HttpClient httpClient;
            public TASKSTATE(object state,HttpClient client)
            {
                userState = state;
                httpClient = client;
            }
        }

        /// <summary>
        /// 不为Null时,任意http请求完成、取消、失败时回调
        /// </summary>
        Action<Task, object> _callbackOnAnyTaskComplited;
        /// <summary>
        /// 并发控制信号
        /// </summary>
        SemaphoreSlim _semaphore;
        /// <summary>
        /// 工作标记
        /// </summary>
        bool _isWorking;
        /// <summary>
        /// 共用httpclient。为Null时,为每个http请求new httpclient。
        /// </summary>
        HttpClient _httpClient;
        /// <summary>
        /// http request task 记录
        /// </summary>
        readonly ConcurrentDictionary<Task, TASKSTATE> _workingTasks = new ConcurrentDictionary<Task, TASKSTATE>();
        /// <summary>
        /// 启动的task计数。
        /// </summary>
        long _workingCount;//原子操作
        /// <summary>
        /// 任务取消标记
        /// </summary>
        CancellationTokenSource _cancelSource;
        /// <summary>
        /// 工作器监视线程
        /// </summary>
        Task _worker;
        /// <summary>
        /// 禁止自动启动任务
        /// </summary>
        bool _autoStartWorking = true;
        /// <summary>
        /// Http Request最大并发数
        /// </summary>
        public int MaxConcurrencyLevel { get; }
        /// <summary>
        /// Http Request超时设置,毫秒。小于等于0时,使用默认值。
        /// </summary>
        public int TimeoutMillisecond { get; }

        /// <summary>
        /// 可控制并发数的HttpClient
        /// </summary>
        /// <param name="concurrencyLevel">Http Request最大并发数</param>
        /// <param name="callbackOnAnyTaskComplited">不为Null时,任意http请求完成、取消、失败时回调。注意:如果使用,请保证方法的线程安全。</param>
        /// <param name="timeoutMillisecond">Http Request超时设置,毫秒。小于等于0时,使用默认值。</param>
        /// <param name="httpClient">留空则每个任务使用一个新的HttpClient对象</param>
        public HttpClientHelper(int concurrencyLevel, Action<Task, object> callbackOnAnyTaskComplited = null, int timeoutMillisecond = 0, HttpClient httpClient = null)
        {
            if (concurrencyLevel < 1)
            {
                throw new ArgumentOutOfRangeException("concurrencyLevel < 1");
            }
            MaxConcurrencyLevel = concurrencyLevel;
            _callbackOnAnyTaskComplited = callbackOnAnyTaskComplited;
            TimeoutMillisecond = timeoutMillisecond;
            _httpClient = httpClient;
        }

        /// <summary>
        /// 返回已发出的http请求数
        /// </summary>
        /// <returns></returns>
        public int GetWorkingTasksCount()
        {
            return _workingTasks.Count;
        }

        //public KeyValuePair<Task, object>[] GetTasks()
        //{
        //    return _workingTasks.ToArray();
        //}

        /// <summary>
        /// 停止工作器
        /// </summary>
        /// <param name="cancelPendingRequests">取消已发起的所有http请求</param>
        public void Stop(bool cancelPendingRequests = false)
        {
            _autoStartWorking = false;
            notifyEndWorker();
            _cancelSource.Cancel();
            if (_httpClient != null)
            {
                _httpClient.CancelPendingRequests();
            }
            else
            {
                foreach (var item in _workingTasks)
                {
                    if (item.Value.httpClient != null)
                    {
                        item.Value.httpClient.CancelPendingRequests();
                    }
                }
            }
            _workingTasks.Clear();
        }

        /// <summary>
        /// 重新启动工作器。stop之后使用。
        /// </summary>
        public void ReStart()
        {
            _autoStartWorking = true;
        }

        /// <summary>
        /// 阻塞直到所有http任务完成。
        /// </summary>
        public void WaitWorkComplited()
        {
            if (_worker != null)
            {
                _worker.Wait();
            }
        }

        /// <summary>
        /// 通过 http client 获取 string。超过并发数时会阻塞,直到有http request完成。
        /// </summary>
        /// <param name="address">http url string</param>
        /// <param name="state">用户状态。用于callbackOnAnyTaskComplited回调。</param>
        /// <returns></returns>
        public Task<string> GetString(string address, object state = null)
        {
            Interlocked.Increment(ref _workingCount);

            notifyStartWorker();

            if (!_isWorking)
            {
                Interlocked.Decrement(ref _workingCount);
                return null;
            }

            _semaphore.Wait(_cancelSource.Token);
            TASKSTATE tstate = new TASKSTATE(state, null);
            HttpClient client;
            try
            {
                if (_httpClient != null)
                {
                    client = _httpClient;
                }
                else
                {
                    client = new HttpClient();
                    if (TimeoutMillisecond > 0)
                    {
                        client.Timeout = TimeSpan.FromMilliseconds(TimeoutMillisecond);
                    }
                    tstate.httpClient = client;
                }
                var t = client.GetStringAsync(address);
                _workingTasks[t] = tstate;
                t.ContinueWith(anyTaskComplited,
                    _cancelSource.Token,
                    TaskContinuationOptions.OnlyOnRanToCompletion & TaskContinuationOptions.NotOnRanToCompletion,
                    TaskScheduler.Current);
                return t;
            }
            catch (HttpRequestException e)
            {
                Interlocked.Decrement(ref _workingCount);
                _semaphore.Release();
                throw new HttpRequestException(e.Message, e.InnerException);
            }
        }

        /// <summary>
        /// 任意http task完成时回调
        /// </summary>
        /// <param name="task"></param>
        private void anyTaskComplited(Task task)
        {
            TASKSTATE tstate;
            _workingTasks.TryRemove(task, out tstate);
            //Debug.Assert(tstate.userState == state);

            _callbackOnAnyTaskComplited?.Invoke(task, tstate.userState);
            _semaphore.Release();

            Interlocked.Decrement(ref _workingCount);
        }

        /// <summary>
        /// 工作器初始化
        /// </summary>
        private void notifyStartWorker()
        {
            if (_isWorking) return;

            if (!_autoStartWorking) return;

            //初始化
            _isWorking = true;
            Debug.WriteLine("httpClientWorker启动……");
            _semaphore = new SemaphoreSlim(MaxConcurrencyLevel, MaxConcurrencyLevel);
            _cancelSource = new CancellationTokenSource();
            //_workingCount = 0;

            if (_httpClient != null && TimeoutMillisecond > 0)
            {
                _httpClient.Timeout = TimeSpan.FromMilliseconds(TimeoutMillisecond);
            }

            _worker = Task.Run(new Action(workerMonitor), _cancelSource.Token);

            _worker.ContinueWith(a=>{ notifyEndWorker(); },TaskContinuationOptions.NotOnRanToCompletion & TaskContinuationOptions.OnlyOnRanToCompletion);
        }

        /// <summary>
        /// 工作器结束清理工作
        /// </summary>
        private void notifyEndWorker()
        {
            if (_isWorking)
            {
                _isWorking = false;
                Debug.WriteLine("httpClientWorker结束……");
            }
        }

        /// <summary>
        /// 任务工作器监视器
        /// </summary>
        private void workerMonitor()
        {
            do
            {
                Thread.Sleep(1000);
            } while (_workingTasks.Count > 0 || Interlocked.Read(ref _workingCount) > 0);
        }

    }
}
时间: 2024-10-12 20:42:32

HttpClientHelper的相关文章

C#微信开发之旅(二):基础类之HttpClientHelper

包含通过HttpClient发起get或post请求的方法,所有调用微信接口的操作都通过此类.话不多说,直接上代码: 1 public class HttpClientHelper 2 { 3 /// <summary> 4 /// get请求 5 /// </summary> 6 /// <param name="url"></param> 7 /// <returns></returns> 8 public s

C#微信开发之旅(二):基础类之HttpClientHelper(更新:SSL安全策略)

public class HttpClientHelper   2     {   3         /// <summary>   4         /// get请求   5         /// </summary>   6         /// <param name="url"></param>   7         /// <returns></returns>   8         pub

java HttpClientHelper

1 首先配置pom.xml,具体参考我的这篇文章:使用httpclient需要的maven依赖 2 上代码 import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.ap

网上找到的一个使用高德API把地址转为经纬度的API

import com.fengyunhe.helper.http.HttpClientHelper; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Cre

Web用户的身份验证及WebApi权限验证流程的设计和实现

前言:Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问,本文通过Form认证,Mvc的Controller基类及Action的权限验证来实现Web系统登录,Mvc前端权限校验以及WebApi服务端的访问校验功能. 1. Web Form认证介绍 Web应用的访问方式因为是基于浏览器的Http地址请求,所以需要验证用户身份的合法性.目前常见的方式是Form认证,其处理逻辑描述如下:1. 用户首先要在登录页面输入用户名和密码,然

WebApi 登录身份验证

前言:Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问,本文通过Form认证,Mvc的Controller基类及Action的权限验证来实现Web系统登录,Mvc前端权限校验以及WebApi服务端的访问校验功能. 1. Web Form认证介绍 Web应用的访问方式因为是基于浏览器的Http地址请求,所以需要验证用户身份的合法性.目前常见的方式是Form认证,其处理逻辑描述如下:1. 用户首先要在登录页面输入用户名和密码,然

本地JAVA开发页面使用AAD验证登录

我们前一篇文章介绍了本地使用APS.NET开发的WEB服务如何使用AZURE AD(AAD)验证登录,今天我们主要介绍本地使用JAVA开发的WEB服务如何使用AAD验证登录.其实方法跟ASP.NET是一样的,需要在AZURE中注册服务才可以,然后得到对应Client ID .Security ID.URL等信息.具体见下: 我们首先将代码整理,然后使用Eclipse打开即可,需要注意的是,我们建议使用Eclipse打开的时候使用Maven方式,这样打开的话会自动下载对应的jar包.很是方便. 我

Handler、Looper消息传递机制

一.Handler消息传递机制初步认识: (一).引入: 子线程没有办法对UI界面上的内容进行操作,如果操作,将抛出异常:CalledFromWrongThreadException 为了实现子线程中操作UI界面,Android中引入了Handler消息传递机制,目的是打破对主线程的依赖性. 什么是Handler? handler通俗一点讲就是用来在各个线程之间发送数据的处理对象.在任何线程中,只要获得了另一个线程的handler,则可以通过  handler.sendMessage(messa

Service一

一.Service: (一).Service 简介: 1.何谓"Service"? "Service" 意思即"服务"的意思, 像 Windows 上面的服务一样,服务是在后台上运行,承担着静悄悄的不为人所注意的工作.Service运行在后台,它是不可见的.无界面的程序. Service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity,这个时候程序要在后台继续播放:比如检测SD卡上文件的变化:再或者在后台记录用户的地