/// <summary> /// 事件之发送模板消息返回结果 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override IResponseMessageBase OnEvent_TemplateSendJobFinishRequest(RequestMessageEvent_TemplateSendJobFinish requestMessage) { switch (requestMessage.Status) { case "success": //发送成功 break; case "failed:user block": //送达由于用户拒收(用户设置拒绝接收公众号消息)而失败 break; case "failed: system failed": //送达由于其他原因失败 break; default: throw new WeixinException("未知模板消息状态:" + requestMessage.Status); } //注意:此方法内不能再发送模板消息,否则会造成无限循环! try { var msg = @"已向您发送模板消息状态:{0}MsgId:{1}".FormatWith(requestMessage.Status, requestMessage.MsgID); CustomApi.SendText(appId, WeixinOpenId, msg);//发送客服消息 } catch (Exception e) { WeixinTrace.SendCustomLog("模板消息发送失败", e.ToString()); } return(null); }
public ActionResult GetAccessToken() { //WeixinNullReferenceException 处理 var myclass = new MyClass(); try { if (myclass.Data == null) { throw new WeixinNullReferenceException("MyClass Data Is Null", myclass); } } catch (WeixinNullReferenceException ex) { var obj = ex.ParentObject as MyClass; if (obj != null) { obj.Data = "Data Is Null"; } Senparc.Weixin.WeixinTrace.SendCustomLog("系统日志", "MyClass Data Is Null"); } var accessToken = AccessTokenContainer.GetAccessToken(Config.AppId, true); //自定义 Log WeixinTrace.SendCustomLog("TestLog", "哈哈哈"); return(Content("accessToken获取成功:" + accessToken.Substring(0, 20) + "\n" + Config.LogRecordCount.ToString())); }
public async Task <IActionResult> DecodeEncryptedData(string type, string sessionId, string encryptedData, string iv) { DecodeEntityBase decodedEntity = null; try { switch (type.ToUpper()) { case "USERINFO": //wx.getUserInfo() decodedEntity = EncryptHelper.DecodeUserInfoBySessionId( sessionId, encryptedData, iv); break; default: break; } } catch (Exception ex) { WeixinTrace.SendCustomLog("EncryptHelper.DecodeUserInfoBySessionId 方法出错", $@"sessionId: {sessionId} encryptedData: {encryptedData} iv: {iv} sessionKey: { (await SessionContainer.CheckRegisteredAsync(sessionId) ? (await SessionContainer.GetSessionAsync(sessionId)).SessionKey : "未保存sessionId")} 异常信息: {ex.ToString()} "); } //检验水印 var checkWatermark = false; if (decodedEntity != null) { checkWatermark = decodedEntity.CheckWatermark(WxOpenAppId); //保存用户信息(可选) if (checkWatermark && decodedEntity is DecodedUserInfo decodedUserInfo) { var sessionBag = await SessionContainer.GetSessionAsync(sessionId); if (sessionBag != null) { await SessionContainer.AddDecodedUserInfoAsync(sessionBag, decodedUserInfo); } } } //注意:此处仅为演示,敏感信息请勿传递到客户端! return(Json(new { success = checkWatermark, //decodedEntity = decodedEntity, msg = $"水印验证:{(checkWatermark ? "通过" : "不通过")}" })); }
/// <summary> /// OAuthScope.snsapi_base方式回调 /// </summary> /// <param name="code"></param> /// <param name="state"></param> /// <param name="returnUrl">用户最初尝试进入的页面</param> /// <returns></returns> public ActionResult BaseCallback(string code, string state, string returnUrl) { try { if (string.IsNullOrEmpty(code)) { return(Content("您拒绝了授权!")); } if (state != HttpContext.Session.GetString("State")) { //这里的state其实是会暴露给客户端的,验证能力很弱,这里只是演示一下, //建议用完之后就清空,将其一次性使用 //实际上可以存任何想传递的数据,比如用户ID,并且需要结合例如下面的Session["OAuthAccessToken"]进行验证 return(Content("验证失败!请从正规途径进入!")); } //通过,用code换取access_token var result = OAuthApi.GetAccessToken(appId, appSecret, code); if (result.errcode != ReturnCode.请求成功) { return(Content("错误:" + result.errmsg)); } //下面2个数据也可以自己封装成一个类,储存在数据库中(建议结合缓存) //如果可以确保安全,可以将access_token存入用户的cookie中,每一个人的access_token是不一样的 HttpContext.Session.SetString("OAuthAccessTokenStartTime", SystemTime.Now.ToString()); HttpContext.Session.SetString("OAuthAccessToken", result.ToJson()); //因为这里还不确定用户是否关注本微信,所以只能试探性地获取一下 OAuthUserInfo userInfo = null; try { //已关注,可以得到详细信息 userInfo = OAuthApi.GetUserInfo(result.access_token, result.openid); if (!string.IsNullOrEmpty(returnUrl)) { return(Redirect(returnUrl)); } ViewData["ByBase"] = true; return(View("UserInfoCallback", userInfo)); } catch (ErrorJsonResultException ex) { Console.WriteLine(ex); //未关注,只能授权,无法得到详细信息 //这里的 ex.JsonResult 可能为:"{\"errcode\":40003,\"errmsg\":\"invalid openid\"}" return(Content("用户已授权,授权Token:" + result)); } } catch (Exception ex) { WeixinTrace.SendCustomLog("BaseCallback 发生错误", ex.ToString()); return(Content("发生错误:" + ex.ToString())); } }
public ActionResult GetAuthorizerInfoResultPage(string authorizerAppId) { WeixinTrace.SendCustomLog("查询授权信息json", authorizerAppId);//记录到日志中 var getAuthorizerInfoResult = AuthorizerContainer.GetAuthorizerInfoResult(component_AppId, authorizerAppId); getAuthorizerInfoResult.authorization_info.authorizer_appid = authorizerAppId; return(Json(getAuthorizerInfoResult, JsonRequestBehavior.AllowGet)); }
public ActionResult Result(string openId, string template_id, int scene, string reserved) { //template_id就是微信后台可以看到的template_id if (reserved != Session["WeixinSubscribeMsgReserved"] as string) { //reserved用于保持请求和回调的状态,授权请后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验,开发者可以填写a-zA-Z0-9的参数值,最多128字节 return(Content("请求错误!")); } WeixinTrace.SendCustomLog("一次性订阅消息-参数", string.Format("openId:{0},templateId:{1},scene:{2}", openId, template_id, scene)); var action = Request.QueryString["action"];//MVC直接通过Action获取到的action参数为ActionName if (action == "confirm") { //发送提示 var data = new { content = new { value = "Value", color = "#00ff00" } }; //var data1 = new //{ // content = new[] // { // new{ // value = "Value", // color = "#00ff00" // } // } //}; try { TemplateApi.Subscribe(base.AppId, openId, template_id, scene, "这是一条“一次性订阅消息”", data); return(Content("发送成功!")); } catch (ErrorJsonResultException e) { if (e.JsonResult.errcode == ReturnCode.api功能未授权) { return(Content("功能正常,由于微信官方(程序或文档)问题,返回错误:" + e.JsonResult.errcode + "。请等待微信官方更新!")); } else { return(Content("发生错误:" + e.Message)); } } } else { return(Content("您已取消授权!")); } }
/// <summary> /// H5支付 /// </summary> /// <param name="productId"></param> /// <param name="hc"></param> /// <returns></returns> public async Task <IActionResult> H5Pay(int productId, int hc) { try { //获取产品信息 var products = ProductModel.GetFakeProductList(); var product = products.FirstOrDefault(z => z.Id == productId); if (product == null || product.GetHashCode() != hc) { return(Content("商品信息不存在,或非法进入!1002")); } string openId = null;//此时在外部浏览器,无法或得到OpenId string sp_billno = Request.Query["order_no"]; if (string.IsNullOrEmpty(sp_billno)) { //生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一 sp_billno = string.Format("{0}{1}{2}", TenPayV3Info.MchId /*10位*/, SystemTime.Now.ToString("yyyyMMddHHmmss"), TenPayV3Util.BuildRandomStr(6)); } else { sp_billno = Request.Query["order_no"]; } var timeStamp = TenPayV3Util.GetTimestamp(); var nonceStr = TenPayV3Util.GetNoncestr(); var body = product == null ? "test" : product.Name; var price = product == null ? 100 : (int)(product.Price * 100); var notifyUrl = TenPayV3Info.TenPayV3Notify.Replace("/TenpayV3/", "/TenpayRealV3/"); TransactionsRequestData.Scene_Info sence_info = new(HttpContext.UserHostAddress()?.ToString(), null, null, new("Wap", null, null, null, null)); TransactionsRequestData requestData = new(TenPayV3Info.AppId, TenPayV3Info.MchId, body, sp_billno, new TenpayDateTime(DateTime.Now.AddHours(1), false), null, notifyUrl, null, new() { currency = "CNY", total = price }, new(openId), null, null, sence_info); WeixinTrace.SendCustomLog("H5Pay接口请求", requestData.ToJson()); var result = await _basePayApis.H5Async(requestData); WeixinTrace.SendCustomLog("H5Pay接口返回", result.ToJson()); if (!result.VerifySignSuccess == true) { return(Content("未通过验证,请检查数据有效性!")); } //直接跳转 return(Redirect(result.h5_url)); } catch (Exception ex) { WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); throw; } }
/// <summary> /// 尝试下载 /// </summary> /// <param name="code"></param> /// <returns></returns> public ActionResult Download(string guid) { var success = CheckCanDownload(guid); if (!success) { string message = null; var guidNotFound = !ConfigHelper.CodeCollection.ContainsKey(guid); if (guidNotFound) { message = "审核失败,请从官方下载页面进入!"; } else { var codeRecord = ConfigHelper.CodeCollection[guid]; if (!codeRecord.AllowDownload) { message = string.Format("审核失败,文件不允许下载,或已经下载过!如需重新下载请刷新浏览器!(101 - {0})", guid); } } message = message ?? string.Format("未通过审核,或此二维码已过期,请刷新网页后重新操作!(102 - {0})", guid); var file = File(Encoding.UTF8.GetBytes(message), "text/plain"); file.FileDownloadName = "下载失败.txt"; return(file); } else { var codeRecord = ConfigHelper.CodeCollection[guid]; codeRecord.Used = true; //codeRecord.AllowDownload = false;//这里如果只允许一次下载,有的浏览器插件或者防护软件会自动访问页面上的链接,导致用户真实的下载时效 var configHelper = new ConfigHelper(); var filePath = configHelper.Download(codeRecord.Version, codeRecord.IsWebVersion).Replace("/", "\\"); //var file = File(filePath, "application/octet-stream");(此方法在.net core中会失败) //使用流的方式来发送 var fs = new FileStream(filePath, FileMode.Open); var ms = new MemoryStream(); fs.CopyTo(ms); ms.Seek(0, SeekOrigin.Begin); var file = File(ms, "application/octet-stream"); var fileName = string.Format("Senparc.Weixin{0}-v{1}.{2}", codeRecord.IsWebVersion ? "-Web" : "", codeRecord.Version, filePath.Split('.').Last()//同步扩展名 ); file.FileDownloadName = fileName; WeixinTrace.SendCustomLog("download-path", filePath + " , " + file.FileDownloadName); return(file); } }
public ActionResult GetPrepayid(string sessionId) { try { var sessionBag = SessionContainer.GetSession(sessionId); var openId = sessionBag.OpenId; //生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一 var sp_billno = string.Format("{0}{1}{2}", Config.SenparcWeixinSetting.TenPayV3_MchId /*10位*/, SystemTime.Now.ToString("yyyyMMddHHmmss"), TenPayV3Util.BuildRandomStr(6)); var timeStamp = TenPayV3Util.GetTimestamp(); var nonceStr = TenPayV3Util.GetNoncestr(); var body = "小程序微信支付Demo"; var price = 1;//单位:分 var xmlDataInfo = new TenPayV3UnifiedorderRequestData(WxOpenAppId, Config.SenparcWeixinSetting.TenPayV3_MchId, body, sp_billno, price, Request.UserHostAddress, Config.SenparcWeixinSetting.TenPayV3_WxOpenTenpayNotify, TenPay.TenPayV3Type.JSAPI, openId, Config.SenparcWeixinSetting.TenPayV3_Key, nonceStr); var result = TenPayV3.Unifiedorder(xmlDataInfo);//调用统一订单接口 WeixinTrace.SendCustomLog("统一订单接口调用结束", "请求:" + xmlDataInfo.ToJson() + "\r\n\r\n返回结果:" + result.ToJson()); var packageStr = "prepay_id=" + result.prepay_id; //记录到缓存 var cacheStrategy = CacheStrategyFactory.GetObjectCacheStrategyInstance(); cacheStrategy.Set($"WxOpenUnifiedorderRequestData-{openId}", xmlDataInfo, TimeSpan.FromDays(4));//3天内可以发送模板消息 cacheStrategy.Set($"WxOpenUnifiedorderResultData-{openId}", result, TimeSpan.FromDays(4));//3天内可以发送模板消息 return Json(new { success = true, prepay_id = result.prepay_id, appId = Config.SenparcWeixinSetting.WxOpenAppId, timeStamp, nonceStr, package = packageStr, //signType = "MD5", paySign = TenPayV3.GetJsPaySign(WxOpenAppId, timeStamp, nonceStr, packageStr, Config.SenparcWeixinSetting.TenPayV3_Key) }); } catch (Exception ex) { return Json(new { success = false, msg = ex.Message }); } }
public void ConfigOnWeixinExceptionFunc(WeixinException ex) { try { string desc = "发生错误" + ex.GetType().Name; string message = ex.Message; WeixinTrace.SendCustomLog(desc, desc); } catch (Exception e) { WeixinTrace.SendCustomLog("OnWeixinExceptionFunc过程错误", e.Message); } }
/// <summary> /// OAuthScope.snsapi_base方式回调 /// </summary> /// <param name="code"></param> /// <param name="returnUrl">用户最初尝试进入的页面</param> /// <returns></returns> public ActionResult BaseCallback(string code, string returnUrl) { try { if (string.IsNullOrEmpty(code)) { return(Content("您拒绝了授权!")); } //通过,用code换取access_token var result = OAuthApi.GetAccessToken(appId, appSecret, code); if (result.errcode != ReturnCode.请求成功) { return(Content("错误:" + result.errmsg)); } //下面2个数据也可以自己封装成一个类,储存在数据库中(建议结合缓存) //如果可以确保安全,可以将access_token存入用户的cookie中,每一个人的access_token是不一样的 HttpContext.Session.SetString("OAuthAccessTokenStartTime", SystemTime.Now.ToString()); HttpContext.Session.SetString("OAuthAccessToken", result.ToJson()); //因为这里还不确定用户是否关注本微信,所以只能试探性地获取一下 OAuthUserInfo userInfo = null; try { //已关注,可以得到详细信息 userInfo = OAuthApi.GetUserInfo(result.access_token, result.openid); if (!string.IsNullOrEmpty(returnUrl)) { return(Redirect(returnUrl)); } ViewData["ByBase"] = true; return(View("UserInfoCallback", userInfo)); } catch (ErrorJsonResultException ex) { //未关注,只能授权,无法得到详细信息 //这里的 ex.JsonResult 可能为:"{\"errcode\":40003,\"errmsg\":\"invalid openid\"}" return(Content("用户已授权,授权Token:" + result, "text/html", Encoding.UTF8)); } } catch (Exception ex) { WeixinTrace.SendCustomLog("BaseCallback 发生错误", ex.ToString()); return(Content("发生错误:" + ex.ToString())); } }
/// <summary> /// 退款通知地址 /// </summary> /// <returns></returns> public async Task <IActionResult> RefundNotifyUrl() { WeixinTrace.SendCustomLog("RefundNotifyUrl被访问", "IP" + HttpContext.UserHostAddress()?.ToString()); NotifyReturnData returnData = new(); try { var resHandler = new TenPayNotifyHandler(HttpContext); var refundNotifyJson = await resHandler.AesGcmDecryptGetObjectAsync <RefundNotifyJson>(); WeixinTrace.SendCustomLog("跟踪RefundNotifyUrl信息", refundNotifyJson.ToJson()); string refund_status = refundNotifyJson.refund_status; if (/*refundNotifyJson.VerifySignSuccess == true &*/ refund_status == "SUCCESS") { returnData.code = "SUCCESS"; returnData.message = "OK"; //获取接口中需要用到的信息 例 string transaction_id = refundNotifyJson.transaction_id; string out_trade_no = refundNotifyJson.out_trade_no; string refund_id = refundNotifyJson.refund_id; string out_refund_no = refundNotifyJson.out_refund_no; int total_fee = refundNotifyJson.amount.payer_total; int refund_fee = refundNotifyJson.amount.refund; //填写逻辑 WeixinTrace.SendCustomLog("RefundNotifyUrl被访问", "验证通过"); } else { returnData.code = "FAILD"; returnData.message = "验证失败"; WeixinTrace.SendCustomLog("RefundNotifyUrl被访问", "验证失败"); } //进行后续业务处理 } catch (Exception ex) { returnData.code = "FAILD"; returnData.message = ex.Message; WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); } //https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_3.shtml return(Json(returnData)); }
public override IResponseMessageBase OnUnknownTypeRequest(RequestMessageUnknownType requestMessage) { /* * 此方法用于应急处理SDK没有提供的消息类型, * 原始XML可以通过requestMessage.RequestDocument(或this.RequestDocument)获取到。 * 如果不重写此方法,遇到未知的请求类型将会抛出异常(v14.8.3 之前的版本就是这么做的) */ var msgType = Senparc.NeuChar.Helpers.MsgTypeHelper.GetRequestMsgTypeString(requestMessage.RequestDocument); var responseMessage = this.CreateResponseMessage <ResponseMessageText>(); responseMessage.Content = "未知消息类型:" + msgType; WeixinTrace.SendCustomLog("未知请求消息类型", requestMessage.RequestDocument.ToString());//记录到日志中 return(responseMessage); }
public override async Task OnMessageReceiced(WebSocketHelper webSocketHandler, ReceivedMessage receivedMessage, string originalData) { if (receivedMessage == null || string.IsNullOrEmpty(receivedMessage.Message)) { return; } var message = receivedMessage.Message; await webSocketHandler.SendMessage("originalData:" + originalData, webSocketHandler.WebSocket.Clients.Caller); await webSocketHandler.SendMessage("您发送了文字:" + message, webSocketHandler.WebSocket.Clients.Caller); await webSocketHandler.SendMessage("正在处理中(反转文字)...", webSocketHandler.WebSocket.Clients.Caller); await Task.Delay(1000); //处理文字 var result = string.Concat(message.Reverse()); await webSocketHandler.SendMessage(result, webSocketHandler.WebSocket.Clients.Caller); var appId = Config.SenparcWeixinSetting.WxOpenAppId;//与微信小程序账号后台的AppId设置保持一致,区分大小写。 try { var sessionBag = SessionContainer.GetSession(receivedMessage.SessionId); //临时演示使用固定openId var openId = sessionBag != null ? sessionBag.OpenId : "onh7q0DGM1dctSDbdByIHvX4imxA";// "用户未正确登陆"; //await webSocketHandler.SendMessage("OpenId:" + openId, webSocketHandler.WebSocket.Clients.Caller); //await webSocketHandler.SendMessage("FormId:" + formId); //群发 await webSocketHandler.SendMessage($"[群发消息] [来自 OpenId:***{openId.Substring(openId.Length - 10, 10)},昵称:{sessionBag.DecodedUserInfo?.nickName}]:{message}", webSocketHandler.WebSocket.Clients.All); } catch (Exception ex) { var msg = ex.Message + "\r\n\r\n" + originalData + "\r\n\r\nAPPID:" + appId; await webSocketHandler.SendMessage(msg, webSocketHandler.WebSocket.Clients.Caller); //VS2017以下如果编译不通过,可以注释掉这一行 WeixinTrace.SendCustomLog("WebSocket OnMessageReceiced()过程出错", msg); } }
public ActionResult Index() { var guid = Guid.NewGuid().ToString("n"); ViewData["Guid"] = guid; var configHelper = new ConfigHelper(); int qrCodeId = 0; CreateQrCodeResult qrResult = null; try { //chm二维码 qrCodeId = configHelper.GetQrCodeId(); qrResult = MP.AdvancedAPIs.QrCodeApi.Create(appId, 10000, qrCodeId, QrCode_ActionName.QR_SCENE); var qrCodeUrl = MP.AdvancedAPIs.QrCodeApi.GetShowQrCodeUrl(qrResult.ticket); ViewData["QrCodeUrl"] = qrCodeUrl; } catch (Exception e) { WeixinTrace.SendCustomLog("Document发生appsecret错误!", e.ToString()); var accessTokenBags = AccessTokenContainer.GetAllItems(); WeixinTrace.SendCustomLog("当前AccessToken信息", accessTokenBags.ToJson()); } finally { ConfigHelper.CodeCollection[guid] = new CodeRecord() { Key = guid, QrCodeId = qrCodeId, QrCodeTicket = qrResult };//添加对应关系 //下载版本 var config = configHelper.GetConfig(); ViewData["Versions"] = config.Versions; ViewData["WebVersions"] = config.WebVersions; ViewData["DownloadCount"] = config.DownloadCount.ToString("##,###"); } return(View()); }
//DPBMARK_END #region 订单及退款 /// <summary> /// 退款申请接口 /// </summary> /// <returns></returns> public async Task <IActionResult> Refund() { try { WeixinTrace.SendCustomLog("进入退款流程", "1"); string nonceStr = TenPayV3Util.GetNoncestr(); string outTradeNo = HttpContext.Session.GetString("BillNo"); if (!TradeNumberToTransactionId.TryGetValue(outTradeNo, out string transactionId)) { return(Content("transactionId 不正确,可能是服务器还没有收到微信回调确认通知,退款失败。请稍后刷新再试。")); } WeixinTrace.SendCustomLog("进入退款流程", "2 outTradeNo:" + outTradeNo + ",transactionId:" + transactionId); string outRefundNo = "OutRefunNo-" + SystemTime.Now.Ticks; int totalFee = int.Parse(HttpContext.Session.GetString("BillFee")); int refundFee = totalFee; string opUserId = TenPayV3Info.MchId; var notifyUrl = "https://sdk.weixin.senparc.com/TenPayRealV3/RefundNotifyUrl"; //var dataInfo = new TenPayV3RefundRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, TenPayV3Info.Key, // null, nonceStr, null, outTradeNo, outRefundNo, totalFee, refundFee, opUserId, null, notifyUrl: notifyUrl); //TODO:该接口参数二选一传入 var dataInfo = new RefundRequsetData(transactionId, null, outRefundNo, "Senparc TenPayV3 demo退款测试", notifyUrl, null, new RefundRequsetData.Amount(refundFee, null, refundFee, "CNY"), null); //#region 新方法(Senparc.Weixin v6.4.4+) //var result = TenPayOldV3.Refund(_serviceProvider, dataInfo);//证书地址、密码,在配置文件中设置,并在注册微信支付信息时自动记录 //#endregion var result = await _basePayApis.RefundAsync(dataInfo); WeixinTrace.SendCustomLog("进入退款流程", "3 Result:" + result.ToJson()); ViewData["Message"] = $"退款结果:{result.status} {result.ResultCode}。您可以刷新当前页面查看最新结果。"; return(View()); //return Json(result, JsonRequestBehavior.AllowGet); } catch (Exception ex) { WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); throw; } }
/// <summary> /// 配置微信跟踪日志 /// </summary> private void ConfigWeixinTraceLog() { //这里设为Debug状态时,/App_Data/WeixinTraceLog/目录下会生成日志文件记录所有的API请求日志,正式发布版本建议关闭 Config.IsDebug = true; WeixinTrace.SendCustomLog("系统日志", "系统启动");//只在Senparc.Weixin.Config.IsDebug = true的情况下生效 //自定义日志记录回调 WeixinTrace.OnLogFunc = () => { //加入每次触发Log后需要执行的代码 }; //当发生基于WeixinException的异常时触发 WeixinTrace.OnWeixinExceptionFunc = ex => { //加入每次触发WeixinExceptionLog后需要执行的代码 var eventService = new EventService(); eventService.ConfigOnWeixinExceptionFunc(ex); }; }
public HttpResult Refund() { try { WeixinTrace.SendCustomLog("进入退款流程", "1"); string nonceStr = TenPayV3Util.GetNoncestr(); string outTradeNo = HttpContext.Session.GetString("BillNo"); WeixinTrace.SendCustomLog("进入退款流程", "2 outTradeNo:" + outTradeNo); string outRefundNo = "OutRefunNo-" + SystemTime.Now.Ticks; int totalFee = int.Parse(HttpContext.Session.GetString("BillFee")); int refundFee = totalFee; string opUserId = TenPayV3Info.MchId; var notifyUrl = "https://yufaquan.cn/wx/PayV3/RefundNotifyUrl"; var dataInfo = new TenPayV3RefundRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, TenPayV3Info.Key, null, nonceStr, null, outTradeNo, outRefundNo, totalFee, refundFee, opUserId, null, notifyUrl: notifyUrl); #region 旧方法 //var cert = @"D:\cert\apiclient_cert_SenparcRobot.p12";//根据自己的证书位置修改 //var password = TenPayV3Info.MchId;//默认为商户号,建议修改 //var result = TenPayV3.Refund(dataInfo, cert, password); #endregion #region 新方法(Senparc.Weixin v6.4.4+) var result = TenPayV3.Refund(_serviceProvider, dataInfo);//证书地址、密码,在配置文件中设置,并在注册微信支付信息时自动记录 #endregion WeixinTrace.SendCustomLog("进入退款流程", "3 Result:" + result.ToJson()); return(HttpResult.Success($"退款结果:{result.result_code} {result.err_code_des}。", null)); } catch (Exception ex) { WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); throw; } }
public override void OnResultExecuted(ResultExecutedContext filterContext) { var currentThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; if (!_start.ContainsKey(currentThreadId)) { return; } try { //计算出当前页面访问耗时 var costSeconds = (DateTime.Now - _start[currentThreadId]).TotalSeconds; if (costSeconds > 2)//如果耗时超过2秒,就是用log4net打印出,具体是哪个页面访问超过了2秒,具体使用了多长时间。 { LogUtility.TrackPageLoadPerformance.Warn($"页面执行时间超过{WARM_LOAD_SECONDS}秒。时间:{costSeconds},地址:{_url[currentThreadId]}"); } if (!RecordActionName.IsNullOrEmpty() && (RecordActionName == "*" || RecordActionName.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) .Select(z => z.Trim().ToUpper()).Contains(filterContext.RouteData.DataTokens["action"])) ) { var msg = $"页面【{filterContext.RouteData.Values["Action"]}】执行时间:{costSeconds}秒,地址:{_url[currentThreadId]}"; LogUtility.TrackPageLoadPerformance.Debug(msg); WeixinTrace.SendCustomLog("页面性能", msg); } } catch (Exception ex) { LogUtility.TrackPageLoadPerformance.ErrorFormat(ex.Message, ex); } finally { _start.Remove(currentThreadId); _url.Remove(currentThreadId); } }
public async Task <IActionResult> DecodeEncryptedData(string type, string sessionId, string encryptedData, string iv) { DecodeEntityBase decodedEntity = null; CoreCmsUserWeChatInfo userInfo = null; try { switch (type.ToUpper()) { case "USERINFO": //wx.getUserInfo() decodedEntity = EncryptHelper.DecodeUserInfoBySessionId(sessionId, encryptedData, iv); break; default: break; } } catch (Exception ex) { WeixinTrace.SendCustomLog("EncryptHelper.DecodeUserInfoBySessionId 方法出错", $@"sessionId: {sessionId}encryptedData: {encryptedData}iv: {iv}sessionKey: { (await SessionContainer.CheckRegisteredAsync(sessionId) ? (await SessionContainer.GetSessionAsync(sessionId)).SessionKey : "未保存sessionId")}异常信息:{ex.ToString()}"); } //检验水印 var checkWatermark = false; if (decodedEntity != null) { checkWatermark = decodedEntity.CheckWatermark(WxOpenAppId); //保存用户信息(可选) if (checkWatermark && decodedEntity is DecodedUserInfo decodedUserInfo) { var sessionBag = await SessionContainer.GetSessionAsync(sessionId); if (sessionBag != null) { await SessionContainer.AddDecodedUserInfoAsync(sessionBag, decodedUserInfo); } //更新数据库讯息 userInfo = _userWeChatInfoServices.QueryByClause(p => p.openid == decodedUserInfo.openId); if (userInfo == null) { userInfo = new CoreCmsUserWeChatInfo(); userInfo.type = (int)GlobalEnumVars.UserAccountTypes.微信小程序; userInfo.openid = decodedUserInfo.openId; userInfo.sessionKey = sessionBag.SessionKey; userInfo.unionId = decodedUserInfo.unionId; userInfo.avatar = decodedUserInfo.avatarUrl; userInfo.nickName = decodedUserInfo.nickName; userInfo.gender = decodedUserInfo.gender; userInfo.language = ""; userInfo.city = decodedUserInfo.city; userInfo.province = decodedUserInfo.province; userInfo.country = decodedUserInfo.country; userInfo.mobile = ""; userInfo.createTime = DateTime.Now; var id = _userWeChatInfoServices.Insert(userInfo); if (id > 0) { userInfo.id = id; _userWeChatInfoServices.Update(p => new CoreCmsUserWeChatInfo() { userId = id }, p => p.id == id); } } else { userInfo.gender = decodedUserInfo.gender; userInfo.city = decodedUserInfo.city; userInfo.avatar = decodedUserInfo.avatarUrl; userInfo.country = decodedUserInfo.country; userInfo.nickName = decodedUserInfo.nickName; userInfo.province = decodedUserInfo.province; userInfo.unionId = decodedUserInfo.unionId; userInfo.gender = decodedUserInfo.gender; _userWeChatInfoServices.Update(userInfo); } } } //注意:此处仅为演示,敏感信息请勿传递到客户端! return(Json(new { success = checkWatermark, userInfo = userInfo, msg = string.Format("水印验证:{0}", checkWatermark ? "通过" : "不通过") })); }
public override async Task OnMessageReceiced(WebSocketHelper webSocketHandler, ReceivedMessage receivedMessage, string originalData) { if (receivedMessage == null || string.IsNullOrEmpty(receivedMessage.Message)) { return; } var message = receivedMessage.Message; await webSocketHandler.SendMessage("originalData:" + originalData); await webSocketHandler.SendMessage("您发送了文字:" + message); await webSocketHandler.SendMessage("正在处理中..."); await Task.Delay(1000); //处理文字 var result = string.Concat(message.Reverse()); await webSocketHandler.SendMessage(result); #if NET45 var appId = Config.SenparcWeixinSetting.WxOpenAppId; //与微信小程序账号后台的AppId设置保持一致,区分大小写。 #else var appId = "WxOpenAppId"; //与微信小程序账号后台的AppId设置保持一致,区分大小写。 #endif try { //发送模板消息 var formId = receivedMessage.FormId;//发送模板消息使用,需要在wxml中设置<form report-submit="true"> var sessionBag = SessionContainer.GetSession(receivedMessage.SessionId); //临时演示使用固定openId var openId = sessionBag != null ? sessionBag.OpenId : "onh7q0DGM1dctSDbdByIHvX4imxA";// "用户未正确登陆"; await webSocketHandler.SendMessage("OpenId:" + openId); //await webSocketHandler.SendMessage("FormId:" + formId); if (sessionBag == null) { openId = "onh7q0DGM1dctSDbdByIHvX4imxA";//临时测试 } //var data = new WxOpenTemplateMessage_PaySuccessNotice( // "在线购买", SystemTime.Now, "图书众筹", "1234567890", // 100, "400-9939-858", "http://sdk.senparc.weixin.com"); var data = new { keyword1 = new TemplateDataItem("来自小程序WebSocket的模板消息"), keyword2 = new TemplateDataItem(SystemTime.Now.LocalDateTime.ToString()), keyword3 = new TemplateDataItem("Name"), keyword4 = new TemplateDataItem("Number"), keyword5 = new TemplateDataItem(100.ToString("C")), keyword6 = new TemplateDataItem("400-031-8816"), }; var tmResult = Senparc.Weixin.WxOpen.AdvancedAPIs.Template.TemplateApi.SendTemplateMessage(appId, openId, "Ap1S3tRvsB8BXsWkiILLz93nhe7S8IgAipZDfygy9Bg", data, receivedMessage.FormId, "pages/websocket/websocket", "websocket", null); } catch (Exception ex) { var msg = ex.Message + "\r\n\r\n" + originalData + "\r\n\r\nAPPID:" + appId; await webSocketHandler.SendMessage(msg); //VS2017以下如果编译不通过,可以注释掉这一行 WeixinTrace.SendCustomLog("WebSocket OnMessageReceiced()过程出错", msg); } }
/// <summary> /// 小程序微信支付回调 /// </summary> /// <returns></returns> public ActionResult PayNotifyUrlWxOpen() { WeixinTrace.SendCustomLog("小程序微信支付回调", "TenPayV3Controller.PayNotifyUrlWxOpen()"); return(PayNotifyUrl(true));//调用正常的流程 }
/// <summary> /// JS-SDK支付回调地址(在统一下单接口中设置notify_url) /// </summary> /// <returns></returns> public ActionResult PayNotifyUrl(bool isWxOpenPay = false)//注意:统一下单接口中不能带参数! { WeixinTrace.SendCustomLog("微信支付回调", "来源:" + (isWxOpenPay ? "微信支付" : "小程序支付")); try { ResponseHandler resHandler = new ResponseHandler(null); string return_code = resHandler.GetParameter("return_code"); string return_msg = resHandler.GetParameter("return_msg"); bool paySuccess = false; resHandler.SetKey(TenPayV3Info.Key); //验证请求是否从微信发过来(安全) if (resHandler.IsTenpaySign() && return_code.ToUpper() == "SUCCESS") { paySuccess = true;//正确的订单处理 //直到这里,才能认为交易真正成功了,可以进行数据库操作,但是别忘了返回规定格式的消息! } else { paySuccess = false;//错误的订单处理 } if (paySuccess) { /* 这里可以进行订单处理的逻辑 */ //发送支付成功的模板消息 try { string appId = Config.SenparcWeixinSetting.WeixinAppId;//与微信公众账号后台的AppId设置保持一致,区分大小写。 string openId = resHandler.GetParameter("openid"); if (isWxOpenPay) { //DPBMARK MiniProgram var cacheStrategy = CacheStrategyFactory.GetObjectCacheStrategyInstance(); var unifiedorderRequestData = cacheStrategy.Get <TenPayV3UnifiedorderRequestData>($"WxOpenUnifiedorderRequestData-{openId}"); //获取订单请求信息缓存 var unifedorderResult = cacheStrategy.Get <UnifiedorderResult>($"WxOpenUnifiedorderResultData-{openId}"); //获取订单信息缓存 if (unifedorderResult != null || !string.IsNullOrEmpty(unifedorderResult.prepay_id)) { Senparc.Weixin.WeixinTrace.SendCustomLog("支付成功模板消息参数(小程序)", appId + " , " + openId); //小程序支付,发送小程序模板消息 var templateData = new WxOpenTemplateMessage_PaySuccessNotice( "在线购买(小程序支付)测试", SystemTime.Now, "小程序支付 | 注意:这条消息来自微信服务器异步回调,官方证明支付成功! | prepay_id:" + unifedorderResult.prepay_id, unifiedorderRequestData.OutTradeNo, unifiedorderRequestData.TotalFee, "400-031-8816", "https://weixin.senparc.com"); //微信官方已停用此接口 //Senparc.Weixin.WxOpen.AdvancedAPIs // .Template.TemplateApi // .SendTemplateMessage( // Config.SenparcWeixinSetting.WxOpenAppId, openId, templateData.TemplateId, templateData, unifedorderResult.prepay_id, "pages/index/index", "图书", "#fff00"); } else { Senparc.Weixin.WeixinTrace.SendCustomLog("支付成功模板消息参数(小程序)", "prepayId未记录:" + appId + " , " + openId); } //DPBMARK_END } else { //微信公众号支付 var templateData = new WeixinTemplate_PaySuccess("https://weixin.senparc.com", "购买商品", "状态:" + return_code); Senparc.Weixin.WeixinTrace.SendCustomLog("支付成功模板消息参数(公众号)", appId + " , " + openId); var result = AdvancedAPIs.TemplateApi.SendTemplateMessage(appId, openId, templateData); } } catch (Exception ex) { WeixinTrace.WeixinExceptionLog(new WeixinException("支付成功模板消息异常", ex)); //WeixinTrace.SendCustomLog("支付成功模板消息", ex.ToString()); } WeixinTrace.SendCustomLog("PayNotifyUrl回调", "支付成功"); } else { Senparc.Weixin.WeixinTrace.SendCustomLog("PayNotifyUrl回调", "支付失败"); } #region 记录日志 var logDir = ServerUtility.ContentRootMapPath(string.Format("~/App_Data/TenPayNotify/{0}", SystemTime.Now.ToString("yyyyMMdd"))); if (!Directory.Exists(logDir)) { Directory.CreateDirectory(logDir); } var logPath = Path.Combine(logDir, string.Format("{0}-{1}-{2}.txt", SystemTime.Now.ToString("yyyyMMdd"), SystemTime.Now.ToString("HHmmss"), Guid.NewGuid().ToString("n").Substring(0, 8))); using (var fileStream = System.IO.File.OpenWrite(logPath)) { var notifyXml = resHandler.ParseXML(); //fileStream.Write(Encoding.Default.GetBytes(res), 0, Encoding.Default.GetByteCount(res)); fileStream.Write(Encoding.Default.GetBytes(notifyXml), 0, Encoding.Default.GetByteCount(notifyXml)); fileStream.Close(); } #endregion string xml = string.Format(@"<xml> <return_code><![CDATA[{0}]]></return_code> <return_msg><![CDATA[{1}]]></return_msg> </xml>", return_code, return_msg); return(Content(xml, "text/xml")); } catch (Exception ex) { WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); throw; } }
public ActionResult Result(string openId, string template_id, string scene, string reserved) { //template_id就是微信后台可以看到的template_id if (reserved != Session["WeixinSubscribeMsgReserved"] as string) { //reserved用于保持请求和回调的状态,授权请后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验,开发者可以填写a-zA-Z0-9的参数值,最多128字节 return(Content("请求错误!")); } WeixinTrace.SendCustomLog("一次性订阅消息-参数", string.Format("openId:{0},templateId:{1},scene:{2}", openId, template_id, scene)); var action = Request.QueryString["action"];//MVC直接通过Action获取到的action参数为ActionName if (action == "confirm") { //发送提示 var data = new { content = new { value = @"您现在收到的是一条“一次订阅”消息。 感谢您对盛派网络的支持! 1、Senparc.Weixin SDK官方教程《微信开发深度解析》已经出版,请购买正版! 2、Senparc 官方视频教程《微信公众号+小程序快速开发》已经上线,点击【详情】观看或购买!", color = "#008000" } }; //var data1 = new //{ // content = new[] // { // new{ // value = "Value", // color = "#00ff00" // }, // new{ // value = "Value2", // color = "#ff0000" // } // } //}; try { var url = "https://book.weixin.senparc.com/book/videolinknetease?code=SenparcRobot-SubscribeMsg"; TemplateApi.Subscribe(base.AppId, openId, template_id, scene, "这是一条“一次性订阅消息”", data, url); return(Content("发送成功!")); } catch (ErrorJsonResultException e) { if (e.JsonResult.errcode == ReturnCode.api功能未授权) { return(Content("功能正常,由于微信官方(程序或文档)问题,返回错误:" + e.JsonResult.errcode + "。请等待微信官方更新!")); } else { return(Content("发生错误:" + e.Message)); } } } else { return(Content("您已取消授权!")); } }
/// <summary> /// 点击事件 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override IResponseMessageBase OnEvent_ClickRequest(RequestMessageEvent_Click requestMessage) { IResponseMessageBase reponseMessage = null; //菜单点击,需要跟创建菜单时的Key匹配 switch (requestMessage.EventKey) { case "OneClick": { //这个过程实际已经在OnTextOrEventRequest中完成,这里不会执行到。 var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); reponseMessage = strongResponseMessage; strongResponseMessage.Content = "您点击了底部按钮。\r\n为了测试微信软件换行bug的应对措施,这里做了一个——\r\n换行"; } break; case "SubClickRoot_Text": { var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); reponseMessage = strongResponseMessage; strongResponseMessage.Content = "您点击了子菜单按钮。"; } break; case "SubClickRoot_News": { var strongResponseMessage = CreateResponseMessage <ResponseMessageNews>(); reponseMessage = strongResponseMessage; strongResponseMessage.Articles.Add(new Article() { Title = "您点击了子菜单图文按钮", Description = "您点击了子菜单图文按钮,这是一条图文信息。这个区域是Description内容\r\n可以使用\\r\\n进行换行。", PicUrl = "http://sdk.weixin.senparc.com/Images/qrcode.jpg", Url = "http://sdk.weixin.senparc.com" }); //随机添加一条图文,或只输出一条图文信息 if (DateTime.Now.Second % 2 == 0) { strongResponseMessage.Articles.Add(new Article() { Title = "这是随机产生的第二条图文信息,用于测试多条图文的样式", Description = "这是随机产生的第二条图文信息,用于测试多条图文的样式", PicUrl = "http://sdk.weixin.senparc.com/Images/qrcode.jpg", Url = "http://sdk.weixin.senparc.com" }); } } break; case "SubClickRoot_Music": { //上传缩略图 var accessToken = Containers.AccessTokenContainer.TryGetAccessToken(appId, appSecret); var uploadResult = AdvancedAPIs.MediaApi.UploadTemporaryMedia(accessToken, UploadMediaFileType.thumb, Server.GetMapPath("~/Images/Logo.thumb.jpg")); //PS:缩略图官方没有特别提示文件大小限制,实际测试哪怕114K也会返回文件过大的错误,因此尽量控制在小一点(当前图片39K) //设置音乐信息 var strongResponseMessage = CreateResponseMessage <ResponseMessageMusic>(); reponseMessage = strongResponseMessage; strongResponseMessage.Music.Title = "天籁之音"; strongResponseMessage.Music.Description = "真的是天籁之音"; strongResponseMessage.Music.MusicUrl = "https://sdk.weixin.senparc.com/Content/music1.mp3"; strongResponseMessage.Music.HQMusicUrl = "https://sdk.weixin.senparc.com/Content/music1.mp3"; strongResponseMessage.Music.ThumbMediaId = uploadResult.thumb_media_id; } break; case "SubClickRoot_Image": { //上传图片 var accessToken = Containers.AccessTokenContainer.TryGetAccessToken(appId, appSecret); var uploadResult = AdvancedAPIs.MediaApi.UploadTemporaryMedia(accessToken, UploadMediaFileType.image, Server.GetMapPath("~/Images/Logo.jpg")); //设置图片信息 var strongResponseMessage = CreateResponseMessage <ResponseMessageImage>(); reponseMessage = strongResponseMessage; strongResponseMessage.Image.MediaId = uploadResult.media_id; } break; case "SubClickRoot_Agent": //代理消息 { //获取返回的XML DateTime dt1 = DateTime.Now; reponseMessage = MessageAgent.RequestResponseMessage(this, agentUrl, agentToken, RequestDocument.ToString()); //上面的方法也可以使用扩展方法:this.RequestResponseMessage(this,agentUrl, agentToken, RequestDocument.ToString()); DateTime dt2 = DateTime.Now; if (reponseMessage is ResponseMessageNews) { (reponseMessage as ResponseMessageNews) .Articles[0] .Description += string.Format("\r\n\r\n代理过程总耗时:{0}毫秒", (dt2 - dt1).Milliseconds); } } break; case "Member": //托管代理会员信息 { //原始方法为:MessageAgent.RequestXml(this,agentUrl, agentToken, RequestDocument.ToString());//获取返回的XML reponseMessage = this.RequestResponseMessage(agentUrl, agentToken, RequestDocument.ToString()); } break; case "OAuth": //OAuth授权测试 { var strongResponseMessage = CreateResponseMessage <ResponseMessageNews>(); strongResponseMessage.Articles.Add(new Article() { Title = "OAuth2.0测试", Description = "选择下面两种不同的方式进行测试,区别在于授权成功后,最后停留的页面。", //Url = "http://sdk.weixin.senparc.com/oauth2", //PicUrl = "http://sdk.weixin.senparc.com/Images/qrcode.jpg" }); strongResponseMessage.Articles.Add(new Article() { Title = "OAuth2.0测试(不带returnUrl),测试环境可使用", Description = "OAuth2.0测试(不带returnUrl)", Url = "http://sdk.weixin.senparc.com/oauth2", PicUrl = "http://sdk.weixin.senparc.com/Images/qrcode.jpg" }); var returnUrl = "/OAuth2/TestReturnUrl"; strongResponseMessage.Articles.Add(new Article() { Title = "OAuth2.0测试(带returnUrl),生产环境强烈推荐使用", Description = "OAuth2.0测试(带returnUrl)", Url = "http://sdk.weixin.senparc.com/oauth2?returnUrl=" + returnUrl.UrlEncode(), PicUrl = "http://sdk.weixin.senparc.com/Images/qrcode.jpg" }); reponseMessage = strongResponseMessage; } break; case "Description": { var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); strongResponseMessage.Content = GetWelcomeInfo(); reponseMessage = strongResponseMessage; } break; case "SubClickRoot_PicPhotoOrAlbum": { var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); reponseMessage = strongResponseMessage; strongResponseMessage.Content = "您点击了【微信拍照】按钮。系统将会弹出拍照或者相册发图。"; } break; case "SubClickRoot_ScancodePush": { var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); reponseMessage = strongResponseMessage; strongResponseMessage.Content = "您点击了【微信扫码】按钮。"; } break; case "ConditionalMenu_Male": { var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); reponseMessage = strongResponseMessage; strongResponseMessage.Content = "您点击了个性化菜单按钮,您的微信性别设置为:男。"; } break; case "ConditionalMenu_Femle": { var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); reponseMessage = strongResponseMessage; strongResponseMessage.Content = "您点击了个性化菜单按钮,您的微信性别设置为:女。"; } break; case "GetNewMediaId": //获取新的MediaId { var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); try { var result = AdvancedAPIs.MediaApi.UploadForeverMedia(appId, Server.GetMapPath("~/Images/logo.jpg")); strongResponseMessage.Content = result.media_id; } catch (Exception e) { strongResponseMessage.Content = "发生错误:" + e.Message; WeixinTrace.SendCustomLog("调用UploadForeverMedia()接口发生异常", e.Message); } } break; default: { var strongResponseMessage = CreateResponseMessage <ResponseMessageText>(); strongResponseMessage.Content = "您点击了按钮,EventKey:" + requestMessage.EventKey; reponseMessage = strongResponseMessage; } break; } return(reponseMessage); }
/// <summary> /// 退款申请接口 /// </summary> /// <returns></returns> public ActionResult Refund() { try { WeixinTrace.SendCustomLog("进入退款流程", "1"); string nonceStr = TenPayV3Util.GetNoncestr(); string outTradeNo = HttpContext.Session.GetString("BillNo"); WeixinTrace.SendCustomLog("进入退款流程", "2 outTradeNo:" + outTradeNo); string outRefundNo = "OutRefunNo-" + SystemTime.Now.Ticks; int totalFee = int.Parse(HttpContext.Session.GetString("BillFee")); int refundFee = totalFee; string opUserId = TenPayV3Info.MchId; var notifyUrl = "https://sdk.weixin.senparc.com/TenPayV3/RefundNotifyUrl"; var dataInfo = new TenPayV3RefundRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, TenPayV3Info.Key, null, nonceStr, null, outTradeNo, outRefundNo, totalFee, refundFee, opUserId, null, notifyUrl: notifyUrl); #region 旧方法 //var cert = @"D:\cert\apiclient_cert_SenparcRobot.p12";//根据自己的证书位置修改 //var password = TenPayV3Info.MchId;//默认为商户号,建议修改 //var result = TenPayOldV3.Refund(dataInfo, cert, password); #endregion #region 新方法(Senparc.Weixin v6.4.4+) var result = TenPayOldV3.Refund(_serviceProvider, dataInfo);//证书地址、密码,在配置文件中设置,并在注册微信支付信息时自动记录 #endregion WeixinTrace.SendCustomLog("进入退款流程", "3 Result:" + result.ToJson()); ViewData["Message"] = $"退款结果:{result.result_code} {result.err_code_des}。您可以刷新当前页面查看最新结果。"; return(View()); //return Json(result, JsonRequestBehavior.AllowGet); } catch (Exception ex) { WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); throw; } #region 原始方法 //RequestHandler packageReqHandler = new RequestHandler(null); //设置package订单参数 //packageReqHandler.SetParameter("appid", TenPayV3Info.AppId); //公众账号ID //packageReqHandler.SetParameter("mch_id", TenPayV3Info.MchId); //商户号 //packageReqHandler.SetParameter("out_trade_no", "124138540220170502163706139412"); //填入商家订单号 ////packageReqHandler.SetParameter("out_refund_no", ""); //填入退款订单号 //packageReqHandler.SetParameter("total_fee", ""); //填入总金额 //packageReqHandler.SetParameter("refund_fee", "100"); //填入退款金额 //packageReqHandler.SetParameter("op_user_id", TenPayV3Info.MchId); //操作员Id,默认就是商户号 //packageReqHandler.SetParameter("nonce_str", nonceStr); //随机字符串 //string sign = packageReqHandler.CreateMd5Sign("key", TenPayV3Info.Key); //packageReqHandler.SetParameter("sign", sign); //签名 ////退款需要post的数据 //string data = packageReqHandler.ParseXML(); ////退款接口地址 //string url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; ////本地或者服务器的证书位置(证书在微信支付申请成功发来的通知邮件中) //string cert = @"D:\cert\apiclient_cert_SenparcRobot.p12"; ////私钥(在安装证书时设置) //string password = TenPayV3Info.MchId; //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); ////调用证书 //X509Certificate2 cer = new X509Certificate2(cert, password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet); //#region 发起post请求 //HttpWebRequest webrequest = (HttpWebRequest)HttpWebRequest.Create(url); //webrequest.ClientCertificates.Add(cer); //webrequest.Method = "post"; //byte[] postdatabyte = Encoding.UTF8.GetBytes(data); //webrequest.ContentLength = postdatabyte.Length; //Stream stream; //stream = webrequest.GetRequestStream(); //stream.Write(postdatabyte, 0, postdatabyte.Length); //stream.Close(); //HttpWebResponse httpWebResponse = (HttpWebResponse)webrequest.GetResponse(); //StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream()); //string responseContent = streamReader.ReadToEnd(); //#endregion //// var res = XDocument.Parse(responseContent); ////string openid = res.Element("xml").Element("out_refund_no").Value; //return Content("申请成功:<br>" + HttpUtility.RequestUtility.HtmlEncode(responseContent)); #endregion }
/// <summary> /// 退款通知地址 /// </summary> /// <returns></returns> public ActionResult RefundNotifyUrl() { WeixinTrace.SendCustomLog("RefundNotifyUrl被访问", "IP" + HttpContext.UserHostAddress()?.ToString()); string responseCode = "FAIL"; string responseMsg = "FAIL"; try { ResponseHandler resHandler = new ResponseHandler(HttpContext); string return_code = resHandler.GetParameter("return_code"); string return_msg = resHandler.GetParameter("return_msg"); WeixinTrace.SendCustomLog("跟踪RefundNotifyUrl信息", resHandler.ParseXML()); if (return_code == "SUCCESS") { responseCode = "SUCCESS"; responseMsg = "OK"; string appId = resHandler.GetParameter("appid"); string mch_id = resHandler.GetParameter("mch_id"); string nonce_str = resHandler.GetParameter("nonce_str"); string req_info = resHandler.GetParameter("req_info"); if (!appId.Equals(Senparc.Weixin.Config.SenparcWeixinSetting.TenPayV3_AppId)) { /* * 注意: * 这里添加过滤只是因为盛派Demo经常有其他公众号错误地设置了我们的地址, * 导致无法正常解密,平常使用不需要过滤! */ SenparcTrace.SendCustomLog("RefundNotifyUrl 的 AppId 不正确", $"appId:{appId}\r\nmch_id:{mch_id}\r\nreq_info:{req_info}"); return(Content("faild")); } SenparcTrace.SendCustomLog("解密 - req_info", req_info); var decodeReqInfo = TenPayV3Util.DecodeRefundReqInfo(req_info, TenPayV3Info.Key); SenparcTrace.SendCustomLog("解密 - decodeReqInfo", decodeReqInfo); var decodeDoc = XDocument.Parse(decodeReqInfo); //获取接口中需要用到的信息 string transaction_id = decodeDoc.Root.Element("transaction_id").Value; string out_trade_no = decodeDoc.Root.Element("out_trade_no").Value; string refund_id = decodeDoc.Root.Element("refund_id").Value; string out_refund_no = decodeDoc.Root.Element("out_refund_no").Value; int total_fee = int.Parse(decodeDoc.Root.Element("total_fee").Value); int? settlement_total_fee = decodeDoc.Root.Element("settlement_total_fee") != null ? int.Parse(decodeDoc.Root.Element("settlement_total_fee").Value) : null as int?; int refund_fee = int.Parse(decodeDoc.Root.Element("refund_fee").Value); int tosettlement_refund_feetal_fee = int.Parse(decodeDoc.Root.Element("settlement_refund_fee").Value); string refund_status = decodeDoc.Root.Element("refund_status").Value; string success_time = decodeDoc.Root.Element("success_time").Value; string refund_recv_accout = decodeDoc.Root.Element("refund_recv_accout").Value; string refund_account = decodeDoc.Root.Element("refund_account").Value; string refund_request_source = decodeDoc.Root.Element("refund_request_source").Value; WeixinTrace.SendCustomLog("RefundNotifyUrl被访问", "验证通过"); //进行后续业务处理 } } catch (Exception ex) { responseMsg = ex.Message; WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); } string xml = string.Format(@"<xml> <return_code><![CDATA[{0}]]></return_code> <return_msg><![CDATA[{1}]]></return_msg> </xml>", responseCode, responseMsg); return(Content(xml, "text/xml")); }
/// <summary> /// 【异步方法】执行微信请求 /// </summary> public override async Task BuildResponseMessageAsync() { #region NeuChar 执行过程 var weixinAppId = this._postModel == null ? "" : this._postModel.AppId; switch (RequestMessage.MsgType) { case RequestMsgType.Text: { try { var requestMessage = RequestMessage as RequestMessageText; ResponseMessage = await CurrentMessageHandlerNode.ExecuteAsync(requestMessage, this, weixinAppId) ?? ((await(OnTextOrEventRequestAsync(requestMessage)) ?? (await OnTextRequestAsync(requestMessage)))); } catch (Exception ex) { SenparcTrace.SendCustomLog("mp-response error", ex.Message + "\r\n|||\r\n" + (ex.InnerException != null ? ex.InnerException.ToString() : "")); } } break; case RequestMsgType.Location: ResponseMessage = await OnLocationRequestAsync(RequestMessage as RequestMessageLocation); break; case RequestMsgType.Image: WeixinTrace.SendCustomLog("NeuChar Image", $"appid:{weixinAppId}"); ResponseMessage = await CurrentMessageHandlerNode.ExecuteAsync(RequestMessage, this, weixinAppId) ?? await OnImageRequestAsync(RequestMessage as RequestMessageImage); break; case RequestMsgType.Voice: ResponseMessage = await OnVoiceRequestAsync(RequestMessage as RequestMessageVoice); break; case RequestMsgType.Video: ResponseMessage = await OnVideoRequestAsync(RequestMessage as RequestMessageVideo); break; case RequestMsgType.Link: ResponseMessage = await OnLinkRequestAsync(RequestMessage as RequestMessageLink); break; case RequestMsgType.ShortVideo: ResponseMessage = await OnShortVideoRequestAsync(RequestMessage as RequestMessageShortVideo); break; case RequestMsgType.File: ResponseMessage = await OnFileRequestAsync(RequestMessage as RequestMessageFile); break; case RequestMsgType.NeuChar: ResponseMessage = await OnNeuCharRequestAsync(RequestMessage as RequestMessageNeuChar); break; case RequestMsgType.Unknown: ResponseMessage = await OnUnknownTypeRequestAsync(RequestMessage as RequestMessageUnknownType); break; case RequestMsgType.Event: { var requestMessageText = (RequestMessage as IRequestMessageEventBase).ConvertToRequestMessageText(); ResponseMessage = await CurrentMessageHandlerNode.ExecuteAsync(RequestMessage, this, weixinAppId) ?? await OnTextOrEventRequestAsync(requestMessageText) ?? (await OnEventRequestAsync(RequestMessage as IRequestMessageEventBase)); } break; default: Weixin.WeixinTrace.SendCustomLog("NeuChar", "未知的MsgType请求类型" + RequestMessage.MsgType); //throw new UnknownRequestMsgTypeException("未知的MsgType请求类型", null); break; } #endregion }
/// <summary> /// 退款通知地址 /// </summary> /// <returns></returns> public ActionResult RefundNotifyUrl() { WeixinTrace.SendCustomLog("RefundNotifyUrl被访问", "IP" + HttpContext.UserHostAddress()?.ToString()); string responseCode = "FAIL"; string responseMsg = "FAIL"; try { ResponseHandler resHandler = new ResponseHandler(null); string return_code = resHandler.GetParameter("return_code"); string return_msg = resHandler.GetParameter("return_msg"); WeixinTrace.SendCustomLog("跟踪RefundNotifyUrl信息", resHandler.ParseXML()); if (return_code == "SUCCESS") { responseCode = "SUCCESS"; responseMsg = "OK"; string appId = resHandler.GetParameter("appid"); string mch_id = resHandler.GetParameter("mch_id"); string nonce_str = resHandler.GetParameter("nonce_str"); string req_info = resHandler.GetParameter("req_info"); var decodeReqInfo = TenPayV3Util.DecodeRefundReqInfo(req_info, TenPayV3Info.Key); var decodeDoc = XDocument.Parse(decodeReqInfo); //获取接口中需要用到的信息 string transaction_id = decodeDoc.Root.Element("transaction_id").Value; string out_trade_no = decodeDoc.Root.Element("out_trade_no").Value; string refund_id = decodeDoc.Root.Element("refund_id").Value; string out_refund_no = decodeDoc.Root.Element("out_refund_no").Value; int total_fee = int.Parse(decodeDoc.Root.Element("total_fee").Value); int? settlement_total_fee = decodeDoc.Root.Element("settlement_total_fee") != null ? int.Parse(decodeDoc.Root.Element("settlement_total_fee").Value) : null as int?; int refund_fee = int.Parse(decodeDoc.Root.Element("refund_fee").Value); int tosettlement_refund_feetal_fee = int.Parse(decodeDoc.Root.Element("settlement_refund_fee").Value); string refund_status = decodeDoc.Root.Element("refund_status").Value; string success_time = decodeDoc.Root.Element("success_time").Value; string refund_recv_accout = decodeDoc.Root.Element("refund_recv_accout").Value; string refund_account = decodeDoc.Root.Element("refund_account").Value; string refund_request_source = decodeDoc.Root.Element("refund_request_source").Value; //进行业务处理 } } catch (Exception ex) { responseMsg = ex.Message; WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); } string xml = string.Format(@"<xml> <return_code><![CDATA[{0}]]></return_code> <return_msg><![CDATA[{1}]]></return_msg> </xml>", responseCode, responseMsg); return(Content(xml, "text/xml")); }
/// <summary> /// 【异步方法】执行微信请求 /// </summary> public override async Task ExecuteAsync() { if (CancelExcute) { return; } await OnExecutingAsync(); if (CancelExcute) { return; } try { if (RequestMessage == null) { return; } #region NeuChar 执行过程 var weixinAppId = this._postModel.AppId; switch (RequestMessage.MsgType) { case RequestMsgType.Text: { try { var requestMessage = RequestMessage as RequestMessageText; ResponseMessage = await CurrentMessageHandlerNode.ExecuteAsync(requestMessage, this, weixinAppId) ?? ((await(OnTextOrEventRequestAsync(requestMessage)) ?? (await OnTextRequestAsync(requestMessage)))); } catch (Exception ex) { SenparcTrace.SendCustomLog("mp-response error", ex.Message + "\r\n|||\r\n" + (ex.InnerException != null ? ex.InnerException.ToString() : "")); } } break; case RequestMsgType.Location: ResponseMessage = await OnLocationRequestAsync(RequestMessage as RequestMessageLocation); break; case RequestMsgType.Image: WeixinTrace.SendCustomLog("NeuChar Image", $"appid:{weixinAppId}"); ResponseMessage = await CurrentMessageHandlerNode.ExecuteAsync(RequestMessage, this, weixinAppId) ?? await OnImageRequestAsync(RequestMessage as RequestMessageImage); break; case RequestMsgType.Voice: ResponseMessage = await OnVoiceRequestAsync(RequestMessage as RequestMessageVoice); break; case RequestMsgType.Video: ResponseMessage = await OnVideoRequestAsync(RequestMessage as RequestMessageVideo); break; case RequestMsgType.Link: ResponseMessage = await OnLinkRequestAsync(RequestMessage as RequestMessageLink); break; case RequestMsgType.ShortVideo: ResponseMessage = await OnShortVideoRequestAsync(RequestMessage as RequestMessageShortVideo); break; case RequestMsgType.File: ResponseMessage = await OnFileRequestAsync(RequestMessage as RequestMessageFile); break; case RequestMsgType.NeuChar: ResponseMessage = await OnNeuCharRequestAsync(RequestMessage as RequestMessageNeuChar); break; case RequestMsgType.Unknown: ResponseMessage = await OnUnknownTypeRequestAsync(RequestMessage as RequestMessageUnknownType); break; case RequestMsgType.Event: { var requestMessageText = (RequestMessage as IRequestMessageEventBase).ConvertToRequestMessageText(); ResponseMessage = await CurrentMessageHandlerNode.ExecuteAsync(RequestMessage, this, weixinAppId) ?? await OnTextOrEventRequestAsync(requestMessageText) ?? (await OnEventRequestAsync(RequestMessage as IRequestMessageEventBase)); } break; default: Weixin.WeixinTrace.SendCustomLog("NeuChar", "未知的MsgType请求类型" + RequestMessage.MsgType); //throw new UnknownRequestMsgTypeException("未知的MsgType请求类型", null); break; } #endregion //记录上下文 //此处修改 if (MessageContextGlobalConfig.UseMessageContext && ResponseMessage != null && !string.IsNullOrEmpty(ResponseMessage.FromUserName)) { GlobalMessageContext.InsertMessage(ResponseMessage); } } catch (Exception ex) { throw new MessageHandlerException("MessageHandler中Execute()过程发生错误:" + ex.Message, ex); } finally { await OnExecutedAsync(); } }