C# MVC 微信支付之微信模板消息推送

微信支付之微信模板消息推送
 
        
        今天我要跟你们分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那仍是真真的牛逼呐。缘由在哪?就是由于它是依赖微信生存的呀,因此他能不牛逼吗?如今的社会,人多多少少都有或轻或重的“强迫症”。就是,看到有未读消息,都要去看一下。特别是如今的微信,大部分能够几个小时不看手机QQ有没有新消息来,可是这大部分人绝对作不到一个小时不看微信有没有消息来。如今的微信,真特么是神同样的存在,几乎人人手机上都会有微信。并且,若是你的公众号是服务号的话,这个推送消息会显示在首页列表中(若是有新的消息,会把公众号显示在最顶端,并提示有新消息),不像订阅好,会放在一个小盒子里面。成熟的例子也有许多,例如一些商业银行的刷卡消费提醒这些。好,这方面是他微信的优点,就是,you can't miss it.另一个优点就是:只要你给他推送了,他的到达率是很是的高,几乎能够保证,100%送达(鉴于天朝的相关法规,这种100%的东西,是没人敢说的,因此,通常都和谐的说99.97%的样子)。因此,以这样的送达率,秒杀传统的短信通知。更有甚者,就是,他的推送,彻底免费,彻底免费,彻底免费!并且,速度极快,速度极快,速度极快。。。好了,再说下去,估计等下大家觉得我是腾讯的员工了。好了,这些我就很少说了,下面,咱们进入主题吧。
 
        首先,新建一个MVC的项目,以下图(在第二个页面里面,身份认证,改成不须要身份验证):
 
 
        而后咱们去把官方demo(demo地址: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1)中的business和lib拷贝到咱们的项目中,并新建一个文件夹WxLib,放到里面去,以下图:
 
 
        而后咱们再“从新生成”如下项目,或者快捷键:ctrl+shift+b,这时候,会提下以下错误:
 
 
这时候,咱们去添加引用,把 WxLib/ lib文件夹中的 LitJson.dll 添加上便可,以下图:
 
 
 
到这里,咱们就基本把官方的demo的环境给搭建好了,接下来,咱们就要开始编写代码了。
 
首先,咱们来看看官方文档,怎么介绍这个模板消息的,查看步骤(这个是须要登陆公众平台才能看到的),以下图:
 
 
 
        经过API文档,咱们得知,咱们推送模板消息,有三个必需要获取到的参数,他们分别是: ACCESS_TOKEN和OPENID,以及template_id,
ACCESS_TOKEN和OPENID,咱们前面的额公众号支付已经演示过如何获取,若是忘了,能够回头看看( 微信支付教程系列之公众号支付),
        
        下面,我来说讲怎么获取这个template_id。template_id是模板消息的ID,咱们推送消息,不像咱们发短信同样,能够随意编辑内容,想说啥就说啥,必需要符合模板消息的规则。例如,咱们此次选择一个“账户资金变更提醒”,添加操做以下:
点击”添加“以后,就会在”个人模板”里面出现,以下图:
 
 
这个“lypG1jYyOEfYsr*********jOK7-LhEwpPeVNHHxemSI”就是咱们的模板ID了,也就是:template_id。
 
        好,如今,咱们知道 ACCESS_TOKEN和OPENID以及template_id了,理论上,咱们就有了能够发送推送消息的前提了。下面,咱们来进入代码部分,以下:
 
 
        首先,新建一个HomeController.cs,代码以下:
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace 微信支付之模板消息推送.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {
            return View();
        }
    }
} 
复制代码

 

 
 
        而后添加一个View,代码以下:
         
复制代码
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div> 
    </div>
</body>
</html>
复制代码

 

 
 
 
 
 
        再说多几句,咱们此次选的是一个“账户资金变更提醒”,他的传参类型以下:
 
在此以前:因为咱们这里面的文字,还能够设定颜色,咱们从这里(模板里面看不到,可是能够从官方的demo)能够看出来:
可是,咱们本次用的模板不是这个,是“账户资金变更提醒”,可是道理相同,因此,咱们也要新建一个类,文件名字就叫作:DataFontStyle.cs吧,代码以下:
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace 微信支付之模板消息推送.Models
{
    public class DataFontStyle
    {
        public string value { get; set; }
        public string color { get; set; }
    }
}  
复制代码

 

再分析他的参数,分别有:first,date,adCharge,type,cashBalance以及remark,因此,咱们给他新建一个Model,到时候会用到的,新建的Model的文件名字就叫作:CashModel.cs,代码以下:
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
namespace 微信支付之模板消息推送.Models
{
    /// <summary>
    /// 账户资金变更提醒Model
    /// </summary>
    public class CashModel
    {
        public DataFontStyle first { get; set; }
        public DataFontStyle date { get; set; }
        public DataFontStyle adCharge { get; set; }
        public DataFontStyle type { get; set; }
        public DataFontStyle cashBalance { get; set; }
        public DataFontStyle remark { get; set; }
    }
}  
 
复制代码

 

 
 
 
 
此外,还有最后一个,那就是这个推送的Model,也要新建一个类,文件名,咱们就叫作PushMess.cs吧,代码以下:
 
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace 微信支付之模板消息推送.Models
{
    public class PushMessage
    {
        public string touser { get; set; }
        public string template_id { get; set; }
        public string url { get; set; }
        public string topcolor { get; set; }
        /// <summary>
        /// 注意,这里是CashModel,你若是要通用,有多个推送模板要用,那你就用object
        /// </summary>
        public CashModel data { get; set; }
   
    }
}  
复制代码

 

漏了一个类,如今补回来,咱们命名为:WxResult.cs,代码以下:
 
   public class WxResult
    {
        public int? errcode { get; set; }
        public string errmsg { get; set; }
        public int? msgid { get; set; }
    }  

 

 
 
文件物理路径逻辑以下,检查一下,看看有无误差,以下图:
 
        说明一下:一些推送必须的代码,我就直接贴出(例如后去Access_token和推送代码),再也不说明了,由于在前面几篇都有说明,若是看不懂,请翻阅前面的教程。
 
        如今,咱们来编辑一下先后端的代码,前端的代码的逻辑,仍是跟往常同样,我代码尽可能精简,本次,那个推送,我只传一个参数到后台,那就是first,其余的,都是在后台固定,实际项目中应用,到时候,大家再行修改便可,前台代码:
 
 
 
复制代码
@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>身份认证</title>
    <link href="~/Scripts/jquery-easyui-1.4.5/themes/bootstrap/easyui.css" rel="stylesheet" />
    <link href="~/Scripts/jquery-easyui-1.4.5/themes/mobile.css" rel="stylesheet" />
    <link href="~/Scripts/jquery-easyui-1.4.5/themes/icon.css" rel="stylesheet" />
    <style type="text/css">
 
        .line {
            width: 100%;
            float: left;
            height: auto;
            text-align: center;
            margin-top: 15pt;
            font-size: x-large;
        }
 
        .lineText {
            width: 100%;
            float: left;
            height: auto;
            text-indent: 5%;
            text-align: left;
            font-size: x-large;
            margin: 0;
        }
 
        a {
            text-decoration: none;
            color: white;
        }
 
        .input {
            height: 30pt;
            width: 90%;
            font-size: x-large;
            border-radius: 10px;
            margin: 0;
            padding: 0;
        }
 
        .btn {
            width: 90%;
            height: 35pt;
            font-size: x-large;
            background-color: green;
            color: white;
            border: none;
            border-radius: 10px;
        }
    </style>
</head>
<body>
    <div style="width: 100%; text-align: center;">
        <form id="form1">
            <div class="line">
                <div class="lineText">*接收者openid:</div>
            </div>
            <div class="line">
                <input type="text" id="openid" name="openid" class="input" />
            </div>
            <div class="line">
                <div class="lineText">*first.DATA:</div>
            </div>
            <div class="line">
                <input type="text" id="first" name="first" class="input" />
            </div>
        </form>
 
    </div>
    <div class="line">
        <input type="button" id="btnSave" class="btn" value="推送" onclick="fPush()" />
    </div>
    <script src="~/Scripts/jquery-easyui-1.4.5/jquery.min.js"></script>
    <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.min.js"></script>
    <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.mobile.js"></script>
    <script src="~/Scripts/jquery-easyui-1.4.5/easyloader.js"></script>
    <script type="text/javascript">
        $(function () {
            var vCode = getQueryString("code");
            if (vCode != "" && vCode != null) {
                $.ajax({
                    type: 'post',
                    data: {
                        code: vCode
                    },
                    url: '/Home/getWxInfo',
                    success: function (sjson) {
                        $.messager.show({
                            title: '提示',
                            msg: '欢迎您的到来(看到这个提示,表明已经成功获取openid和access_token了)。'
                        });
                        $("#openid").val(sjson.openid);
                    }
                })
            }
            else {
                $.ajax({
                    type: 'post',
                    url: '/Home/getCode',
                    success: function (sjson) {
                        location.href = sjson;
                    }
                })
            }
        })
        //获取url的参数
        function getQueryString(name) {
            var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
            var r = window.location.search.substr(1).match(reg);
            if (r != null) return unescape(r[2]); return null;
        }
 
        //推送
        function fPush() {
            var vTtile = $("#first").val();
            $.ajax({
                type: 'post',
                data: {
                    first: vTtile
                },
                url: '/Home/Push',
                success: function (sjson) {
                    if (sjson.result) {
                        $.messager.alert("提示", sjson.msg, 'info');
                    }
                    else {
                        $.messager.alert("提示", sjson.msg, 'warning');
                    }
                }
            })
        }
    </script>
</body>
</html>
复制代码

 

 
 
后台代码:
 
复制代码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using WxPayAPI;
using 微信支付之模板消息推送.Models;
 
namespace 微信支付之模板消息推送.Controllers
{
    public class HomeController : Controller
    {
        JsApiPay jsApiPay = new JsApiPay();
 
        JavaScriptSerializer JsonHelper = new JavaScriptSerializer();
        /// <summary>
        /// 最后更新Access_token的时间
        /// </summary>
        public static DateTime dtAccess_token;
        /// <summary>
        /// Access_token的值
        /// </summary>
        public static string strAccess_token;
        // GET: Home
        public ActionResult Index()
        {
            if (Session["openid"] == null)
            {
                try
                {
                    //调用【网页受权获取用户信息】接口获取用户的openid和access_token
                    GetOpenidAndAccessToken();
 
                }
                catch (Exception ex)
                {
                    //Response.Write(ex.ToString());
                    //throw;
                }
            }
            return View();
        }
 
        /**
        * 
        * 网页受权获取用户基本信息的所有过程
        * 详情请参看网页受权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
        * 第一步:利用url跳转获取code
        * 第二步:利用code去获取openid和access_token
        * 
        */
        public void GetOpenidAndAccessToken()
        {
            if (Session["code"] != null)
            {
                //获取code码,以获取openid和access_token
                string code = Session["code"].ToString();
                Log.Debug(this.GetType().ToString(), "Get code : " + code);
                jsApiPay.GetOpenidAndAccessTokenFromCode(code);
            }
            else
            {
                //构造网页受权获取code的URL
                string host = Request.Url.Host;
                string path = Request.Path;
                string redirect_uri = HttpUtility.UrlEncode("http://" + host + path);
                WxPayData data = new WxPayData();
                data.SetValue("appid", WxPayConfig.APPID);
                data.SetValue("redirect_uri", redirect_uri);
                data.SetValue("response_type", "code");
                data.SetValue("scope", "snsapi_base");
                data.SetValue("state", "STATE" + "#wechat_redirect");
                string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();
                Log.Debug(this.GetType().ToString(), "Will Redirect to URL : " + url);
                Session["url"] = url;
            }
        }
 
 
        /// <summary>
        /// 获取code
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult getCode()
        {
            object objResult = "";
            if (Session["url"] != null)
            {
                objResult = Session["url"].ToString();
            }
            else
            {
                objResult = "url为空。";
            }
            return Json(objResult);
        }
 
        /// <summary>
        /// 经过code换取网页受权access_token和openid的返回数据
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult getWxInfo()
        {
            object objResult = "";
            string strCode = Request.Form["code"];
            string strAccess_Token = "";
            string strOpenid = "";
            if (Session["access_token"] == null || Session["openid"] == null)
            {
                jsApiPay.GetOpenidAndAccessTokenFromCode(strCode);
                strAccess_Token = Session["access_token"].ToString();
                strOpenid = Session["openid"].ToString();
            }
            else
            {
                strAccess_Token = Session["access_token"].ToString();
                strOpenid = Session["openid"].ToString();
            }
            objResult = new { openid = strOpenid, access_token = strAccess_Token };
            return Json(objResult);
        }
 
        /// <summary>
        /// 推送
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Push()
        {
            object objResult = "";
            string strFirst = Request.Form["first"];
            string strMsg = "";
            bool bResult = false;
            //这个是推送消息的类
            PushMessage aPushMessage = new PushMessage()
            {
                template_id = "lypG1jYyOEfY********OK7-LhEwpPeVNHHxemSI",//模板ID
                //data=,//暂时不赋值
                topcolor = "#FF0000",//头部颜色
                touser = Session["openid"].ToString(),//用户的Openid
                url = "http://www.baidu.com"//用途是当用户点击推送消息的时候,会进入这个页面,具体用途,本身拓展
            };
 
            //构造要推送的内容
            CashModel aCachData = new CashModel()
            {
                adCharge = new DataFontStyle()
                {
                    color = "#589E63",
                    value = "对应变更金额"
                },
                cashBalance = new DataFontStyle()
                {
                    color = "#589E63",
                    value = "对应账户余额"
                },
                date = new DataFontStyle()
                {
                    color = "#589E63",
                    value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                },
                first = new DataFontStyle()
                {
                    color = "#589E63",
                    value = strFirst
                },
                remark = new DataFontStyle()
                {
                    color = "#589E63",
                    value = "对应:点击“查看详情“当即查阅您的账户财务记录。"
                },
                type = new DataFontStyle()
                {
                    color = "#589E63",
                    value = "对应“现金”"
                }
            };
            //这时候,把要推送的内容,赋值给push,这样,咱们要推送的内容就完成了。
            aPushMessage.data = aCachData;
 
            string strUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + GetLatestAccess_token();
            
            string strJsonData = JsonHelper.Serialize(aPushMessage);
            string strResult = HttpPost(strUrl, strJsonData);
            WxResult aResult = JsonHelper.Deserialize<WxResult>(strResult);
            if (aResult != null)
            {
                if (aResult.errcode == 0)
                {
                    bResult = true;
                }
                else
                {
                    bResult = false;
                    strMsg = aResult.errmsg;
                }
            }
            else
            {
                bResult = false;
                strMsg = "通信失败,请重试。";
            }
 
            objResult = new { result = bResult, msg = strMsg };
            return Json(objResult);
        }
 
 
 
        /// <summary>
        /// HttpPost
        /// </summary>
        /// <param name="Url"></param>
        /// <param name="postDataStr"></param>
        /// <returns></returns>
        public static string HttpPost(string Url, string postDataStr)
        {
            byte[] postData = Encoding.UTF8.GetBytes(postDataStr);//编码,尤为是汉字,事先要看下抓取网页的编码方式   
            WebClient webClient = new WebClient();
            webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");//采起POST方式必须加的header,若是改成GET方式的话就去掉这句话便可  
            byte[] responseData = webClient.UploadData(Url, "POST", postData);//获得返回字符流             
            string srcString = Encoding.UTF8.GetString(responseData);//解码 
            return srcString;
           
        }
 
 
        /// <summary>
        /// 返回最新的Access_token
        /// </summary>
        /// <returns></returns>
        public string GetLatestAccess_token()
        {
            if (dtAccess_token == null || dtAccess_token <= DateTime.Now.AddHours(-1) || string.IsNullOrWhiteSpace(strAccess_token))
            {
                string strUrl = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", WxPayConfig.APPID, WxPayConfig.APPSECRET);
                string strAccess_tokenData = HttpGet(strUrl, "");
                ModelForAccess_token aToken = JsonHelper.Deserialize<ModelForAccess_token>(strAccess_tokenData);
                dtAccess_token = DateTime.Now;
                strAccess_token = aToken.access_token;
                return strAccess_token;
            }
            else
            {
                return strAccess_token;
            }
        }
 
        /// <summary>
        /// WebGet
        /// </summary>
        /// <param name="Url"></param>
        /// <param name="postDataStr"></param>
        /// <returns></returns>
        public static string HttpGet(string Url, string postDataStr)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr);
            request.Method = "GET";
            request.ContentType = "text/html;charset=UTF-8";
 
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream myResponseStream = response.GetResponseStream();
            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
            string retString = myStreamReader.ReadToEnd();
            myStreamReader.Close();
            myResponseStream.Close();
 
            return retString;
        }
 
        public class ModelForAccess_token
        {
            public string access_token { get; set; }
            public int? expires_in { get; set; }
        }
    }
} 
复制代码

 

 
 
代码已完整提供,若是有缺漏的,请在评论中指出或者进群来告诉我。若是代码提供正常,应该就能推送到的了,目前这个代码,只能给本身推送。实际应用中,能够经过这个页面,而后绑定用户,这样,咱们就能够经过用户名字,给他们的openid推送消息。下面贴出推送的截图
 
 
 
对了,忘记了一点,这个要发布到IIS上,而后你发布的域名,要在公众平台里面,那个获取用户权限(前面博文说起到)的网址里面,改为你发布的网址,例如:push.lmx.ren ,不然是获取不到用户信息的。
相关文章
相关标签/搜索