.NET CORE3.1實(shí)現(xiàn)微信小程序發(fā)送訂閱消息
一、appsettings.json定義小程序配置信息
"WX": {
"AppId": "wx88822730803edd44",
"AppSecret": "75b269042e8b5026e6ed14aa24ba9353",
"Templates": {
"Audit": {
"TemplateId": "aBaIjTsPBluYtj2tzotzpowsDDBGLhXQkwrScupnQsM",
"PageUrl": "/pages/index/formAudit?formId={0}&tableId={1}",
"MiniprogramState": "developer",
"Lang": "zh_TW",
"Data": {
"Title": "thing6",
"Content": "thing19",
"Date": "date9"
}
}
},
"SignatureToken": "aaaaaa",
"MessageSendUrl": "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={0}",
"AccessTokenUrl": "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"
}
二、編寫通用類加載配置
using System;
using System.Text;
using System.Security.Cryptography;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
namespace WXERP.Services
{
/// <summary>
/// 項(xiàng)目公有靜態(tài)類
/// </summary>
public class Common
{
/// <summary>
/// 獲取根目錄
/// </summary>
public static string AppRoot => Environment.CurrentDirectory;// AppContext.BaseDirectory;
/// <summary>
/// 獲取項(xiàng)目配置
/// </summary>
public static IConfiguration Configuration { get; set; }
/// <summary>
/// 加載項(xiàng)目配置
/// </summary>
static Common()
{
Configuration = new ConfigurationBuilder()
.Add(new JsonConfigurationSource
{
Path = "appsettings.json",
ReloadOnChange = true //當(dāng)appsettings.json被修改時重新加載
})
.Build();
}
/// <summary>
/// SHA1加密
/// </summary>
/// <param name="content">需要加密的字符串</param>
/// <returns>返回40位大寫字符串</returns>
public static string SHA1(string content)
{
try
{
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] bytes_in = Encoding.UTF8.GetBytes(content);
byte[] bytes_out = sha1.ComputeHash(bytes_in);
sha1.Dispose();
string result = BitConverter.ToString(bytes_out);
result = result.Replace("-", "");
return result;
}
catch (Exception ex)
{
throw new Exception("Error in SHA1: " + ex.Message);
}
}
}
}
三、編寫HttpHelper請求類
using System;
using System.Text;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace WXERP.Services
{
/// <summary>
/// HTTP請求輔助類
/// </summary>
public class HttpHelper
{
/// <summary>
/// post同步請求
/// </summary>
/// <param name="url">地址</param>
/// <param name="postData">數(shù)據(jù)</param>
/// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
/// <param name="headers">請求頭</param>
/// <returns></returns>
public static string HttpPost(string url, string postData = null, string contentType = null, Dictionary<string, string> headers = null)
{
using HttpClient client = new HttpClient();
if (headers != null)
{
foreach (var header in headers)
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
postData ??= "";
using HttpContent httpContent = new StringContent(postData, Encoding.UTF8);
if (contentType != null)
httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
HttpResponseMessage response = client.PostAsync(url, httpContent).Result;
return response.Content.ReadAsStringAsync().Result;
}
/// <summary>
/// post異步請求
/// </summary>
/// <param name="url">地址</param>
/// <param name="postData">數(shù)據(jù)</param>
/// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
/// <param name="timeOut">請求超時時間</param>
/// <param name="headers">請求頭</param>
/// <returns></returns>
public static async Task<string> HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary<string, string> headers = null)
{
using HttpClient client = new HttpClient();
client.Timeout = new TimeSpan(0, 0, timeOut);
if (headers != null)
{
foreach (var header in headers)
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
postData ??= "";
using HttpContent httpContent = new StringContent(postData, Encoding.UTF8);
if (contentType != null)
httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
HttpResponseMessage response = await client.PostAsync(url, httpContent);
return await response.Content.ReadAsStringAsync();
}
/// <summary>
/// get同步請求
/// </summary>
/// <param name="url">地址</param>
/// <param name="headers">請求頭</param>
/// <returns></returns>
public static string HttpGet(string url, Dictionary<string, string> headers = null)
{
using HttpClient client = new HttpClient();
if (headers != null)
{
foreach (var header in headers)
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
HttpResponseMessage response = client.GetAsync(url).Result;
return response.Content.ReadAsStringAsync().Result;
}
/// <summary>
/// get異步請求
/// </summary>
/// <param name="url"></param>
/// <param name="headers"></param>
/// <returns></returns>
public static async Task<string> HttpGetAsync(string url, Dictionary<string, string> headers = null)
{
using HttpClient client = new HttpClient();
if (headers != null)
{
foreach (var header in headers)
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
HttpResponseMessage response = await client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
}
}
四、在sqlserver下存儲并獲取openid,這個主要是因?yàn)樘峤幌⒉⒉皇窃谖⑿判〕绦蚨?,如果是在微信小程序上發(fā)起訂閱消息,可以忽略這個步驟
// 創(chuàng)建數(shù)據(jù)庫表
create table TBSF_Conmmunicate_WXUser
(
ID int identity(1,1) primary key,
Staff_ID varchar(10),
OpenId varchar(50),
SessionKey varchar(50),
UnionId varchar(50),
IsValid bit,
)
// SqlHelper數(shù)據(jù)庫輔助類來自于CommunicationOperateDBUtility,可以自己編寫
using System.Data;
using System.Text;
using CommunicationOperateDBUtility;
namespace WXERP.Services.CommunicationOperateDAL
{
/// <summary>
/// 微信信息
/// </summary>
public class WXInforDeal
{
private SqlHelper sqlHelper = null;
/// <summary>
/// 初始化數(shù)據(jù)庫輔助對象
/// </summary>
/// <param name="con"></param>
public WXInforDeal(object con)
{
sqlHelper = new SqlHelper(con);
}
/// <summary>
/// 獲取微信登陸用戶信息
/// </summary>
/// <param name="staffIdList">工號</param>
/// <returns></returns>
public DataSet GetLoginUserInfo(string staffIdList)
{
DataSet ds = new DataSet();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(" SELECT distinct OpenId FROM ");
stringBuilder.Append(" TBSF_Conmmunicate_WXUser WHERE Staff_ID IN (");
stringBuilder.Append(staffIdList);
stringBuilder.Append(")");
string strSql = stringBuilder.ToString();
sqlHelper.DBRunSql(strSql, ref ds);
return ds;
}
}
}
五、編寫訂閱消息基類模型
using System;
using System.Data;
using Newtonsoft.Json;
using System.Collections.Generic;
using WXERP.Services.CommunicationOperateDAL;
namespace WXERP.Models
{
/// <summary>
/// 訂閲消息請求模型
/// </summary>
public class SubscribeMessageModel
{
/// <summary>
/// 初始化審核訂閲消息
/// </summary>
/// <param name="dbTransOrCnn">數(shù)據(jù)庫事務(wù)</param>
/// <param name="nextAuditStaffId">下一個審核通知用戶工號</param>
public SubscribeMessageModel(object dbTransOrCnn, string nextAuditStaffId)
{
WXInforDeal wxInfoDeal = new WXInforDeal(dbTransOrCnn);
DataSet wxUserInfo = wxInfoDeal.GetLoginUserInfo(nextAuditStaffId);
if (wxUserInfo != null && wxUserInfo.Tables.Count > 0 && wxUserInfo.Tables[0].Rows.Count > 0)
{
Touser = wxUserInfo.Tables[0].Rows[0]["OpenId"].ToString();
}
}
/// <summary>
/// 消息接收者的openid
/// </summary>
[JsonProperty("touser")]
public string Touser { get; set; }
/// <summary>
/// 消息模板ID
/// </summary>
[JsonProperty("template_id")]
public string TemplateId { get; set; }
/// <summary>
/// 點(diǎn)擊模板卡片后的跳轉(zhuǎn)頁面,僅限本小程序內(nèi)的頁面,支持帶參數(shù)(示例index?foo=bar),該字段不填則不跳轉(zhuǎn)
/// </summary>
[JsonProperty("page")]
public string Page { get; set; }
/// <summary>
/// 跳轉(zhuǎn)小程序類型:developer開發(fā)版、trial體驗(yàn)版、formal正式版,默認(rèn)為正式版
/// </summary>
[JsonProperty("miniprogram_state")]
public string MiniprogramState { get; set; }
/// <summary>
/// 進(jìn)入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認(rèn)為zh_CN
/// </summary>
[JsonProperty("lang")]
public string Lang { get; set; }
/// <summary>
/// 模板內(nèi)容
/// </summary>
[JsonProperty("data")]
public Dictionary<string, DataValue> Data { get; set; }
}
/// <summary>
/// 模板內(nèi)容關(guān)鍵字
/// </summary>
public class DataValue
{
/// <summary>
/// 訂閲消息參數(shù)值
/// </summary>
[JsonProperty("value")]
public string Value { get; set; }
}
/// <summary>
/// 小程序訂閲消息響應(yīng)模型
/// </summary>
public class SubscribeMsgResponseModel
{
/// <summary>
/// 錯誤代碼
/// </summary>
public int Errcode { get; set; }
/// <summary>
/// 錯誤信息
/// </summary>
public string Errmsg { get; set; }
}
/// <summary>
/// 小程序獲取token響應(yīng)模型
/// </summary>
public class AccessTokenResponseModel
{
/// <summary>
/// 小程序訪問token
/// </summary>
public string Access_token { get; set; }
/// <summary>
/// Token過期時間,單位秒
/// </summary>
public int Expires_id { get; set; }
/// <summary>
/// Token創(chuàng)建時間
/// </summary>
public DateTime Create_time { get; set; }
/// <summary>
/// 刷新以後的Token
/// </summary>
public string Refresh_token { get; set; }
/// <summary>
/// 小程序用戶唯一標(biāo)識,如果用戶未關(guān)注公衆(zhòng)號,訪問公衆(zhòng)號網(wǎng)頁也會產(chǎn)生
/// </summary>
public string Openid { get; set; }
/// <summary>
/// 用戶授權(quán)的作用域,使用逗號分隔
/// </summary>
public string Scope { get; set; }
}
}
六、實(shí)現(xiàn)消息訂閱基類,下面的SetTemplateData方法根據(jù)自己的情況設(shè)置需要推送消息的內(nèi)容,如果以后有其他訂閱消息模板,新增一個類實(shí)現(xiàn)SubscribeMessageModel
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using BestSoft.Common.Resources;
using BSFWorkFlow.Common.GeneralUtility;
using WXERP.Models;
namespace WXERP.Services.SubscribeMessage
{
/// <summary>
/// 審核訂閲消息
/// </summary>
public class AuditSubscribeMessage : SubscribeMessageModel
{
private string page;
private string lang;
private Dictionary<string, DataValue> data;
/// <summary>
/// 設(shè)置小程序OpenId
/// </summary>
/// <param name="dbTransOrCnn">數(shù)據(jù)庫事務(wù)</param>
/// <param name="nextAuditStaffId">下一個審核通知用戶工號</param>
public AuditSubscribeMessage(object dbTransOrCnn, string nextAuditStaffId)
: base(dbTransOrCnn, nextAuditStaffId)
{
}
/// <summary>
/// 消息模板ID
/// </summary>
[JsonProperty("template_id")]
public new string TemplateId => Common.Configuration["WX:Templates:Audit:TemplateId"];
/// <summary>
/// 設(shè)置小程序訂閲消息跳轉(zhuǎn)頁面
/// </summary>
/// <param name="formId"></param>
/// <param name="tableId"></param>
public void SetPageUrl(string formId, string tableId)
{
Page = string.Format(Common.Configuration["WX:Templates:Audit:PageUrl"],
formId, tableId);
}
/// <summary>
/// 點(diǎn)擊模板卡片后的跳轉(zhuǎn)頁面
/// </summary>
[JsonProperty("page")]
public new string Page
{
get
{
return page;
}
set
{
page = value;
return;
}
}
/// <summary>
/// 跳轉(zhuǎn)小程序類型
/// </summary>
[JsonProperty("miniprogram_state")]
public new string MiniprogramState => Common.Configuration["WX:Templates:Audit:MiniprogramState"];
/// <summary>
/// 進(jìn)入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認(rèn)為zh_CN
/// </summary>
[JsonProperty("lang")]
public new string Lang
{
get
{
lang = Common.Configuration["WX:Templates:Audit:Lang"];
if (!string.IsNullOrEmpty(MyHttpContext.Current.Request.Headers["bsLanKind"]))
lang = MyHttpContext.Current.Request.Headers["bsLanKind"];
return lang;
}
set
{
lang = value;
return;
}
}
/// <summary>
/// 設(shè)置審核訂閲消息數(shù)據(jù)
/// </summary>
/// <param name="operation">審核動作:通過、否決、作廢、退回</param>
/// <param name="itemAuditStatus">審核狀態(tài):1代表審核完畢</param>
/// <param name="currentWorkflowName">審核標(biāo)題</param>
public void SetTemplateData(WFAuditOperation operation, WFAuditItemStatus itemAuditStatus, string currentWorkflowName)
{
string tip_msg = "";
switch (operation)
{
case WFAuditOperation.AuditPassAndAgree:
if (itemAuditStatus == WFAuditItemStatus.SuccessfulToFinishAllAudits)
tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_FinishAuditTip"), "您的單據(jù)已審核完成!");
else
tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAgreeTip"), "您有一筆新單據(jù)待審核!");
break;
case WFAuditOperation.AuditPassButDegree:
tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditDegreeTip"), "您提交的單據(jù)等待異議!");
break;
case WFAuditOperation.AuditAbort:
tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAbortTip"), "您提交的單據(jù)已被作廢!");
break;
case WFAuditOperation.AuditBack:
tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditBackTip"), "您提交的單據(jù)已被退回修正!");
break;
}
string title = Common.Configuration["WX:Templates:Audit:Data:Title"];
string content = Common.Configuration["WX:Templates:Audit:Data:Content"];
string date = Common.Configuration["WX:Templates:Audit:Data:Date"];
Dictionary<string, DataValue> data = new Dictionary<string, DataValue>()
{
{title, new DataValue{ Value= currentWorkflowName }},
{content, new DataValue{ Value= tip_msg }},
{date, new DataValue{ Value= DateTime.Now.ToShortDateString() }}
};
Data = data;
}
/// <summary>
/// 審核訂閲消息數(shù)據(jù)
/// </summary>
[JsonProperty("data")]
public new Dictionary<string, DataValue> Data
{
get
{
return data;
}
set
{
data = value;
return;
}
}
}
}
七、編寫發(fā)送訂閱消息,消息推送配置簽名認(rèn)證
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Newtonsoft.Json;
using WXERP.Models;
namespace WXERP.Services
{
/// <summary>
/// 系統(tǒng)消息上下文
/// </summary>
public class MessageContext
{
/// <summary>
/// 獲取AccessToken的全局鎖
/// </summary>
private readonly static object SyncLock = new object();
private static Dictionary<string, AccessTokenResponseModel> tokenCache = new Dictionary<string, AccessTokenResponseModel>();
/// <summary>
/// 發(fā)送訂閲消息
/// </summary>
/// <param name="msg">消息內(nèi)容</param>
/// <param name="errMsg">可能由於獲取的token錯誤</param>
/// <returns></returns>
public static bool SendSubscribeMsg(SubscribeMessageModel msg, out string errMsg)
{
errMsg = "";
try
{
string token = GetAccessToken();
if (token.Length < 20)
{
errMsg = "Failed to send subscription message, Access token error!";
return false;
}
string url = string.Format(Common.Configuration["WX:MessageSendUrl"], token);
string requestJson = JsonConvert.SerializeObject(msg);
string responseJson = HttpHelper.HttpPost(url, requestJson, "application/json", null);
var msgResponse = JsonConvert.DeserializeObject<SubscribeMsgResponseModel>(responseJson);
if (msgResponse.Errcode != 0)
{
errMsg = string.Format("Failed to send subscription message, {0}", msgResponse.Errmsg);
return false;
}
}
catch (Exception exp)
{
throw new Exception("SendSubscribeMsg: " + exp.Message);
}
return true;
}
/// <summary>
/// 獲取小程序訪問token
/// </summary>
/// <returns></returns>
private static string GetAccessToken()
{
lock (SyncLock)
{
string appid = Common.Configuration["WX:AppId"];
string appsecret = Common.Configuration["WX:AppSecret"];
string accessTokenUrl = string.Format(Common.Configuration["WX:AccessTokenUrl"], appid, appsecret);
AccessTokenResponseModel result = null;
if (tokenCache.ContainsKey(appid))
result = tokenCache[appid];
if (result == null)
{
string responseJson = HttpHelper.HttpGet(accessTokenUrl, null);
result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson);
result.Create_time = DateTime.Now;
tokenCache.Add(appid, result);
}
else if (DateTime.Compare(result.Create_time.AddSeconds(result.Expires_id), DateTime.Now) < 1)
{
string responseJson = HttpHelper.HttpGet(accessTokenUrl, null);
result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson);
result.Create_time = DateTime.Now;
tokenCache[appid] = result;
}
return result.Access_token;
}
}
/// <summary>
/// 驗(yàn)證消息來自於微信服務(wù)器
/// </summary>
/// <param name="signature">微信加密簽名,signature結(jié)合了開發(fā)者填寫的token、timestamp、nonce</param>
/// <param name="timestamp">時間戳</param>
/// <param name="nonce">隨機(jī)數(shù)</param>
/// <returns></returns>
public async Task<bool> CheckSignature(string signature, string timestamp, string nonce)
{
string token = Common.Configuration["WX:SignatureToken"];
string[] tmpArr = { token, timestamp, nonce };
Array.Sort(tmpArr);
string tmpStr = string.Join("", tmpArr);
tmpStr = Common.SHA1(tmpStr);
if (!tmpStr.Equals(signature, StringComparison.OrdinalIgnoreCase))
return false;
await Task.CompletedTask;
return true;
}
}
}
八、編寫消息推送配置簽名認(rèn)證控制器
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WXERP.Services;
namespace WXERP.Controllers
{
/// <summary>
/// 消息控制器
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class MessageController : ControllerBase
{
private readonly MessageContext _context;
/// <summary>
/// 初始化消息
/// </summary>
public MessageController()
{
_context = new MessageContext();
}
/// <summary>微信消息</summary>
/// <remarks>驗(yàn)證消息來自於微信服務(wù)器</remarks>
/// <param name="signature">微信加密簽名,signature結(jié)合了開發(fā)者填寫的token、timestamp、nonce</param>
/// <param name="timestamp">時間戳</param>
/// <param name="nonce">隨機(jī)數(shù)</param>
/// <param name="echostr">隨機(jī)字符串</param>
/// <returns></returns>
[HttpGet("checkSignature")]
[AllowAnonymous]
public async void CheckSignature(string signature,string timestamp,string nonce,string echostr)
{
bool result = await _context.CheckSignature(signature, timestamp, nonce);
if (result)
{
HttpContext.Response.ContentType = "text/plain; charset=utf-8";
await HttpContext.Response.WriteAsync(echostr);
}
else
{
HttpContext.Response.StatusCode = 409;
HttpContext.Response.ContentType = "text/plain; charset=utf-8";
await HttpContext.Response.WriteAsync("error");
}
}
}
}
九、調(diào)用小程序訂閱消息,需要自己實(shí)現(xiàn)其他邏輯
//@iFormSaveDAL.GetTran 數(shù)據(jù)庫鏈接事務(wù),如果發(fā)送消息失敗,應(yīng)該回滾提交的表單數(shù)據(jù)
//@wFControl.NextAuditNotifyStaffIDStr 下一個審核用戶的工號
//@auditPageData.FormID 表單編號
//@auditPageData.MainRecordID 表單數(shù)據(jù)ID
//@operationByCode 一個枚舉類型,前端傳遞的:審核通過、作廢、退回等
//@wFControl.ItemAuditStatus 一個枚舉類型,如果全部審核完畢為1,否則為0
//@wFControl.CurrentWorkflowName 當(dāng)前流程的名稱,例如:請假單審核
//@SaveAfterInfo 全局字符變量,用于保存結(jié)果信息
AuditSubscribeMessage auditMsg = new AuditSubscribeMessage(iFormSaveDAL.GetTran, wFControl.NextAuditNotifyStaffIDStr);
auditMsg.SetPageUrl(auditPageData.FormID, auditPageData.MainRecordID);
auditMsg.SetTemplateData(operationByCode, wFControl.ItemAuditStatus, wFControl.CurrentWorkflowName);
if (!string.IsNullOrEmpty(auditMsg.Touser))
{
if (!MessageContext.SendSubscribeMsg(auditMsg, out messageStr))
{
SaveAfterInfo = messageStr;
return false;
}
}
到此這篇關(guān)于.NET CORE3.1實(shí)現(xiàn)微信小程序發(fā)送訂閱消息的文章就介紹到這了,更多相關(guān).NET CORE 小程序發(fā)送訂閱內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#后臺調(diào)用前臺javascript的五種方法小結(jié)
于項(xiàng)目需要,用到其他項(xiàng)目組用VC開發(fā)的組件,在web后臺代碼無法訪問這個組件,所以只好通過后臺調(diào)用前臺的javascript,從而操作這個組件。2010-12-12
Repeater的FooterTemplate顯示某列總計(jì)思路與代碼
在Repeater的FooterTemplate顯示某列總計(jì),接下來與大家分享詳細(xì)的實(shí)現(xiàn)方案,感興趣的各位可以參考下哈2013-03-03
Visual Stduio 2010開發(fā)環(huán)境搭建教程
這篇文章主要為大家詳細(xì)介紹了Visual Stduio 2010開發(fā)環(huán)境搭建教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
ASP.NET Core中間件計(jì)算Http請求時間示例詳解
這篇文章主要給大家介紹了關(guān)于ASP.NET Core中間件計(jì)算Http請求時間的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用ASP.NET Core具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
asp.net 使用js分頁實(shí)現(xiàn)異步加載數(shù)據(jù)
這篇文章主要介紹了asp.net使用js分頁實(shí)現(xiàn)異步加載數(shù)據(jù),需要的朋友可以參考下2014-04-04
asp.net中Datalist使用數(shù)字分頁的實(shí)現(xiàn)方法
asp.net下Datalist使用數(shù)字分頁的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2010-10-10

