/// <summary> /// 处理远程请求方法,并返回需要的实体 /// </summary> /// <typeparam name="T">需要返回的实体类型</typeparam> /// <param name="request">远程请求组件的request基本信息</param> /// <param name="funcFormat">获取实体格式化方法</param> /// <param name="needCert">是否需要双向证书</param> /// <param name="checkSign">是否检查返回签名,个别接口没有</param> /// <returns>实体类型</returns> protected async Task <T> RestCommonAsync <T>(OssHttpRequest request, Func <HttpResponseMessage, Task <T> > funcFormat, bool needCert, bool checkSign) where T : WXPayBaseResp, new() { var t = default(T); try { var client = GetCertHttpClient(needCert); var resp = await client.RestSend(request); if (resp.IsSuccessStatusCode) { if (funcFormat != null) { t = await funcFormat(resp); } else { var contentStr = await resp.Content.ReadAsStringAsync(); t = GetRespResult <T>(contentStr); } } } catch (Exception ex) { LogHelper.Error(string.Concat("基类请求出错,错误信息:", ex.Message), "RestCommon", WXPayConfigProvider.ModuleName); t = new T().WithResp(SysRespTypes.AppError, "微信支付请求失败"); } return(t); }
/// <summary> /// 根据Tag群发消息接口 /// </summary> /// <param name="openIds"></param> /// <param name="msgType">群发的消息类型</param> /// <param name="data">素材消息的media_id, text类型时是content, wxcard 时是card_id </param> /// <param name="sendIgnoreReprint">当 send_ignore_reprint=1时,文章被判定为转载时,且原创文允许转载时,将继续进行群发操作。当 send_ignore_reprint =0时,文章被判定为转载时,将停止群发操作。send_ignore_reprint 默认为0</param> /// <returns></returns> public async Task <WXSendMassMsgResp> SendMassMsgByOpenIds(List <string> openIds, WXMassMsgType msgType, string data, int sendIgnoreReprint = 0) { var msgStr = new StringBuilder("{"); #region 拼接touser msgStr.Append("\"touser\":["); for (int i = 0; i < openIds.Count; i++) { if (i > 0) { msgStr.Append(","); } msgStr.Append("\"").Append(openIds[i]).Append("\""); } msgStr.Append("],"); #endregion // 拼接内容mediaid, content , cardid GenerateMsgBody(msgType, data, msgStr); msgStr.Append("}"); var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Post; req.AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/message/mass/send"); req.CustomBody = msgStr.ToString(); return(await RestCommonOffcialAsync <WXSendMassMsgResp>(req)); }
/// <summary> /// 获取授权者列表 /// </summary> /// <param name="grantorAppId"></param> /// <param name="offset"></param> /// <param name="count"></param> /// <returns></returns> public async Task <WXGetGrantorListResp> GetGrantorList(string grantorAppId, int offset, int count) { var appConfigRes = await GetMeta(); if (!appConfigRes.IsSuccess()) { return(new WXGetGrantorListResp().WithResp(appConfigRes)); } var appConfig = appConfigRes.data; var strContent = new StringBuilder(); strContent.Append("{\"component_appid\":\"").Append(appConfig.AppId).Append("\","); strContent.Append("\"offset\":\"").Append(offset).Append("\","); strContent.Append("\"count\":\"").Append(count).Append("\"}"); var req = new OssHttpRequest { AddressUrl = $"{m_ApiUrl}/cgi-bin/component/api_get_authorizer_list", HttpMethod = HttpMethod.Post, CustomBody = strContent.ToString() }; return(await RestCommonPlatAsync <WXGetGrantorListResp>(req)); }
/// <summary> /// 获取平台下当前授权账号的AccessToken响应实体 /// </summary> /// <param name="authorizationCode">授权code,会在授权成功时返回给第三方平台</param> /// <returns></returns> public async Task <WXGetGrantedAccessTokenResp> GetGrantorAccessToken(string authorizationCode) { var appConfigRes = await GetMeta(); if (!appConfigRes.IsSuccess()) { return(new WXGetGrantedAccessTokenResp().WithResp(appConfigRes)); } var appConfig = appConfigRes.data; var strContent = new StringBuilder(); strContent.Append("{\"component_appid\":\"").Append(appConfig.AppId).Append("\","); strContent.Append("\"authorization_code\":\"").Append(authorizationCode).Append("\" }"); var req = new OssHttpRequest { AddressUrl = $"{m_ApiUrl}/cgi-bin/component/api_query_auth", HttpMethod = HttpMethod.Post, CustomBody = strContent.ToString() }; return(await RestCommonPlatAsync <WXGetGrantedAccessTokenResp>(req)); }
/// <summary> /// 设置授权方的选项信息 /// location_report(地理位置上报选项) 0-无上报 1-进入会话时上报 2-每5s上报 /// voice_recognize(语音识别开关选项) 0-关闭语音识别 1-开启语音识别 /// customer_service(多客服开关选项) 0-关闭多客服 1-开启多客服 /// </summary> /// <param name="grantorAppId">授权公众号或小程序的appid</param> /// <param name="optionName">选项名称</param> /// <param name="optionValue">设置的选项值</param> /// <returns></returns> public async Task <WXBaseResp> SetGrantorOption(string grantorAppId, string optionName, string optionValue) { var appConfigRes = await GetMeta(); if (!appConfigRes.IsSuccess()) { return(new WXBaseResp().WithResp(appConfigRes)); } var appConfig = appConfigRes.data; var strContent = new StringBuilder(); strContent.Append("{\"component_appid\":\"").Append(appConfig.AppId).Append("\","); strContent.Append("\"authorizer_appid\":\"").Append(grantorAppId).Append("\","); strContent.Append("\"option_name\":\"").Append(optionName).Append("\","); strContent.Append("\"option_value\":\"").Append(optionValue).Append("\"}"); var req = new OssHttpRequest { AddressUrl = $"{m_ApiUrl}/cgi-bin/component/api_set_authorizer_option", HttpMethod = HttpMethod.Post, CustomBody = strContent.ToString() }; return(await RestCommonPlatAsync <WXBaseResp>(req)); }
/// <summary> /// 下载对账单 /// </summary> /// <param name="billReq"></param> /// <returns></returns> public async Task <Resp <string> > DownloadBillAsync(WXPayDownloadBillReq billReq) { var dics = billReq.GetDics(); dics.Add("appid", ApiConfig.AppId); dics.Add("mch_id", ApiConfig.MchId); CompleteDicSign(dics); var req = new OssHttpRequest { HttpMethod = HttpMethod.Post, AddressUrl = string.Concat(m_ApiUrl, "/pay/downloadbill"), CustomBody = dics.ProduceXml() }; var response = await req.RestSend(); if (!response.IsSuccessStatusCode) { return new Resp <string>() { ret = -1, msg = "当前请求出错!" } } ; var content = await response.Content.ReadAsStringAsync(); return(content.StartsWith("<xml>") ? new Resp <string>(content) : new Resp <string>().WithResp(RespTypes.OperateFailed, content)); } #endregion }
/// <summary> /// 下载文件方法 /// </summary> protected static async Task <WXFileResp> DownLoadFileAsync(OssHttpRequest req) { var resp = await req.RestSend(WXPlatConfigProvider.ClientFactory?.Invoke()); if (!resp.IsSuccessStatusCode) { return new WXFileResp() { ret = (int)RespTypes.ObjectStateError, msg = "当前请求失败!" } } ; var contentStr = resp.Content.Headers.ContentType.MediaType; using (resp) { if (!contentStr.Contains("application/json")) { return new WXFileResp() { content_type = contentStr, file = await resp.Content.ReadAsByteArrayAsync() } } ; return(JsonConvert.DeserializeObject <WXFileResp>(await resp.Content.ReadAsStringAsync())); } } #endregion } }
/// <summary> /// 根据Tag群发消息接口 /// </summary> /// <param name="openId">openid,wxName和openId同时赋值时,以wxname优先</param> /// <param name="wxName">微信名称,wxName和openId同时赋值时,以wxname优先</param> /// <param name="msgType">群发的消息类型</param> /// <param name="data">素材消息的media_id, text类型时是content, wxcard 时是card_id </param> /// <param name="sendIgnoreReprint">当 send_ignore_reprint=1时,文章被判定为转载时,且原创文允许转载时,将继续进行群发操作。当 send_ignore_reprint =0时,文章被判定为转载时,将停止群发操作。send_ignore_reprint 默认为0</param> /// <returns></returns> public async Task <WXSendMassMsgResp> PreviewMassMsgAsync(string wxName, string openId, WXMassMsgType msgType, string data, int sendIgnoreReprint = 0) { var msgStr = new StringBuilder("{"); #region 拼接 发送用户信息 if (!string.IsNullOrEmpty(wxName)) { msgStr.Append("\"towxname\":\"").Append(wxName).Append("\","); } if (!string.IsNullOrEmpty(openId)) { msgStr.Append("\"touser\":\"").Append(openId).Append("\","); } #endregion // 拼接内容mediaid, content , cardid GenerateMsgBody(msgType, data, msgStr); msgStr.Append("}"); var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Post; req.AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/message/mass/preview"); req.CustomBody = msgStr.ToString(); return(await RestCommonOffcialAsync <WXSendMassMsgResp>(req)); }
/// <summary> /// 写入请求的内容信息 (非文件上传请求) /// </summary> /// <param name="request"></param> /// <returns></returns> private static string GetNormalFormData(OssHttpRequest request) { var formstring = new StringBuilder(); if (request.FormParameters != null) { foreach (var p in request.FormParameters) { if (formstring.Length > 1) { formstring.Append("&"); } formstring.AppendFormat(p.ToString()); } } if (string.IsNullOrEmpty(request.CustomBody)) { return(formstring.ToString()); } if (formstring.Length > 1) { formstring.Append("&"); } formstring.Append(request.CustomBody); return(formstring.ToString()); }
/// <summary> /// 获取授权access_token (每个用户都是单独唯一) /// </summary> /// <param name="code">填写第一步获取的code参数</param> /// <returns></returns> public async Task <WXGetOauthAccessTokenResp> GetOauthAccessTokenAsync(string code) { var reqUrl = new StringBuilder(m_ApiUrl); if (ApiConfig.OperateMode == AppOperateMode.ByAgent) { var comAccessToken = WXOauthConfigProvider.AgentAccessTokenFunc?.Invoke(ApiConfig); if (string.IsNullOrEmpty(comAccessToken)) { throw new ArgumentNullException("AgentAccessToken", "AgentAccessToken未发现,请检查 WXOauthConfigProvider 下 AgentAccessTokenFunc 委托是否为空或者返回值不正确!"); } reqUrl.Append("/sns/oauth2/component/access_token?appid=").Append(ApiConfig.AppId) .Append("&code=").Append(code) .Append("&grant_type=authorization_code") .Append("&component_appid=").Append(ApiConfig.ByAppId) .Append("&component_access_token=").Append(comAccessToken); } else { reqUrl.Append("/sns/oauth2/access_token?appid=").Append(ApiConfig.AppId) .Append("&secret=").Append(ApiConfig.AppSecret) .Append("&code=").Append(code) .Append("&grant_type=authorization_code"); } var req = new OssHttpRequest { AddressUrl = reqUrl.ToString(), HttpMethod = HttpMethod.Get }; return(await RestCommonJson <WXGetOauthAccessTokenResp>(req)); }
/// <summary> /// 处理远程请求方法,并返回需要的实体 /// </summary> /// <typeparam name="T">需要返回的实体类型</typeparam> /// <param name="request">远程请求组件的request基本信息</param> /// <returns>实体类型</returns> protected static async Task <T> RestCommonJson <T>(OssHttpRequest request) where T : WXBaseResp, new() { var resp = await request.RestSend(WXPlatConfigProvider.ClientFactory?.Invoke()); if (!resp.IsSuccessStatusCode) { return new T() { ret = -(int)resp.StatusCode, msg = resp.ReasonPhrase } } ; var contentStr = await resp.Content.ReadAsStringAsync(); var t = JsonConvert.DeserializeObject <T>(contentStr); if (!t.IsSuccess()) { t.msg = t.errmsg; } return(t); }
/// <summary> /// 发送请求 /// </summary> /// <param name="request">请求的参数</param> /// <param name="completionOption"></param> /// <param name="token"></param> /// <param name="client"></param> /// <returns>自定义的Response结果</returns> public static Task <HttpResponseMessage> RestSend(this OssHttpRequest request, HttpCompletionOption completionOption, CancellationToken token, HttpClient client = null) { return((client ?? GetDefaultClient()).RestSend(request, completionOption, token)); }
/// <summary> /// 公众号主要Rest请求接口封装 /// 主要是预处理accesstoken赋值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="req"></param> /// <returns></returns> protected async Task <T> RestCommonOffcialAsync <T>(OssHttpRequest req) where T : WXBaseResp, new() { var tokenRes = await GetAccessTokenFromCacheAsync(); if (!tokenRes.IsSuccess()) { return(new T().WithResp(tokenRes)); // tokenRes.ConvertToResultInherit<T>(); } req.RequestSet = r => { r.Headers.Add("Accept", "application/json"); if (r.Content != null) { r.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json") { CharSet = "UTF-8" }; } }; req.AddressUrl = string.Concat(req.AddressUrl, req.AddressUrl.IndexOf('?') > 0 ? "&" : "?", "access_token=", tokenRes.access_token); return(await RestCommonJson <T>(req)); }
/// <summary> /// 配置使用的cotent /// </summary> /// <param name="reqMsg"></param> /// <param name="req"></param> /// <returns></returns> private static void ConfigReqContent(HttpRequestMessage reqMsg, OssHttpRequest req) { if (req.HttpMethod == HttpMethod.Get) { req.RequestSet?.Invoke(reqMsg); return; } if (req.HasFile) { var boundary = GetBoundary(); var memory = new MemoryStream(); WriteMultipartFormData(memory, req, boundary); memory.Seek(0, SeekOrigin.Begin);//设置指针到起点 reqMsg.Content = new StreamContent(memory); req.RequestSet?.Invoke(reqMsg); reqMsg.Content.Headers.Remove("Content-Type"); reqMsg.Content.Headers.TryAddWithoutValidation("Content-Type", $"multipart/form-data;boundary={boundary}"); } else { var data = GetNormalFormData(req); reqMsg.Content = new StringContent(data); req.RequestSet?.Invoke(reqMsg); } }
/// <summary> /// 获取客服的用户会话列表 /// </summary> /// <param name="account">客服账号</param> /// <returns></returns> public async Task <WXGetKfSessionsByAccountResp> GetKfSessionsByAccount(string account) { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/customservice/kfsession/getsessionlist?kf_account=", account); return(await RestCommonOffcialAsync <WXGetKfSessionsByAccountResp>(req)); }
/// <summary> /// 获取用户客服会话信息 /// </summary> /// <param name="openId"></param> /// <returns></returns> public async Task <WXGetUserKfSessionResp> GetUserKfSession(string openId) { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/customservice/kfsession/getsession?openid=", openId); return(await RestCommonOffcialAsync <WXGetUserKfSessionResp>(req)); }
/// <summary> /// 获取在线客服列表 /// </summary> /// <returns></returns> public async Task <WXGetKfOnlineResp> GetKfOnlineList() { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/customservice/getonlinekflist"); return(await RestCommonOffcialAsync <WXGetKfOnlineResp>(req)); }
/// <summary> /// 删除客服账号 /// </summary> /// <param name="account">完整客服账号,格式为:账号前缀@公众号微信号</param> /// <returns></returns> public async Task <WXBaseResp> DeleteKFAccountAsync(string account) { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/customservice/kfaccount/del?kf_account=", account); return(await RestCommonOffcialAsync <WXBaseResp>(req)); }
/// <summary> /// 获取门店类目列表 /// </summary> /// <returns></returns> public async Task <WXStoreCategoryResp> GetStoreCategoryAsync() { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = String.Concat(m_ApiUrl, "/cgi-bin/poi/getwxcategory"); return(await RestCommonOffcialAsync <WXStoreCategoryResp>(req)); }
/// <summary> /// 删除菜单 /// </summary> /// <returns></returns> public async Task <WXBaseResp> DeleteMenuAsync() { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/menu/delete"); return(await RestCommonPlatAsync <WXBaseResp>(req)); }
/// <summary> /// 获取用户openid列表 /// </summary> /// <param name="next_openid">第一个拉取的OPENID,不填默认从头开始拉取</param> /// <returns></returns> public async Task <WXOpenIdsResp> GetOpenIdListAsync(string next_openid = "") { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/user/get?next_openid=", next_openid); return(await RestCommonOffcialAsync <WXOpenIdsResp>(req)); }
/// <summary> /// 获取公众号已创建的标签 /// </summary> /// <returns></returns> public async Task <WXGetTagListResp> GetTagListAsync() { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/tags/get"); return(await RestCommonOffcialAsync <WXGetTagListResp>(req)); }
/// <summary> /// 获取未接入会话列表 /// </summary> /// <returns></returns> public async Task <WXGetKfWaitUserListResp> GetKfWaitUserList() { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/customservice/kfsession/getwaitcase?"); return(await RestCommonOffcialAsync <WXGetKfWaitUserListResp>(req)); }
/// <summary> /// 获取客服基本信息列表 /// </summary> /// <returns></returns> public async Task <WXGetKFAccountListResp> GetKFAccountListAsync() { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/customservice/getkflist"); return(await RestCommonPlatAsync <WXGetKFAccountListResp>(req)); }
/// <summary> /// 获取用户基本信息(UnionID机制) /// </summary> /// <param name="userReq">请求参数</param> /// <returns></returns> public async Task <WXPlatUserInfoResp> GetUserInfoAsync(WXPlatUserInfoReq userReq) { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Get; req.AddressUrl = string.Concat(m_ApiUrl, $"/cgi-bin/user/info?openid={userReq.openid}&lang={userReq.lang}"); return(await RestCommonOffcialAsync <WXPlatUserInfoResp>(req)); }
/// <summary> /// 添加永久微信图文素材(文章组合) /// </summary> /// <param name="list"></param> /// <returns></returns> public async Task <WXMediaResp> AddArticleGroupAsync(IList <WXArticleInfo> list) { var req = new OssHttpRequest(); req.HttpMethod = HttpMethod.Post; req.AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/material/add_news"); req.CustomBody = JsonConvert.SerializeObject(new { articles = list }); return(await RestCommonPlatAsync <WXMediaResp>(req)); }
/// <summary> /// 获取视频素材【临时素材】下载地址 /// </summary> /// <param name="mediaId"></param> /// <returns></returns> public async Task <WXMediaTempVideoUrlResp> GetTempMediaVedioUrlAsync(string mediaId) { var req = new OssHttpRequest { HttpMethod = HttpMethod.Get, AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/media/get?media_id=", mediaId) }; return(await RestCommonPlatAsync <WXMediaTempVideoUrlResp>(req)); }
/// <summary> /// 获取素材总数 /// </summary> /// <returns></returns> public async Task <WXMediaCountResp> GetMediaCountAsync() { var req = new OssHttpRequest { HttpMethod = HttpMethod.Get, AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/material/get_materialcount") }; return(await RestCommonPlatAsync <WXMediaCountResp>(req)); }
/// <summary> /// 获取素材【临时素材】 文件流 /// </summary> /// <param name="mediaId"></param> /// <returns></returns> public async Task <WXFileResp> DownloadTempMediaAsync(string mediaId) { var req = new OssHttpRequest { HttpMethod = HttpMethod.Get, AddressUrl = string.Concat(m_ApiUrl, $"/cgi-bin/media/get?media_id={mediaId}") }; return(await DownLoadFileAsync(req)); }
/// <summary> /// 下载【永久】素材文件 /// 视频 和 图文 请通过另外两个接口获取 /// </summary> /// <param name="mediaId"></param> /// <returns></returns> public async Task <WXFileResp> DownloadMediaAsync(string mediaId) { var req = new OssHttpRequest { HttpMethod = HttpMethod.Post, AddressUrl = string.Concat(m_ApiUrl, "/cgi-bin/material/get_material") }; return(await DownLoadFileAsync(req)); }