MVC下c#对接微信公众平台开发者模式

 

在ashx文件中进行HttpContext的处理:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Biz.WX;

namespace weixinplat
{
    /// <summary>
    /// WeiXin 的摘要说明
    /// </summary>
    public class WeiXin : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            try
            {
                string postString = string.Empty;//初始化空字符串来转抓到的request请求的bit流
                context.Response.ContentType = "text/plain";
                if (context.Request.HttpMethod.ToLower() == "post")//如果从requset的httpmethod方法是post就进行图文等处理
                {

                }
                else//否则就是get方式,进行校验认证
                {
                    AccessToken.Auth();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            
            
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

在专门处理数据的类库Biz中校验:

其中AccessToken类用来处理token:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Configuration;

namespace Biz.WeiXin
{
    public class AccessToken
    {
        /// <summary>
        /// 这个函数是初始化配置服务器地址
        /// </summary>
        public static void Auth()
        {
            string echoStr = HttpContext.Current.Request.QueryString["echoStr"];
            if (CheckSignature()) //校验签名是否正确
            {
                if (!string.IsNullOrEmpty(echoStr))
                {
                    HttpContext.Current.Response.Write(echoStr);
                    HttpContext.Current.Response.End();

                }
            }
        }
        /// <summary>
        /// 校验微信公众平台签名函数
        /// </summary>
        /// <returns></returns>
        public static bool CheckSignature()
        {
            string signature = HttpContext.Current.Request.QueryString["signature"];
            string timestamp = HttpContext.Current.Request.QueryString["timestamp"];
            string nonce = HttpContext.Current.Request.QueryString["nonce"];
            string token = ConfigurationManager.AppSettings["weixin_token"];

            string[] tmpArr = { token , timestamp, nonce };
            Array.Sort(tmpArr);
            string tmpStr = string.Join("", tmpArr);
            tmpStr = WX.Sha1_Hash(tmpStr);

            if (tmpStr == signature)
            {
               
                return true;
            }
            else
            {
                return
                    false;
            }


        }
    }
}

WX类用来处理哈希算法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Biz.WX
{
    public class WX
    {
        public static string Sha1_Hash(string str_sha1_in)
        {
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            byte[] bytes_sha1_in = UTF8Encoding.Default.GetBytes(str_sha1_in);
            byte[] bytes_sha1_out = sha1.ComputeHash(bytes_sha1_in);
            string str_sha1_out = BitConverter.ToString(bytes_sha1_out);
            str_sha1_out = str_sha1_out.Replace("-", "").ToLower();
            return str_sha1_out;
        }
    }
}
  •  将菜单发布到微信公众平台

在treegrid空间的toolbar工具栏按钮中通过ajax来连接到后台方法:

 {
                    id: 'btnRefresh',
                    text: '发布到微信公众平台',
                    iconCls: 'icon-redo',
                    handler: function () {
                        $.ajax({
                            url: "/WxMenu/MenuToWeiXin",
                            data: {},
                            dataType: "json",
                            type: "POST",
                            traditional: true,
                            beforeSend: function () {
                                showProcess(true, "系统提示", "正发布到微信公众平台......");
                            },
                            error: function () {
                            },
                            success: function (result) {
                                showMsg("系统提示", result.Message, false);
                            },
                            complete: function () {
                                showProcess(false);
                            }
                        });
                    }
View Code

连接到后台的MenuToWeiXin方法返回json对象:

 public JsonResult MenuToWeiXin()
        {
            try
            {
                MenuManager.CreateMenu();
                return Json(new { Success = true, Message = "请求成功" });
            }
            catch (Exception ex)
            {
                return Json(new { Success = false,Message = ex.Message });
            }
        }
View Code

其中 MenuManager.CreateMenu()方法就是去将微信菜单对接到微信API上面。如下:

public static void CreateMenu()
        {
            NHibernateHelper nhlper = new NHibernateHelper();
            ISession session = nhlper.GetSession();
            IEnumerable<WeiXinMenu> kinds = session.Query<WeiXinMenu>();
            if (kinds.Count() <= 1)
            {
                throw new Exception("请先配置菜单");
            }
            string menu = "";
            menu += "{\"button\":[";
            kinds.Where(c => c.ParentId == "10000").Foreach(c => {
                menu += "{";
                menu += "\"name\":\"{0}\",".FormartWith(c.MenuName);
                menu += "\"sub_button\":[";
                kinds.Where(m=>m.ParentId==c.MenuId).Foreach(m=> {
                    menu += "{";
                    menu += "\"type\":\"{0}\",".FormartWith(m.MenuType);
                    menu += "\"name\":\"{0}\",".FormartWith(m.MenuName);
                    if (m.MenuType == "click")
                    {
                        menu += "\"key\":\"{0}\"".FormartWith(m.MenuKey);
                    }
                    else
                    {
                        menu += "\"url\":\"{0}\"".FormartWith(m.MenuUrl);
                    }
                    menu += "},";
                });
                menu = menu.Remove(menu.Length - 1, 1);
                menu += "]";
                menu += "},";
            });
            menu = menu.Remove(menu.Length - 1, 1);

            menu += "]";
            menu += "}";
            string url = url_menu_create + AccessToken.Weixin_ACCESS_TOKEN;
            string responsestring = HttpUtils.GetHttprequest(url);
            JObject result = JsonConvert.DeserializeObject(responsestring) as JObject;
            string errcode = result["errcode"].ToString();
            string errmsg = result["errmsg"].ToString();
            if (errcode != "0")
            {
                throw new Exception(Weixin_Errorcode.GetErrormsg(int.Parse(errcode)));
            }
        }
View Code

其中url_menu_create是微信给的API接口 private static string url_menu_create = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="; 

 然后将查询到的菜单组装成微信后台需要的json格式。然后调用接口,用post方式的httprequest去访问。可以根据返回的错误代码来知道具体问题是在哪里。

tips:调用微信的很多API接口都需要微信的access_token,所以可以单独写个类来获取:其中AccessToken.Weixin_ACCESS_TOKEN就是获取到微信的access_token:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Configuration;
using System.Security.Cryptography;
using Business.Extsion;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Business.weixin
{
    public class AccessToken
    {
        public static string AppID = ConfigurationManager.AppSettings["weixin_AppID"];
        public static string AppSecret = ConfigurationManager.AppSettings["weixin_AppSecret"];

        public static string mAccessToken;
        public static DateTime GettokenTime;
        public static int Expires_Period = 7200;//token有效时间,默认2小时

        /// <summary>
        /// 正经对接微信公众平台函数。获取echoStr,来返回。
        /// </summary>
        public static void Auth()
        {
            string echoStr = HttpContext.Current.Request.QueryString["echoStr"];
            if (CheckSignature())
            {
                if (!string.IsNullOrEmpty(echoStr))
                {
                    HttpContext.Current.Response.Write("echoStr");
                    HttpContext.Current.Response.End();
                }
            }
        }

        /// <summary>
        /// 校验函数,微信后台返回的signature和token+timestamp+nonce 对比
        /// </summary>
        /// <returns></returns>
        public static bool CheckSignature()
        {
            string signature = HttpContext.Current.Request.QueryString["signature"];
            string timestamp = HttpContext.Current.Request.QueryString["timestamp"];
            string nonce = HttpContext.Current.Request.QueryString["nonce"];
            string token = ConfigurationManager.AppSettings["weixintoken"];

            string[] tmpArr = { token, timestamp, nonce };
            Array.Sort(tmpArr);
            string tmpStr = string.Join("", tmpArr);
            tmpStr = Sha1_Hash(tmpStr);//通过hash算法得到一个字符串,跟signature对比
            if (tmpStr == signature)
            {
                return true;
            }
            else
            {
                return false;
            }

        }

        public static string Sha1_Hash(string intputstr)
        {
            SHA1 sha1 =new SHA1CryptoServiceProvider();
            byte[] byte_in = UTF8Encoding.Default.GetBytes(intputstr);
            byte[] byte_out = sha1.ComputeHash(byte_in);
            string outputstr = BitConverter.ToString(byte_out);
            outputstr = outputstr.Replace("-","").ToLower();
            return outputstr;
        }

        
        public static string Weixin_ACCESS_TOKEN
        {
            get{
                //如果为空或者过期。则重新获取
                if (string.IsNullOrEmpty(mAccessToken) || HasExpired())
                {
                    //获取accesstoken函数
                    mAccessToken = GetAccessToken(AppID, AppSecret);
                }
                return mAccessToken;
            }
        }
        /// <summary>
        /// 判断是不是token过期
        /// </summary>
        /// <returns></returns>
        public static bool HasExpired()
        {
            if (GettokenTime != null)
            {
                if (DateTime.Now > GettokenTime.AddSeconds(7200).AddSeconds(-60))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 获取accesstoken函数
        /// </summary>
        /// <param name="AppID"></param>
        /// <param name="AppSecret"></param>
        /// <returns></returns>
        public static string GetAccessToken(string AppID,string AppSecret)
        {
            string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
            url = string.Format(url, AppID, AppSecret);
            string responsestring = HttpUtils.GetHttprequest(url);
            JObject result = JsonConvert.DeserializeObject(responsestring) as JObject;
            if (result["access_token"] != null)
            {
                GettokenTime = DateTime.Now;
                if (result["expires_in"] != null)
                {
                    Expires_Period = int.Parse(result["expires_in"].ToString());
                }
                return result["access_token"].ToString();
            }
            else
            {
                GettokenTime = DateTime.MinValue;
            }
            return null;
        }
    }
}
View Code

在访问这种api接口的时候都需要主动去访问,所以可以把httprequest请求单独写在一个类HttpUtils中:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Business.Extsion
{
   public class HttpUtils
    {
        /// <summary>
        /// 发起一个post类型的http请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string SendHttprequest(string url,string data)
        {
            return SendPostHttprequest( url, "application/x-www-form-urlencoded",  data);
        }
        /// <summary>
        /// 发起一个get模式的http请求
        /// </summary>
        /// <returns></returns>
        public static string GetHttprequest(string url)
        {
            return SendGetHttprequest(url,"application/x-www-form-urlencoded");
        }
        public static string SendPostHttprequest(string url,string contentType, string requestData)
        {
            WebRequest request = (WebRequest)HttpWebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = contentType;
            byte[] postbytes = Encoding.UTF8.GetBytes(requestData);
            request.ContentLength = postbytes.Length;
            using (Stream outstream = request.GetRequestStream())
            {
                outstream.Write(postbytes, 0, postbytes.Length);
            }
            string result = string.Empty;
            using (WebResponse response = request.GetResponse())
            {
                if (response !=null)
                {
                    using (Stream getstream = response.GetResponseStream())
                    {
                        using (StreamReader reader = new StreamReader(getstream,Encoding.UTF8))
                        {
                            result = reader.ReadToEnd();
                        }
                    }
                }
            }
            return result;

        }

        public static string SendGetHttprequest(string url ,string contenType)
        {
            WebRequest request = (WebRequest)HttpWebRequest.Create(url);
            request.Method = "GET";
            request.ContentType = contenType;
            string result = string.Empty;
            using (WebResponse response = request.GetResponse())
            {
                if (response != null)
                {
                    using (Stream resstream = response.GetResponseStream())
                    {
                        using (StreamReader reader = new StreamReader(resstream,Encoding.UTF8) )
                        {
                            result = reader.ReadToEnd();
                        }
                    }
                }
            }
            return result;
        }
    }
}
View Code
  • 编辑新增菜单

通过控制器返回视图:

public ActionResult MenuEdit(int id)
        {
            NHibernateHelper nhlper = new NHibernateHelper();
            ISession session = nhlper.GetSession();
            WeiXinMenu model = session.Get<WeiXinMenu>(id);

            if (model == null)
            {
                model = new WeiXinMenu();
                model.IsEnable = "1";
                model.CreateTime = DateTime.Now;
            }

            return View(model);
        }
View Code

控制器动作跟着返回查询到的model在视图上显示:

@model Domain.OrmLib.Entity.WeiXinMenu
@{
    ViewBag.Title = "MenuEdit";
    Layout = "~/Views/Shared/_Form.cshtml";
}

@section header {

}

@section body{
    @using (Html.BeginForm("MenuSaveOrUpdate", "WeiXin", FormMethod.Post, new { id = "dataForm" }))
    {
        <table class="datalistDaily" cellpadding="5" style="font-size:12px;margin-top:10px;margin-left:10px;">
            <tr>
                <td style="text-align:right;">菜单编码:</td>
                <td>
                    <input class="easyui-textbox" id="MenuId" name="MenuId"
                           style="width:300px;" data-options="required:true" value="@Model.MenuId" />
                </td>
            </tr>
            <tr>
                <td style="text-align:right;">菜单名字:</td>
                <td>
                    <input class="easyui-textbox" id="MenuName" name="MenuName"
                           style="width:300px;" data-options="required:true" value="@Model.MenuName" />
                </td>
            </tr>
            <tr>
                <td style="text-align:right;">动作类型:</td>
                <td>
                    <select id="MenuType" name="MenuType" class="easyui-combobox" style="width:300px;">
                        <option selected="selected" value="view">跳转URL</option>
                        <option value="click">点击推事件</option>
                        <option value="scancode_push">扫码推事件</option>
                        <option value="scancode_waitmsg">扫码推事件且弹出(消息接收中)提示框</option>
                        <option value="pic_sysphoto">弹出系统拍照发图</option>
                        <option value="pic_photo_or_album">弹出拍照或者相册发图</option>
                        <option value="pic_weixin">弹出微信相册发图器</option>
                        <option value="location_select">弹出地理位置选择器</option>
                        <option value="media_id">下发消息(除文本消息)</option>
                        <option value="view_limited">跳转图文消息URL</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td style="text-align:right;">菜单Url:</td>
                <td>
                    <input class="easyui-textbox" id="MenuUrl" name="MenuUrl"
                           style="width:300px;" value="@Model.MenuUrl" />
                </td>
            </tr>
            <tr>
                <td style="text-align:right;">菜单Key:</td>
                <td>
                    <input class="easyui-textbox" id="MenuKey" name="MenuKey"
                           style="width:300px;" value="@Model.MenuKey" />
                </td>
            </tr>
            <tr>
                <td style="text-align:right;">菜单排序:</td>
                <td>
                    <input class="easyui-textbox" id="OrderBy" name="OrderBy" data-options="required:true"
                           style="width:300px;" value="@Model.OrderBy" />
                </td>
            </tr>
            <tr>
                <td style="text-align:right;">菜单状态:</td>
                <td>
                    <select id="IsEnable" name="IsEnable" class="easyui-combobox" style="width:300px;">
                        <option selected="selected" value="1">启用菜单</option>
                        <option value="0">禁用菜单</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td style="text-align:right;">上级菜单:</td>
                <td>
                    <input class="easyui-combotree" name="ParentId" id="ParentId" style="width:300px;" />
                </td>
            </tr>
            <tr>
                <td colspan="2" align="center"></td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    @Html.HiddenFor(model => model.Id)
                    @Html.HiddenFor(model => model.UserNum)
                    @Html.HiddenFor(model => model.UserName)
                    @Html.HiddenFor(model => model.CreateTime)
                    <a icon="icon-ok" class="easyui-linkbutton" onclick="save()">存盘</a>
                </td>
            </tr>
        </table>
    }

    }

@section scripts {
<script src="~/Content/oa/scripts/xlayout.js"></script>
<script type="text/javascript">
    $(function () {
        $('#ParentId').combotree({
            url: "/WxMenu/MenuTree",
            required: true,
            multiple: false,
            lines: true,
            queryParams: { ids: '@Model.ParentId' },
            onLoadSuccess: function () {
                $('#ParentId').combotree('setValue', '@Model.ParentId');
            }
        });
        $('#MenuType').combobox('setValue', '@Model.MenuType');
        $('#IsEnable').combobox('setValue', '@Model.IsEnable');
    })
    function save() {
        alert(2212);
        var dataForm = $("#dataForm").form('validate');
        if (!dataForm) return;

        showProcess(true, "系统提示", "正在存盘中......");
        $.ajax({
            url: "/WxMenu/MenuSaveOrUpdate",
            data: $("#dataForm").serialize(),
            dataType: "json",
            type: "POST",
            traditional: true,
            success: function (result) {
                showProcess(false);
                if (result.Success) {
                    var sys_main = $(self.top.document).find("#sys_main").get(0).contentWindow;
                    sys_main.radWindowCallBackFn();
                    var url = document.URL;
                    url = url.replace("http://" + window.location.host, "");
                    url = url.replace(/\//g, "_");
                    sys_main.CloseWindow(url);
                } else {
                    showMsg("系统提示", result.Message, false);
                }
            }
        });
        return false;
    }

    </script>

}
View Code

通过ajax在后台进行saveorupdate

 

posted @ 2017-05-16 23:27  jackche  阅读(2394)  评论(0编辑  收藏  举报