在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);
}
});
}
连接到后台的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 });
}
}
其中 MenuManager.CreateMenu()方法就是去将微信菜单对接到微信API上面。如下:
public static void CreateMenu()
{
NHibernateHelper nhlper = new NHibernateHelper();
ISession session = nhlper.GetSession();
IEnumerable<WeiXinMenu> kinds = session.Query<WeiXinMenu>();
if (kinds.Count() <= )
{
throw new Exception("请先配置菜单");
}
string menu = "";
menu += "{\"button\":[";
kinds.Where(c => c.ParentId == "").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 - , );
menu += "]";
menu += "},";
});
menu = menu.Remove(menu.Length - , ); 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 != "")
{
throw new Exception(Weixin_Errorcode.GetErrormsg(int.Parse(errcode)));
}
}
其中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 = ;//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().AddSeconds(-))
{
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;
}
}
}
在访问这种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, , 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;
}
}
}
- 编辑新增菜单
通过控制器返回视图:
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 = "";
model.CreateTime = DateTime.Now;
} return View(model);
}
控制器动作跟着返回查询到的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="" 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="">启用菜单</option>
<option value="">禁用菜单</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="" align="center"></td>
</tr>
<tr>
<td colspan="" 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();
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().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> }
通过ajax在后台进行saveorupdate