using System; using System.Collections.Concurrent; using System.Net; using Newtonsoft.Json; using Common; using System.Threading.Tasks; namespace ZcPeng.weixin.PublicAccount { /// /// 微信许可令牌 /// public class AccessToken { /// /// 保存已获取到的许可令牌,键为公众号,值为公众号最后一次获取到的令牌 /// private static ConcurrentDictionary> accessTokens = new ConcurrentDictionary>(); /// /// 获取access token的地址 /// private const string urlForGettingAccessToken = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"; /// /// 获取access token的http方法 /// private const string httpMethodForGettingAccessToken = WebRequestMethods.Http.Get; /// /// 保存access token的最长时间(单位:秒),超过时间之后,需要重新获取 /// private const int accessTokenSavingSeconds = 7000; /// /// access token /// public string access_token { get; set; } /// /// 有效时间,单位:秒 /// public int expires_in { get; set; } /// /// 构造函数 /// /// access token /// 有效时间 internal AccessToken(string _access_token, int _expires_in) { access_token = _access_token; expires_in = _expires_in; } /// /// 返回AccessToken字符串 /// /// public override string ToString() { return string.Format("AccessToken:{0}\r\n有效时间:{1}秒", access_token, expires_in); } /// /// 从JSON字符串解析AccessToken /// /// JSON字符串 /// 返回AccessToken internal static AccessToken ParseFromJson(string json) { var at = JsonConvert.DeserializeAnonymousType(json, new { access_token = "", expires_in = 1 }); return new AccessToken(at.access_token, at.expires_in); } /// /// 尝试从JSON字符串解析AccessToken /// /// JSON字符串 /// 如果解析成功,返回AccessToken;否则,返回null。 /// 返回是否解析成功 internal static bool TryParseFromJson(string json, out AccessToken token) { bool success = false; token = null; try { token = ParseFromJson(json); success = true; } catch { } return success; } /// /// 得到access token /// /// 公众号 /// 返回access token public static AccessToken Get(string userName) { Tuple lastToken = accessTokens.ContainsKey(userName) ? accessTokens[userName] : null; AccessToken token = lastToken == null ? null : lastToken.Item1; DateTime refreshTime = lastToken == null ? DateTime.MinValue : lastToken.Item2; if ((DateTime.Now - refreshTime).TotalSeconds > accessTokenSavingSeconds || token == null) { //尝试从微信服务器获取2次 ErrorMessage msg; AccessToken newToken = GetFromWeixinServer(userName, out msg); if (newToken == null) newToken = GetFromWeixinServer(userName, out msg); if (newToken != null) { lastToken = new Tuple(newToken, DateTime.Now); accessTokens[userName] = lastToken; token = newToken; Message msg1 = new Message(Guid.NewGuid(), MessageType.Request, token.ToString(), DateTime.Now, "GetToken", msg.errmsg); Message.Insert(msg1); } else { Message msg1 = new Message(Guid.NewGuid(), MessageType.Request, msg.errcode == 0 ? "" : msg.errcode.ToString(), DateTime.Now, "GetToken", msg.errcode+":"+msg.errmsg); Message.Insert(msg1); return null; } } return token; } /// /// 从微信服务器获取access token /// /// 公众号 /// 从服务器返回的错误信息。 /// 返回许可令牌;如果获取失败,返回null。 private static AccessToken GetFromWeixinServer(string userName, out ErrorMessage msg) { AccessToken token = null; msg = new ErrorMessage(ErrorMessage.ExceptionCode, ""); AccountInfo account = AccountInfoCollection.GetAccountInfo(userName); if (account == null) { msg.errmsg = "获取公众号参数失败。"; return token; } string url = string.Format(urlForGettingAccessToken, account.AppId, account.AppSecret); string result = HttpHelper.HttpPost(url, httpMethodForGettingAccessToken, "application/text").Result; if(result =="") { msg.errmsg = "从微信服务器获取响应失败。"; return token; } if (ErrorMessage.IsErrorMessage(result)) msg = ErrorMessage.Parse(result); else { try { token = AccessToken.ParseFromJson(result); } catch (Exception e) { msg = new ErrorMessage(e); } } return token; } } }