企業號微信支付 公眾號支付 H5調起支付API示例代碼 JSSDK C# .NET

来源:http://www.cnblogs.com/oppoic/archive/2016/12/05/6132533.html
-Advertisement-
Play Games

先看效果: 1.本文演示的是微信【企業號】的H5頁面微信支付 2.本項目基於開源微信框架WeiXinMPSDK開發:https://github.com/JeffreySu/WeiXinMPSDK 感謝作者蘇志巍的開源精神 一、準備部分 相關參數: AppId:公眾號的唯一標識(登陸微信企業號後臺 ...


 

先看效果

1.本文演示的是微信【企業號】的H5頁面微信支付

2.本項目基於開源微信框架WeiXinMPSDK開發:https://github.com/JeffreySu/WeiXinMPSDK 感謝作者蘇志巍的開源精神

 

一、準備部分

相關參數:

AppId:公眾號的唯一標識(登陸微信企業號後臺 - 設置 - 賬號信息 - CorpID)

AppSecret:(微信企業號後臺 - 設置 - 許可權管理 - 新建一個擁有所有應用許可權的普通管理組 - Secret

Key:商戶API密鑰(登陸微信商戶後臺 - 賬戶中心 - API安全 - API密鑰)

MchId:商戶ID(微信企業號後臺 - 服務中心 - 微信支付 - 微信支付 -商戶信息 - 商戶號)

後臺設置:

微信企業號後臺 - 服務中心 - 微信支付 - 微信支付 - 開發配置 :

1.測試授權目錄,改成線上支付頁面的目錄(例:http://www.abc.com/wxpay/)

2.測試白名單,加上測試用戶的白名單,只有白名單用戶可以付款

 

二、代碼

前端:

使用微信支付先引入JSSDK:http://res.wx.qq.com/open/js/jweixin-1.0.0.js

頁面打開即初始化:

        $.ajax({
            type: "GET",
            url: "/WxPay/GetPayConfig",
            beforeSend: function () {
                $("#btnPay").attr({ "disabled": "disabled" });//獲取到配置之前,禁止點擊付款按鈕
            },
            success: function (data) {
                $("#btnPay").removeAttr("disabled");//獲取到配置,打開付款按鈕
                wx.config({
                    debug: true, // 開啟調試模式,成功失敗都會有alert框
                    appId: data.appId, // 必填,公眾號的唯一標識
                    timestamp: data.timeStamp, // 必填,生成簽名的時間戳
                    nonceStr: data.nonceStr, // 必填,生成簽名的隨機串
                    signature: data.signature,// 必填,簽名
                    jsApiList: ['chooseWXPay'] // 必填,需要使用的JS介面列表
                });
                wx.ready(function () {
                    // config信息驗證後會執行ready方法,所有介面調用都必須在config介面獲得結果之後,config是一個客戶端的非同步操作,所以如果需要在頁面載入時就調用相關介面,則須把相關介面放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的介面,則可以直接調用,不需要放在ready函數中。
                });
                wx.error(function (res) {
                    // config信息驗證失敗會執行error函數,如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數中查看,對於SPA可以在這裡更新簽名。
                });
            }
        });

對應的後端代碼:

        /// <summary>
        /// 獲取微信支付配置
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public JsonResult GetPayConfig()
        {
            string timeStamp = Senparc.Weixin.MP.TenPayLib.TenPayUtil.GetTimestamp();
            string nonceStr = Senparc.Weixin.MP.TenPayLib.TenPayUtil.GetNoncestr();
            string signature = new Senparc.Weixin.MP.TenPayLib.RequestHandler(null).CreateMd5Sign();

            return Json(new { appId = AppId, timeStamp = timeStamp, nonceStr = nonceStr, signature = signature }, JsonRequestBehavior.AllowGet);
        }

 

用戶點擊支付觸發的函數(微信JSSDK的chooseWXPay函數):

        function startWxPay() {
            $.ajax({
                type: "POST",
                url: "/WxPay/GetPaySign",
                data: { code: code, openid: openid },
                beforeSend: function () {
                    $("#btnPay").attr({ "disabled": "disabled" });
                },
                success: function (res) {
                    $("#btnPay").removeAttr("disabled");
                    if (res.openid != null && res.openid != undefined && res.openid != "") {
                        window.localStorage.setItem("openid", res.openid);
                    }
                    wx.chooseWXPay({
                        timestamp: res.data.timeStamp, // 支付簽名時間戳
                        nonceStr: res.data.nonceStr, // 支付簽名隨機串,不長於32 位
                        package: res.data.package, // 統一支付介面返回的prepay_id參數值,提交格式如:prepay_id=***)
                        signType: "MD5", // 簽名方式,預設為'SHA1',使用新版支付需傳入'MD5'
                        paySign: res.data.paysign, // 支付簽名
                        success: function (res) {
                            //支付成功
                        },
                        cancel: function (res) {
                            //支付取消
                        }
                    });
                }
            });
        }

對應的服務端代碼:

        /// <summary>
        /// 支付介面
        /// </summary>
        /// <param name="code"></param>
        /// <param name="openid"></param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult GetPaySign(string code, string openid)
        {
            string body = "支付測試";//支付描述
            string nonce_str = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr();
            string notify_url = "http://" + HttpContext.Request.Url.Host + "/WxPay/PayNotifyUrl";//支付結果回調地址,不能帶參數(PayNotifyUrl回調里能接到訂單號out_trade_no參數)
            string out_trade_no = "WxPay_" + DateTime.Now.ToString("yyyyMMddHHmmssfff");//訂單號:32個字元內、不得重覆
            string spbill_create_ip = Request.UserHostAddress;//用戶端IP
            int total_fee = 1;//訂單金額(單位:分),整數
            string trade_type = "JSAPI";//JSAPI,NATIVE,APP,WAP

            #region 獲取用戶微信OpenId
            string openidExt = string.Empty;
            if (string.IsNullOrEmpty(openid))
            {
                if (!Senparc.Weixin.QY.Containers.AccessTokenContainer.CheckRegistered(AppId))
                {
                    Senparc.Weixin.QY.Containers.AccessTokenContainer.Register(AppId, AppSecret);
                }
                var accountToken = Senparc.Weixin.QY.Containers.AccessTokenContainer.GetToken(AppId, AppSecret);
                var user = Senparc.Weixin.QY.AdvancedAPIs.OAuth2Api.GetUserId(accountToken, code);
                var model = Senparc.Weixin.QY.CommonAPIs.CommonApi.ConvertToOpenId(accountToken, user.UserId);
                openidExt = model.openid;
            }
            else
            {
                openidExt = openid;
            }
            #endregion

            #region 調用統一支付介面獲得prepay_id(預支付交易會話標識)
            Senparc.Weixin.MP.TenPayLibV3.RequestHandler packageReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);
            packageReqHandler.SetParameter("appid", AppId);
            packageReqHandler.SetParameter("body", body);
            packageReqHandler.SetParameter("mch_id", MchId);
            packageReqHandler.SetParameter("nonce_str", nonce_str);
            packageReqHandler.SetParameter("notify_url", notify_url);
            packageReqHandler.SetParameter("openid", openidExt);
            packageReqHandler.SetParameter("out_trade_no", out_trade_no);
            packageReqHandler.SetParameter("spbill_create_ip", spbill_create_ip);
            packageReqHandler.SetParameter("total_fee", total_fee.ToString());
            packageReqHandler.SetParameter("trade_type", trade_type);
            packageReqHandler.SetParameter("sign", packageReqHandler.CreateMd5Sign("key", Key));
            string data = packageReqHandler.ParseXML();

            #region 應該調SDK介面:var result = Senparc.Weixin.MP.AdvancedAPIs.TenPayV3.Unifiedorder(data); 但是總報錯
            var urlFormat = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            var formDataBytes = data == null ? new byte[0] : Encoding.UTF8.GetBytes(data);
            MemoryStream ms = new MemoryStream();
            ms.Write(formDataBytes, 0, formDataBytes.Length);
            ms.Seek(0, SeekOrigin.Begin);
            var result = RequestUtility.HttpPost(urlFormat, null, ms);
            #endregion

            var res = System.Xml.Linq.XDocument.Parse(result);
            string prepay_id = res.Element("xml").Element("prepay_id").Value;
            #endregion

            #region 支付參數
            string timeStamp = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetTimestamp();
            nonce_str = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr();

            Senparc.Weixin.MP.TenPayLibV3.RequestHandler paysignReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);
            paysignReqHandler.SetParameter("appId", AppId);
            paysignReqHandler.SetParameter("timeStamp", timeStamp);
            paysignReqHandler.SetParameter("nonceStr", nonce_str);
            paysignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepay_id));
            paysignReqHandler.SetParameter("signType", "MD5");

            string paysign = paysignReqHandler.CreateMd5Sign("key", Key);
            paysignReqHandler.SetParameter("paysign", paysign);
            #endregion

            return Json(new { data = paysignReqHandler.GetAllParameters(), openid = openidExt }, JsonRequestBehavior.AllowGet);
        }

 

前端頁面全部代碼:

<!DOCTYPE html>
<html>
<head>
    <title>企業號微信支付測試</title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
    <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    <script type="text/javascript" src="http://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
</head>
<body>
    <input type="button" onclick="startWxPay()" class="btn btn-primary btn-lg btn-block" value="點擊付費(¥:0.01元)" id="btnPay" style="margin-top:80px;" />
    <script type="text/javascript">
        var code = GetQueryString("code");
        var openid = window.localStorage.getItem("openid");

        $.ajax({
            type: "GET",
            url: "/WxPay/GetPayConfig",
            beforeSend: function () {
                $("#btnPay").attr({ "disabled": "disabled" });//獲取到配置之前,禁止點擊付款按鈕
            },
            success: function (data) {
                $("#btnPay").removeAttr("disabled");//獲取到配置,打開付款按鈕
                wx.config({
                    debug: true, // 開啟調試模式,成功失敗都會有alert框
                    appId: data.appId, // 必填,公眾號的唯一標識
                    timestamp: data.timeStamp, // 必填,生成簽名的時間戳
                    nonceStr: data.nonceStr, // 必填,生成簽名的隨機串
                    signature: data.signature,// 必填,簽名
                    jsApiList: ['chooseWXPay'] // 必填,需要使用的JS介面列表
                });
                wx.ready(function () {
                    // config信息驗證後會執行ready方法,所有介面調用都必須在config介面獲得結果之後,config是一個客戶端的非同步操作,所以如果需要在頁面載入時就調用相關介面,則須把相關介面放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的介面,則可以直接調用,不需要放在ready函數中。
                });
                wx.error(function (res) {
                    // config信息驗證失敗會執行error函數,如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數中查看,對於SPA可以在這裡更新簽名。
                });
            }
        });

        function startWxPay() {
            $.ajax({
                type: "POST",
                url: "/WxPay/GetPaySign",
                data: { code: code, openid: openid },
                beforeSend: function () {
                    $("#btnPay").attr({ "disabled": "disabled" });
                },
                success: function (res) {
                    $("#btnPay").removeAttr("disabled");
                    if (res.openid != null && res.openid != undefined && res.openid != "") {
                        window.localStorage.setItem("openid", res.openid);
                    }
                    wx.chooseWXPay({
                        timestamp: res.data.timeStamp, // 支付簽名時間戳
                        nonceStr: res.data.nonceStr, // 支付簽名隨機串,不長於32 位
                        package: res.data.package, // 統一支付介面返回的prepay_id參數值,提交格式如:prepay_id=***)
                        signType: "MD5", // 簽名方式,預設為'SHA1',使用新版支付需傳入'MD5'
                        paySign: res.data.paysign, // 支付簽名
                        success: function (res) {
                            //支付成功
                        },
                        cancel: function (res) {
                            //支付取消
                        }
                    });
                }
            });
        }

        function GetQueryString(name) {
            var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
            var r = window.location.search.substr(1).match(reg);
            if (r != null) return unescape(r[2]); return null;
        }
    </script>
</body>
</html>
View Code

後端控制器全部代碼:

using Senparc.Weixin.HttpUtility;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace CNPCCMS.Controllers
{
    public class WxPayController : Controller
    {
        private static string AppId = "改成你的AppId";
        private static string AppSecret = "改成你的AppSecret";
        private static string Key = "改成你的Key";
        private static string MchId = "改成你的MchId";

        /// <summary>
        /// 獲取微信支付配置
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public JsonResult GetPayConfig()
        {
            string timeStamp = Senparc.Weixin.MP.TenPayLib.TenPayUtil.GetTimestamp();
            string nonceStr = Senparc.Weixin.MP.TenPayLib.TenPayUtil.GetNoncestr();
            string signature = new Senparc.Weixin.MP.TenPayLib.RequestHandler(null).CreateMd5Sign();

            return Json(new { appId = AppId, timeStamp = timeStamp, nonceStr = nonceStr, signature = signature }, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// 支付介面
        /// </summary>
        /// <param name="code"></param>
        /// <param name="openid"></param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult GetPaySign(string code, string openid)
        {
            string body = "支付測試";//支付描述
            string nonce_str = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr();
            string notify_url = "http://" + HttpContext.Request.Url.Host + "/WxPay/PayNotifyUrl";//支付結果回調地址,不能帶參數(PayNotifyUrl回調里能接到訂單號out_trade_no參數)
            string out_trade_no = "WxPay_" + DateTime.Now.ToString("yyyyMMddHHmmssfff");//訂單號:32個字元內、不得重覆
            string spbill_create_ip = Request.UserHostAddress;//用戶端IP
            int total_fee = 1;//訂單金額(單位:分),整數
            string trade_type = "JSAPI";//JSAPI,NATIVE,APP,WAP

            #region 獲取用戶微信OpenId
            string openidExt = string.Empty;
            if (string.IsNullOrEmpty(openid))
            {
                if (!Senparc.Weixin.QY.Containers.AccessTokenContainer.CheckRegistered(AppId))
                {
                    Senparc.Weixin.QY.Containers.AccessTokenContainer.Register(AppId, AppSecret);
                }
                var accountToken = Senparc.Weixin.QY.Containers.AccessTokenContainer.GetToken(AppId, AppSecret);
                var user = Senparc.Weixin.QY.AdvancedAPIs.OAuth2Api.GetUserId(accountToken, code);
                var model = Senparc.Weixin.QY.CommonAPIs.CommonApi.ConvertToOpenId(accountToken, user.UserId);
                openidExt = model.openid;
            }
            else
            {
                openidExt = openid;
            }
            #endregion

            #region 調用統一支付介面獲得prepay_id(預支付交易會話標識)
            Senparc.Weixin.MP.TenPayLibV3.RequestHandler packageReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);
            packageReqHandler.SetParameter("appid", AppId);
            packageReqHandler.SetParameter("body", body);
            packageReqHandler.SetParameter("mch_id", MchId);
            packageReqHandler.SetParameter("nonce_str", nonce_str);
            packageReqHandler.SetParameter("notify_url", notify_url);
            packageReqHandler.SetParameter("openid", openidExt);
            packageReqHandler.SetParameter("out_trade_no", out_trade_no);
            packageReqHandler.SetParameter("spbill_create_ip", spbill_create_ip);
            packageReqHandler.SetParameter("total_fee", total_fee.ToString());
            packageReqHandler.SetParameter("trade_type", trade_type);
            packageReqHandler.SetParameter("sign", packageReqHandler.CreateMd5Sign("key", Key));
            string data = packageReqHandler.ParseXML();

            #region 應該調SDK介面:var result = Senparc.Weixin.MP.AdvancedAPIs.TenPayV3.Unifiedorder(data); 但是總報錯
            var urlFormat = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            var formDataBytes = data == null ? new byte[0] : Encoding.UTF8.GetBytes(data);
            MemoryStream ms = new MemoryStream();
            ms.Write(formDataBytes, 0, formDataBytes.Length);
            ms.Seek(0, SeekOrigin.Begin);
            var result = RequestUtility.HttpPost(urlFormat, null, ms);
            #endregion

            var res = System.Xml.Linq.XDocument.Parse(result);
            string prepay_id = res.Element("xml").Element("prepay_id").Value;
            #endregion

            #region 支付參數
            string timeStamp = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetTimestamp();
            nonce_str = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr();

            Senparc.Weixin.MP.TenPayLibV3.RequestHandler paysignReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);
            paysignReqHandler.SetParameter("appId", AppId);
            paysignReqHandler.SetParameter("timeStamp", timeStamp);
            paysignReqHandler.SetParameter("nonceStr", nonce_str);
            paysignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepay_id));
            paysignReqHandler.SetParameter("signType", "MD5");

            string paysign = paysignReqHandler.CreateMd5Sign("key", Key);
            paysignReqHandler.SetParameter("paysign", paysign);
            #endregion

            return Json(new { data = paysignReqHandler.GetAllParameters(), openid = openidExt }, JsonRequestBehavior.AllowGet);
        }


        /// <summary>
        /// 支付結果回調地址
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult PayNotifyUrl()
        {
            Senparc.Weixin.MP.TenPayLibV3.ResponseHandler payNotifyRepHandler = new Senparc.Weixin.MP.TenPayLibV3.ResponseHandler(null);
            payNotifyRepHandler.SetKey(Key);

            string return_code = payNotifyRepHandler.GetParameter("return_code");
            string return_msg = payNotifyRepHandler.GetParameter("return_msg");
            string xml = string.Format(@"<xml><return_code><![CDATA[{0}]]></return_code><return_msg><![CDATA[{1}]]></return_msg></xml>", return_code, return_msg);

            if (return_code.ToUpper() != "SUCCESS")
            {
                return Content(xml, "text/xml");
            }

            string out_trade_no = payNotifyRepHandler.GetParameter("out_trade_no");
            //微信伺服器可能會多次推送到本介面,這裡需要根據out_trade_no去查詢訂單是否處理,如果處理直接返回:return Content(xml, "text/xml"); 不跑下麵代碼

            //驗證請求是否從微信發過來(安全)
            if (payNotifyRepHandler.IsTenpaySign())
            {

            }
            else
            {

            }
            return Content(xml, "text/xml");
        }

    }
}
View Code

 

三、關鍵點

1.支付頁面的鏈接不管是放到自定義菜單還是嵌到公眾號文章內,或是發到微信對話框讓用戶點擊支付,最終的鏈接是:https://open.weixin.qq.com/connect/oauth2/authorize?appid=這裡改成你的appid&redirect_uri=這裡是你支付頁面的地址&response_type=code&scope=SCOPE&state=1#wechat_redirect

這種約定的鏈接最終訪問的還是redirect_uri這個鏈接,同時微信回調這個鏈接還會帶上code和state兩個參數。code參數是當前用戶,state參數自定義,本文未用到。

2.後臺GetPaySign方法同時接收code和openid是為了連續支付或者用戶取消了支付再次點擊支付設計的(每點一次支付就觸發一次後臺GetPaySign方法),因為code是微信伺服器回調帶的,只能用一次。所以第一次code傳到後臺就調介面獲得用戶openid發回前端緩存起來,再起發起請求code和openid一起傳到後端,這個時候code無效了,但是openid可以用

3.微信支付回調介面(notify_url)不能帶參數,但是回調介面里能從微信伺服器推過來的xml文件里提取出訂單號(out_trade_no),可以對其進行操作

爬蟲可恥,本文原始鏈接:http://www.cnblogs.com/oppoic/p/6132533.html

四、附錄

H5調起支付API:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6

統一下單:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

微信JSSDK:https://mp.weixin.qq.com/wiki  微信網頁開發 - 微信JS-SDK說明文檔 - Ctrl+F搜索:chooseWXPay

OAuth驗證介面http://qydev.weixin.qq.com/wiki/index.php?title=OAuth驗證介面

userid轉換成openid:http://qydev.weixin.qq.com/wiki/index.php?title=Userid與openid互換介面

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • http://man.linuxde.net/ ...
  • 源碼環境的搭建 Install源碼 Install源碼 >sudo apt-cache search linux-source linux-source - Linux kernel source with Ubuntu patches linux-source-4.4.0 - Linux kern ...
  • 下載JProfiler包 wget http://download-keycdn.ej-technologies.com/jprofiler/jprofiler_linux_9_2.rpm 安裝JProfiler rpm -ivh jprofiler_linux_9_2.rpm 安裝JProfile ...
  • 每次搭建新伺服器,都要來來回回把這些包再裝一下,來來回回搞了不下20遍了吧,原來都是憑經驗,配置過程中重覆入坑是難免的,故寫此文做個備忘。雖然有像xampp這樣的集成包,但是在生產環境的Linux發行版上,還是通過包管理工具安裝會放心。這次新買的伺服器是CentOS 7(7.2)系統,相關配置也都以 ...
  • 系統環境:CentOS 6.6 首先查看伺服器上是否已安裝了svn # rpm -qa subversion 如果沒有安裝,則執行此命令 # yum list subversion //查看svn包名 # yum install -y subversion.x86_64 //yum安裝svn 創建s ...
  • orch的目標是在建立科學演算法的同時,要有最大的靈活性和速度,而這一過程非常簡單。Torch擁有一個大社區驅動包的生態系統,涉及機器學習、電腦視覺、信號處理、並行處理、圖像、視頻、音頻和網路等,並建立在Lua社區基礎之上。 ...
  • 當初在shell中, 看到">&1"和">&2"始終不明白什麼意思.經過在網上的搜索得以解惑.其實這是兩種輸出. 在 shell 程式中,最常使用的 FD (file descriptor) 大概有三個, 分別是: 0 是一個文件描述符,表示標準輸入(stdin)1 是一個文件描述符,表示標準輸出( ...
  • 在《曆數依賴註入的N種玩法》演示系統自動註冊服務的實例中,我們會發現輸出的列表包含兩個特殊的服務,它們的對應的服務介面分別是IApplicationLifetime和IHostingEnvironment,我們將分別實現這兩個介面的服務統稱在ApplicationLifetime和HostingEn... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...