上来就直接贴代码了,具体问题放到最后说,这个类我将方法全都封装在里面了,基本上拿去修改一下就可以用了
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using System.Web.SessionState;
using Website_CS;
using mgtArticle.mgtArticle;
using System.Net;
using System.Text;
using System.IO;
using System.Data;
using BHWeb;
namespace mgtArticle.wxArticle
{
//此类用于微信功能
public class WebChatHelper
{
private Regex _regex = new Regex(@"\{.*\}", RegexOptions.IgnoreCase);
#region 获取access_token
/// <summary>
/// 获取access_token
/// </summary>
/// <param name="redirect_uri">请求acess_token的地址</param>
/// <param name="appId">微信appID</param>
/// <param name="appSecret">微信appSecret</param>
/// <returns>access_token</returns>
public string GetAccessToken(string redirect_uri, string appId, string appSecret)
{
HttpHelper helper = new HttpHelper();
string access_token = "";
//获取access_token、openId
string access_Token_Url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, appSecret);
string get_Token = helper.GetPageResponse_Get(access_Token_Url, redirect_uri, "*/*");
if (_regex.IsMatch(get_Token))
get_Token = _regex.Match(get_Token).Value;
var result = JsonConvert.DeserializeObject<Get_Access_token>(get_Token);
access_token = result.Access_Token;
return access_token;
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="access_token">微信返回的access_token</param>
/// <param name="type">上传文件的类型</param>
/// <param name="path"></param>
/// <returns></returns>
private static string UploadFile(string access_token, string type, string path)
{
// 设置参数
string url = string.Format("http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token={0}&type={1}", access_token, type);
return HttpUploadFile(url, path);
}
private static string UploadImg(string access_token, string path)
{
// 设置参数
string url = string.Format("https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={0}", access_token);
return HttpUploadFile(url, path);
}
/// <summary>
/// Http上传文件
/// </summary>
public static string HttpUploadFile(string url, string path)
{
// 设置参数
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
CookieContainer cookieContainer = new CookieContainer();
request.CookieContainer = cookieContainer;
request.AllowAutoRedirect = true;
request.Method = "POST";
string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;
byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
int pos = path.LastIndexOf("\\");
string fileName = path.Substring(pos + 1);
//请求头部信息
StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\nContent-Type:application/octet-stream\r\n\r\n", fileName));
byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
byte[] bArr = new byte[fs.Length];
fs.Read(bArr, 0, bArr.Length);
fs.Close();
Stream postStream = request.GetRequestStream();
postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
postStream.Write(bArr, 0, bArr.Length);
postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
postStream.Close();
//发送请求并获取相应回应数据
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程序才开始向目标网页发送Post请求
Stream instream = response.GetResponseStream();
StreamReader sr = new StreamReader(instream, Encoding.UTF8);
//返回结果网页(html)代码
string content = sr.ReadToEnd();
return content;
}
#endregion
#region 拼接图文内容
/// <summary>
/// 拼接图文消息素材Json字符串
/// </summary>
/// <param name="access_token">微信获取的access_token</param>
/// <param name="cIDs">文章的id,用于去数据库读取多个文章用,隔开</param>
/// <returns>拼接好的微信文章Json数据或错误内容,格式为1|Json数据或-1|错误内容</returns>
public string GetArticlesJsonStr(string access_token, string cIDs)
{
RecordSet RS = new RecordSet(BHSet.ConnString, SqlSelector.MSSql);
StringBuilder sbArticlesJson = new StringBuilder();
sbArticlesJson.Append("{\"articles\":[");//图文消息,一个图文消息支持1到10条图文
string[] arr_id = cIDs.Split(‘,‘);
for (int i = 0; i < arr_id.Length; i++)
{
string sql = "select * from Article where cID=‘" + arr_id[i] + "‘ and iStatus=‘1‘";
RS.Execute(sql);
if (RS.RecordCount > 0)
{
foreach (DataRow dr in RS.Rows)
{
string path = HttpContext.Current.Server.MapPath(getPicurte(dr["cContent"].ToString()));
if (!File.Exists(path))
{
return "-1|要发送的图片不存在";
}
// 上传图片返回媒体ID
string msg = UploadFile(access_token, "image", path);
if (_regex.IsMatch(msg))
msg = _regex.Match(msg).Value;
var result = JsonConvert.DeserializeObject<Get_Media_Id>(msg);
string thumb_media_id = result.Media_ID;
string noPicContent = GetNoPicarticle(dr["cContent"].ToString());//去除文章内容中的图片地址
if (noPicContent.Length > 54)
noPicContent = noPicContent.Substring(0, 53);
string changePicContent = GetReplacePic(dr["cContent"].ToString(),access_token);//替换文章内容中的图片地址
sbArticlesJson.Append("{");
sbArticlesJson.Append("\"thumb_media_id\":\"" + thumb_media_id + "\",");
sbArticlesJson.Append("\"author\":\"律桥法律平台\",");
sbArticlesJson.Append("\"title\":\"" + dr["cTitle"].ToString() + "\",");
sbArticlesJson.Append("\"content_source_url\":\"http://www.lvqiao.net/Mobile/ArticleDetail.aspx?cID=" + dr["cID"].ToString() + "\",");//在图文消息页面点击“阅读原文”后的页面
sbArticlesJson.Append("\"content\":\"" + changePicContent + "\",");//图文消息页面的内容,支持HTML标签。具备微信支付权限的公众号,可以使用a标签,其他公众号不能使用
sbArticlesJson.Append("\"digest\":\"" + noPicContent + "\",");//图文消息的描述
sbArticlesJson.Append(i == arr_id.Length - 1 ? "\"show_cover_pic\":\"0\"}" : "\"show_cover_pic\":\"0\"},");// 是否显示封面,1为显示,0为不显示
}
}
}
sbArticlesJson.Append("]}");
return "1|"+sbArticlesJson.ToString();
}
//获取文章内容中第一张的图片路径
private string getPicurte(string cContent)
{
string src = "";
int iIndex = 0;
int iEnd = 0;
try
{
iIndex = cContent.ToLower().IndexOf("src=\"");
if (iIndex > 0)
{
iIndex = cContent.ToLower().IndexOf("\"", iIndex);
iEnd = cContent.ToLower().IndexOf("\"", iIndex + 2);
src = cContent.Substring(iIndex, iEnd - iIndex);
src = src.Replace("\"", "").Replace("src=", "");
}
else
{
src = "";
}
}
catch (Exception ex)
{
src = ex.Message + "(" + iIndex + "," + iEnd + ")";
}
return src;
}
#endregion
#region 获取文章的media_id
/// <summary>
/// 请求Url,发送数据
/// </summary>
public static string PostUrl(string url, string postData)
{
byte[] data = Encoding.UTF8.GetBytes(postData);
// 设置参数
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
CookieContainer cookieContainer = new CookieContainer();
request.CookieContainer = cookieContainer;
request.AllowAutoRedirect = true;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
Stream outstream = request.GetRequestStream();
outstream.Write(data, 0, data.Length);
outstream.Close();
//发送请求并获取相应回应数据
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程序才开始向目标网页发送Post请求
Stream instream = response.GetResponseStream();
StreamReader sr = new StreamReader(instream, Encoding.UTF8);
//返回结果网页(html)代码
string content = sr.ReadToEnd();
return content;
}
/// <summary>
/// 上传图文消息素材获取media_id
/// </summary>
/// <param name="access_token">微信的access_token</param>
/// <param name="postData">拼接好的微信文章json数据</param>
/// <returns>media_id</returns>
public string UploadNews(string access_token, string postData)
{
string content = "";
content = PostUrl(string.Format("https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token={0}", access_token), postData);
if (_regex.IsMatch(content))
content = _regex.Match(content).Value;
var result = JsonConvert.DeserializeObject<Get_Media_Id>(content);
string media_id = result.Media_ID;
string type = result.Type;
string create_at = result.Created_At;
return media_id;
}
#endregion
#region 获取所有关注者的openid
/// <summary>
/// 获取关注者OpenID集合
/// </summary>
/// <param name="access_token">微信获取的access_token</param>
/// <param name="redirect_uri">请求获取openid的页面地址</param>
/// <returns>OpenID集合</returns>
public List<string> GetOpenIDs(string access_token, string redirect_uri)
{
List<string> result = new List<string>();
List<string> openidList = GetOpenIDs(access_token, null, redirect_uri);
result.AddRange(openidList);
while (openidList.Count > 9999)
{
openidList = GetOpenIDs(access_token, openidList[openidList.Count - 1], redirect_uri);
if (openidList.Count > 0)
result.AddRange(openidList);
}
return result;
}
/// <summary>
/// 获取关注者OpenID集合
/// </summary>
public List<string> GetOpenIDs(string access_token, string next_openid,string redirect_uri)
{
// 设置参数
HttpHelper helper = new HttpHelper();
string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}&next_openid={1}", access_token, string.IsNullOrWhiteSpace(next_openid) ? "" : next_openid);
string returnStr = helper.GetPageResponse_Get(url, redirect_uri, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
List<string> list = new List<string>();
var result_list = JsonConvert.DeserializeObject<Get_OpenID>(returnStr);
if (result_list.Data.OpenID.Length > 0)
{
string[] resule_data = result_list.Data.OpenID;
list.AddRange(resule_data);
}
return list;
}
#endregion
#region 拼接图文消息
/// <summary>
/// 拼接图文消息json
/// </summary>
/// <param name="media_id"></param>
/// <param name="openidList"></param>
/// <returns></returns>
public string CreateNewsJson(string media_id, List<string> openidList)
{
StringBuilder sb = new StringBuilder();
sb.Append("{\"touser\":[");
sb.Append(string.Join(",", openidList.ConvertAll<string>(a => "\"" + a + "\"").ToArray()));
sb.Append("],");
sb.Append("\"mpnews\":{\"media_id\":\"" + media_id + "\"},");
sb.Append("\"msgtype\":\"mpnews\"");
sb.Append("}");
return sb.ToString();
}
/// <summary>
/// 拼接图文消息(用于预览),只能使用单一的微信号或者微信openid,需手动更改
/// </summary>
/// <param name="media_id"></param>
/// <returns></returns>
public string CreateNewsJson2(string media_id)
{
BSet b = new BSet("9000");
StringBuilder sb = new StringBuilder();
sb.Append("{\"towxname\":\""+b.cCode2+"\",");
sb.Append("\"msgtype\":\"mpnews\",");
sb.Append("\"mpnews\":{\"media_id\":\"" + media_id + "\"}");
sb.Append("}");
return sb.ToString();
}
/// <summary>
/// 根据OpenID列表群发
/// </summary>
public string Send(string access_token, string postData, string redirect_uri)
{
HttpHelper helper = new HttpHelper();
return helper.GetPageResponse_Post(string.Format("https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token={0}", access_token), postData, redirect_uri);
}
#endregion
#region 微信接口预览
/// <summary>
/// 预览接口
/// </summary>
/// <param name="access_token">access_token</param>
/// <param name="media_id">消息的media_id</param>
/// <param name="openidList">用户openidList数组</param>
/// <param name="redirect_uri">请求页面的地址</param>
/// <param name="postData">文章内容</param>
/// <returns></returns>
public string previewMsg(string access_token, string postData, string redirect_uri)
{
HttpHelper helper = new HttpHelper();
return helper.GetPageResponse_Post(string.Format("https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token={0}", access_token), postData, redirect_uri);
}
#endregion
#region Utility
/// <summary>
/// 生成随机字母字符串(数字字母混和)
/// </summary>
public static string GenerateCheckCode()
{
int rep = 0;
string str = string.Empty;
long num2 = DateTime.Now.Ticks + rep;
rep++;
Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep)));
for (int i = 0; i < 15; i++)
{
char ch;
int num = random.Next();
if ((num % 2) == 0)
{
ch = (char)(0x30 + ((ushort)(num % 10)));
}
else
{
ch = (char)(0x41 + ((ushort)(num % 0x1a)));
}
str = str + ch.ToString();
}
return str;
}
/// <summary>
/// 获取没有图片的文章内容
/// </summary>
public string GetNoPicarticle(string content) {
string str = "<img(.*?)(src)=\"(?!.*?logo).*>";
Regex regex = new Regex(str);
foreach(Match re in regex.Matches(content)){
content = content.Replace(re.Value, "");
}
content = content.Replace("\"", "‘").Replace("<p>","").Replace("</p>","");
content = content.Replace("<label>", "").Replace("</label>", "").Replace("<span>", "</span>");
return content;
}
/// <summary>
/// 替换文章内的图片链接
/// </summary>
/// <returns></returns>
public string GetReplacePic(string content, string access_token)
{
string str = @"<img.*?src=""([^""]*)"".*?>";
Regex regex = new Regex(str);
foreach (Match re in regex.Matches(content))//匹配出所有src
{
////获取图片在微信的url
string wx_url = UploadImg(access_token, HttpContext.Current.Server.MapPath(re.Groups[1].Value));
if (_regex.IsMatch(wx_url))
wx_url = _regex.Match(wx_url).Value;
var result_url = JsonConvert.DeserializeObject<Get_ImgUrl>(wx_url);
string url = result_url.URL;
string result = re.Groups[1].Value.Replace(re.Groups[1].Value, url);
content = content.Replace(re.Groups[1].Value, result);
}
content = content.Replace("\"", "‘");
return content;
}
#endregion
#region Json
//Json解析
public class Get_Access_token
{
[JsonProperty("access_token")]
public string Access_Token { get; set; }
[JsonProperty("expires_in")]
public string Expires_In { get; set; }
}
public class ErrorCode
{
[JsonProperty("errcode")]
public string ErrCode { get; set; }
[JsonProperty("errmsg")]
public string ErrMsg { get; set; }
[JsonProperty("msg_id")]
public string Msg_ID { get; set; }
[JsonProperty("msg_data_id")]
public string Msg_Data_ID { get; set; }
}
public class Get_Media_Id
{
// 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb),次数为news,即图文消息
[JsonProperty("type")]
public string Type { get; set; }
// 媒体文件/图文消息上传后获取的唯一标识
[JsonProperty("media_id")]
public string Media_ID { get; set; }
// 媒体文件上传时间
[JsonProperty("created_at")]
public string Created_At { get; set; }
// [JsonProperty("thumb_media_id")]
//public string Thumb_media_id { get; set; }
}
public class Get_OpenID
{
//媒体文件类型ID
[JsonProperty("total")]
public string Total { get; set; }
[JsonProperty("count")]
public string Count { get; set; }
[JsonProperty("data")]
public Get_OpenIDs Data { get; set; }
[JsonProperty("next_openid")]
public string Next_Openid { get; set; }
}
public class Get_OpenIDs
{
//关注者列表ID
[JsonProperty("openid")]
public string[] OpenID { get; set; }
}
public class Get_ImgUrl
{
//图片在微信的地址
[JsonProperty("url")]
public string URL { get; set; }
}
#endregion
}
}
方法调用
/// <summary>
/// WebChatMsgSub 微信接口调用
/// </summary>
public class WebChatMsgSub : IHttpHandler, IReadOnlySessionState
{
private Regex _regex = new Regex(@"\{.*\}", RegexOptions.IgnoreCase);
public string cIDs = "";
public string appId = "xxxxxx";//微信appId
public string appSecret = "xxxxx";//微信appSecret
public string access_token = "",
media_id = "",
postData = "",
ops = "",
openidlist = "",
redirect_uri = "",
wx_result="",
end_content = "";
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
WebChatHelper wx_helper = new WebChatHelper();
cIDs = HttpUtility.UrlDecode(SqlRequest.Get("cIDs"));//获取文章的数量
string subType = SqlRequest.Get("subType");//0:预览接口 1:发送图文消息
string content = "", p_0 = "";
#region 获取access_token
redirect_uri = context.Request.Url.ToString();
access_token = wx_helper.GetAccessToken(redirect_uri, appId, appSecret);
if (string.IsNullOrEmpty(access_token))
{
context.Response.Write("access_token获取失败"); return;
}
#endregion
#region 拼接图文内容
content = wx_helper.GetArticlesJsonStr(access_token, cIDs);
p_0 = content.Split(‘|‘)[0];
postData = content.Split(‘|‘)[1];
if (p_0 == "-1")
{
context.Response.Write(postData); return;
}
//context.Response.Write(postData); return;
#endregion
#region 获取本次消息的media_id
media_id = wx_helper.UploadNews(access_token, postData);
if (string.IsNullOrEmpty(media_id))
{
context.Response.Write("media_id获取失败"); return;
}
#endregion
switch (subType)
{
case "0":
#region 拼接预览图文json
end_content = wx_helper.CreateNewsJson2(media_id);
#endregion
wx_result=wx_helper.previewMsg(access_token, end_content, redirect_uri);
break;
case "1":
#region 获取所有openid集合
List<string> openidList = new List<string>();
openidList = wx_helper.GetOpenIDs(access_token, redirect_uri);
//ops = "";
//for (int i = 0; i < openidList.Count; i++)
//{
// ops += openidList[i] + ",";
//}
#endregion
#region 拼接图文json
end_content = wx_helper.CreateNewsJson(media_id, openidList);
#endregion
wx_result=wx_helper.Send(access_token, end_content, redirect_uri);
break;
}
//结果处理
if (_regex.IsMatch(wx_result))
wx_result = _regex.Match(wx_result).Value;
var result = JsonConvert.DeserializeObject<ErrorCode>(wx_result);
string errcode = result.ErrCode;
if (errcode != "0")
context.Response.Write("发送失败-错误码:" + errcode + "-消息:" + result.ErrMsg);
else
context.Response.Write("发送成功!");
}
public bool IsReusable
{
get
{
return false;
}
}
public class ErrorCode
{
[JsonProperty("errcode")]
public string ErrCode { get; set; }
[JsonProperty("errmsg")]
public string ErrMsg { get; set; }
[JsonProperty("msg_id")]
public string Msg_ID { get; set; }
[JsonProperty("msg_data_id")]
public string Msg_Data_ID { get; set; }
}
}
这里说一下需要注意的问题,也困扰了我很久的问题,在网上找了一天才找到答案所在,关于这个借口的问题网上的帮助实在太少了,所以就在这里发出一下做个记录,希望能够帮助到更多跟我一样的初学者。 PS,这些内容我也是在前人的基础上进行修改的,因为只有简单的一个功能,没有跟其他大神那样繁杂的框架,所以应该很容易看懂的。
问题一:刚开始我发送时,本以为发送成功了,但始终只有一张图片(也就是单图文消息,而且描述没有显示,点击阅读全文也没有内容),因为我是直接勾选多篇文章直接发送的,所以在文章拼接时肯定出了问题,但我找了很久都没有发现问题,因为比对过腾讯的技术文档,数据一样的,所以困扰了我一整天。
最后终于发现了原因,就是因为在文章拼接的时候content的内容一定不能有双引号!不然你就爽了!所以我在填写文章内容的时候,先用 content = content.Replace("\"", "‘");替换内容里的双引号,这样就没问题了~
问题二:发送成功之后,图文消息详情页只显示第一张图片,其他都没有读取,这个问题就是因为你没有将其他图片上传到腾讯获取他的url替换到你自己的图片地址中,这个技术文档上也有说,但一开始总让我看不懂,他只是说获取media_id的时候用,却特么没告诉我其他图片也要用到这个url!不过这个问题倒没花多少时间,主要是上面的问题。
问题三:文章的描述内容那里直接将html输出了,这个我的解决办法是,直接去除常用的标签,只留下文章内容,方法比较笨,但总算暂时解决了问题~我猜测那个文章的描述应该是不支持html的,跟content不同,好了,内容就说到这里,希望能帮助到大家