刚搞过一个工具,所以没怎么整理,凑合用吧。
public class WeiXinReport
{
string AccessToken { get; set; }
const string GetAccessTokenFormat = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={0}&corpsecret={1}";
const string UploadTempFileFormat = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={0}&type={1}";
const string SendMessageFormat = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={0}";
const int AccessTokenExpiresRange = -10;
void GetAccessToken()
{
AccessToken = AppConfigOperation.GetAppConfig("AccessToken");
string Expires = AppConfigOperation.GetAppConfig("AccessTokenExpires");
DateTime AccessTokenExpires = DateTime.Now.AddDays(-1);
if (!string.IsNullOrEmpty(Expires))
{
try {
AccessTokenExpires = Convert.ToDateTime(Expires);
}
catch{
}
}
//如果AccessToken为空,或者过期时间已经到了
if (string.IsNullOrEmpty(AccessToken) || AccessTokenExpires < DateTime.Now)
{
using (WebClient webClient = new WebClient())
{
string CorpId = AppConfigOperation.GetAppConfig("CorpId");
string Secret = AppConfigOperation.GetAppConfig("Secret");
Byte[] bytes = webClient.DownloadData(string.Format(GetAccessTokenFormat, CorpId, Secret));
string result = Encoding.GetEncoding("utf-8").GetString(bytes);
string[] temp = result.Split(',');
string[] tp = temp[0].Split(':');
AccessToken = tp[1].ToString().Replace('"', ' ').Trim().ToString();
AppConfigOperation.UpdateAppConfig("AccessToken", AccessToken);
//时间设置稍微靠前一些
AppConfigOperation.UpdateAppConfig("AccessTokenExpires", DateTime.Now.AddSeconds(AccessTokenExpiresRange).ToString("yyyy-MM-dd HH:mm:ss"));
}
}
}
UploadJsonResult UploadTempFile(string filename, byte[] files)
{
using (WebClient webClient = new WebClient())
{
string CorpId = AppConfigOperation.GetAppConfig("CorpId");
string Secret = AppConfigOperation.GetAppConfig("Secret");
string url = string.Format(UploadTempFileFormat, AccessToken, "image");
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");
//请求头部信息
StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"file\";filename=\"{0}\";filelength=\"{1}\"\r\nContent-Type:application/octet-stream\r\n\r\n", filename, files.Length));
byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());
//FileStream fs = new FileStream(file, 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(files, 0, files.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();
UploadJsonResult result = JsonConvert.DeserializeObject<UploadJsonResult>(content);
return result;
}
}
/// <summary>
/// {
/// "touser": "UserID1|UserID2|UserID3",
/// "toparty": " PartyID1 | PartyID2 ",
/// "totag": " TagID1 | TagID2 ",
/// "msgtype": "image",
/// "agentid": 1,
/// "image": {
/// "media_id": "MEDIA_ID"
/// },
/// "safe":"0"
///}
/// </summary>
public void SendImage(string filename, byte[] files, SettingItem item) {
GetAccessToken();
UploadJsonResult ujresult = UploadTempFile(filename, files);
using (WebClient webClient = new WebClient())
{
CorpSendImage csi = new CorpSendImage();
csi.toparty = item.WxPartyIds;
csi.msgtype = UploadMediaFileType.image.ToString();
csi.agentid = "2";
csi.SetMediaId(ujresult.media_id);
csi.safe = "0";
var data = JsonConvert.SerializeObject(csi);
Byte[] bytes = webClient.UploadData(string.Format(SendMessageFormat, AccessToken), System.Text.Encoding.UTF8.GetBytes ( data ));
string result = Encoding.UTF8.GetString(bytes);
//{
// "errcode": 0,
// "errmsg": "ok",
// "invaliduser": "UserID1",
// "invalidparty":"PartyID1",
// "invalidtag":"TagID1"
//}
string[] temp = result.Split(',');
string[] tp = temp[1].Split(':');
string errmsg = tp[1];
}
}
}
public class CorpSendImage : CorpSendBase {
public MediaInfo image {get;set;}
public class MediaInfo {
public string media_id { get; set; }
}
public CorpSendImage() {
image = new MediaInfo();
}
public void SetMediaId(string media_id) {
image.media_id = media_id;
}
}
/// <summary>
/// 上传多媒体文件的返回结果
/// </summary>
public class UploadJsonResult
{
/// <summary>
/// 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb,主要用于视频与音乐格式的缩略图)
/// </summary>
public UploadMediaFileType type { get; set; }
/// <summary>
/// 媒体文件上传后,获取时的唯一标识
/// </summary>
public string media_id { get; set; }
/// <summary>
/// 媒体文件上传时间戳
/// </summary>
public long created_at { get; set; }
}
///// 图片(image): 1M,支持JPG格式
/// 语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
/// 视频(video):10MB,支持MP4格式
/// 缩略图(thumb):64KB,支持JPG格式。
public enum UploadMediaFileType {
image,
voice,
video,
thumb
}
/// <summary>
/// 企业号发送消息的基础消息内容
/// </summary>
public class CorpSendBase
{
/// <summary>
/// UserID列表(消息接收者,多个接收者用‘|’分隔)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
/// </summary>
public string touser { get; set; }
/// <summary>
/// PartyID列表,多个接受者用‘|’分隔。当touser为@all时忽略本参数
/// </summary>
public string toparty { get; set; }
/// <summary>
/// TagID列表,多个接受者用‘|’分隔。当touser为@all时忽略本参数
/// </summary>
public string totag { get; set; }
/// <summary>
/// 消息类型
/// </summary>
public string msgtype { get; set; }
/// <summary>
/// 企业应用的id,整型。可在应用的设置页面查看
/// </summary>
public string agentid { get; set; }
/// <summary>
/// 表示是否是保密消息,0表示否,1表示是,默认0
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string safe { get; set; }
}
请问代码中的群发方式是上传到微信平台后获取资源id的方式进行群发的么?
@沐沐紫: 对,我们的应用场景就是定时群发报表图片。。
@waiter: 哦哦,好的,谢谢啦
看一下开发者文档,什么都会了。
就是开发者文档里面没有我想要的需求才提问的(ノへ ̄、),开发者文档里面调用群发接口是需要先上传资源到微信平台再获取id,然后才能群发的,现在我需要的是不上传资源到微信平台上的json格式,开发者文档里面的json格式只有通过资源id进行群发的( ̄△ ̄;)
你所说的是微信公众号推送的群发 还是公众号里你自己设置的菜单里的群发?
是推送的群发接口
@沐沐紫:好吧,我们这边实现了,不过也是像开发文档那样的方法
@挠头中: 像开发文档那样的话就需要上传数据了(ノへ ̄、),如果最后要是实在没法绕过上传的话,也只能用开发文档里面提供的了,或者我还有一种想法就是循环调用发送客服消息的接口( ̄△ ̄;)(可以调用50000次),最好还是能得到绕过上传的json格式(ノへ ̄、)
@沐沐紫: 先不说循环那个能不能实现,在理论上来说有5000次的限制就不太好,而且开发文档上写的,基本都是他们根据当时开发给我们用的接口写的,就是那么设计的,想绕过去也基本不太可能
@挠头中: 是5万的限制,目前来说还是够用的。可是我之前使用推送群发接口的时候还能绕过上传,使用的是如下的格式:
{
"touser": [
"oK0iOwaJvB-6JkhsUKksjnAV4vo4",
"oK0iOwXqyIGoaTTweGvPXG636cck",
"oK0iOwZ-6jKlMyr3RRrrFjxlAfgU"
],
"news": {
"articles": [
{
"title": "基础信息",
"description": "基础信息",
"picurl": "http://localhost:22937/WeiXinPlat/ThumbNail/20160419030546795.jpg",
"url": "http://localhost:22937/WeiXinPlat/WeiXin/Detail.aspx?Mark=1461049598024_0"
}
]
},
"msgtype": "news"
}
然后这几天测试的时候发现失败了,报错是4008消息格式错误,所以想问问最新的绕过上传的json格式是怎样的
@沐沐紫:不太了解,毕竟我们用的上传,不过推送上的url是不能传值的,Mark=1461049598024_0"这句话你确定好使?
@挠头中: 至少之前还是能用成功的(ノへ ̄、),看来目前只能改为上传的方式了。。。
@沐沐紫: 嗯,不按开发文档写,那不止当前碰到的问题,以后调用什么的都有可能影响