C#开发微信门户及应用(26)-公众号微信素材管理

微信公众号最新修改了素材的管理模式,提供了两类素材的管理:临时素材和永久素材的管理,原先的素材管理就是临时素材管理,永久素材可以永久保留在微信服务器上,微信素材可以在上传后,进行图片文件或者图文消息的发送,关注的公众号可以在素材有效期内查看相关的资源,对于永久素材,那就不会存在过期的问题,只是纯粹数量上限的限制。本文综合两方面进行介绍素材管理的各种接口和实现。

1、素材类型和功能点

关于素材的官方说明:
临时素材:
公众号经常有需要用到一些临时性的多媒体素材的场景,例如在使用接口特别是发送消息时,对多媒体文件、多媒体消息的获取和调用等操作,是通过media_id来进行的。素材管理接口对所有认证的订阅号和服务号开放。通过本接口,公众号可以新增临时素材(即上传临时多媒体文件)。对于临时素材,每个素材(media_id)会在开发者上传或粉丝发送到微信服务器3天后自动删除。素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式。
永久素材:
除了3天就会失效的临时素材外,开发者有时需要永久保存一些素材,届时就可以通过本接口新增永久素材。新增的永久素材也可以在公众平台官网素材管理模块中看到。永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000。

素材管理包含了下面截图的相关功能:


2、临时素材的管理接口定义和实现

我们定义一个IMediaApi接口,用来定义相关的接口处理。
1)上传临时文件
对于上传临时文件,官方的接口定义如下所示。
接口调用请求说明

http请求方式: POST/FORM,需使用httpshttps://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
调用示例(使用curl命令,用FORM表单方式上传一个多媒体文件):curl -F media=@test.jpg "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE"

对于上传临时文件的处理,我们可以定义它的接口如下所示。

/// <summary>
/// 上传的临时多媒体文件。格式和大小限制,如下:
/// 图片(image): 1M,支持JPG格式
/// 语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
/// 视频(video):10MB,支持MP4格式
/// 缩略图(thumb):64KB,支持JPG格式。
/// 媒体文件在后台保存时间为3天,即3天后media_id失效。
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="type">媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)</param>
/// <param name="file">form-data中媒体文件标识,有filename、filelength、content-type等信息</param>
/// <returns></returns>
UploadJsonResult UploadTempMedia(string accessToken, UploadMediaFileType type, string file);

根据官方接口的说明,我们需要上传一个文件,并指定它的类型TYPE就可以了。

具体代码如下所示。

public UploadJsonResult UploadTempMedia(string accessToken, UploadMediaFileType type, string file)
{
    string url = string.Format("http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token={0}&type={1}", accessToken, type.ToString());

    UploadJsonResult result = JsonHelper<UploadJsonResult>.PostFile(url, file);
    return result;
}

其中JsonHelper类的PostFile就是发送一个文件流,我们进一步可以看它的实现思路如下所示。

/// <summary>
/// 提交文件并解析返回的结果
/// </summary>
/// <param name="url">提交文件数据的链接地址</param>
/// <param name="file">文件地址</param>
/// <returns></returns>
public static T PostFile(string url, string file, NameValueCollection nvc = null)
{
    HttpHelper helper = new HttpHelper();
    string content = helper.PostStream(url, new string[] { file }, nvc);
    VerifyErrorCode(content);

    T result = JsonConvert.DeserializeObject<T>(content);
    return result;
}

上面代码主要就是通过POST一个文件流,并获得响应的结果字符串内容,然后我们分析其中是否有错误代码,如果没有,我们把字符串结果解析为对应的实体对象就可以了。

其中返回结果的实体类信息UploadJsonResult的类定义如下所示。

/// <summary>
/// 上传多媒体文件的返回结果
/// </summary>
public class UploadJsonResult : BaseJsonResult
{
    /// <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; }
}

这个接口的调用实例代码如下所示。

private void btnUpload_Click(object sender, EventArgs e)
{
    string file = FileDialogHelper.OpenImage(false);
    if (!string.IsNullOrEmpty(file))
    {
        IMediaApi mediaBLL = new MediaApi();
        UploadJsonResult result = mediaBLL.UploadTempMedia(token, UploadMediaFileType.image, file);
        if (result != null)
        {
            this.image_mediaId = result.media_id;
            Console.WriteLine("{0} {1}", result.media_id, result.created_at);
        }
        else
        {
            Console.WriteLine("上传文件失败");
        }
    }
}

2)获取临时素材文件
上传文件是上传一个文件流,并获得对应的返回结果,主要就是一个media_Id的内容;而获取素材文件则是一个逆过程,通过一个media_id的参数获取一个文件流保存到本地的过程。
获取临时文件接口的官方定义如下所示。
接口调用请求说明

http请求方式: GET,https调用
https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
请求示例(示例为通过curl命令获取多媒体文件)curl -I -G "https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID"

对于获取临时文件,我们定义的接口如下所示。

/// <summary>
/// 获取临时素材
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="mediaId">媒体文件ID</param>
/// <param name="stream"></param>
Stream GetTempMedia(string accessToken, string mediaId, ref string fileName);

我们获得文件流的同时,也返回一个文件名参数(不过一般情况下,我们获取不到文件名)。

它的实现代码如下所示,主要逻辑就是解析返回结果,获取返回的文件流。

/// <summary>
/// 获取临时素材
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="mediaId">媒体文件ID</param>
/// <param name="stream"></param>
public Stream GetTempMedia(string accessToken, string mediaId, ref string fileName)
{
    string url = string.Format("http://file.api.weixin.qq.com/cgi-bin/media/get?access_token={0}&media_id={1}", accessToken, mediaId);

    HttpHelper helper = new HttpHelper();
    Stream stream = helper.GetStream(url, ref fileName, null);
    return stream;
}

获取素材文件的实例代码如下所示。

private void btnDownload_Click(object sender, EventArgs e)
{
    if (!string.IsNullOrEmpty(image_mediaId))
    {
        IMediaApi mediaBLL = new MediaApi();

        string fileName = "";
        Stream stream = mediaBLL.GetTempMedia(token, image_mediaId, ref fileName);
        if (stream != null)
        {
            string filePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, fileName);
            using (var fileStream = File.Create(filePath))
            {
                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    fileStream.Write(buffer, 0, bytesRead);
                }
                fileStream.Flush();
            }
            stream.Close();
        }
        Console.WriteLine("下载文件:" + (File.Exists(fileName) ? "成功" : "失败"));
    }
}

3、永久素材的管理接口定义和实现

根据官方接口的描述,我们可以把新增永久素材接口定义为三种:新增图文素材、其他类型永久素材和视频素材三种接口。
1)新增永久图文素材
接口调用请求说明

http请求方式: POST
https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN

调用示例

{
  "articles": [{
       "title": TITLE,
       "thumb_media_id": THUMB_MEDIA_ID,
       "author": AUTHOR,
       "digest": DIGEST,
       "show_cover_pic": SHOW_COVER_PIC(0 / 1),
       "content": CONTENT,
       "content_source_url": CONTENT_SOURCE_URL
    },
    //若新增的是多图文素材,则此处应还有几段articles结构
 ]
}

2)新增其他类型永久素材
接口调用请求说明
通过POST表单来调用接口,表单id为media,包含需要上传的素材内容,有filename、filelength、content-type等信息。请注意:图片素材将进入公众平台官网素材管理模块中的默认分组。

http请求方式: POST
http://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN
调用示例(使用curl命令,用FORM表单方式新增一个其他类型的永久素材):curl -F media=@test.jpg "http://file.api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN"

3)新增永久视频素材
在上传视频素材时需要POST另一个表单,id为description,包含素材的描述信息,内容格式为JSON,格式如下:

{ "title":VIDEO_TITLE, "introduction":INTRODUCTION}

新增永久视频素材的调用示例:

curl "http://file.api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN" -F media=@media.file -F description='{"title":VIDEO_TITLE, "introduction":INTRODUCTION}'

根据上面的说明,我们定义新增永久图文素材的接口代码如下所示。

/// <summary>
/// 新增永久图文素材
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="newsList">图文消息组</param>
/// <returns></returns>
MaterialResult UploadMaterialNews(string accessToken, List<NewsUploadJson> newsList);

定义新增其他永久素材接口如下:

/// <summary>
/// 新增其他类型永久素材(图片(image)、语音(voice)和缩略图(thumb))
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="type">媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)</param>
/// <param name="file">form-data中媒体文件标识,有filename、filelength、content-type等信息</param>
/// <returns></returns>
MaterialResult UploadMaterialMedia(string accessToken, UploadMediaFileType type, string file);

定义新增视频永久素材接口如下所示:

/// <summary>
/// 在上传视频素材时需要POST另一个表单,id为description,包含素材的描述信息,内容格式为JSON.
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="file">form-data中媒体文件标识,有filename、filelength、content-type等信息</param>
/// <param name="title">视频标题</param>
/// <param name="introduction">视频描述</param>
/// <returns></returns>
MaterialResult UploadMaterialVideo(string accessToken, string file, string title, string introduction);

这几个接口都没有太多难度,不过在微信接口讨论组里面,很多人对于上传永久素材的操作总是不成功,觉得可能是微信API本身的问题,其实不然,这个接口我还是测试通过了,并且在服务器上看到对应的素材信息,具体我们来看看上传其他类型素材的接口实现代码。

/// <summary>
/// 新增其他类型永久素材(图片(image)、语音(voice)和缩略图(thumb))
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="type">媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)</param>
/// <param name="file">form-data中媒体文件标识,有filename、filelength、content-type等信息</param>
/// <returns></returns>
public MaterialResult UploadMaterialMedia(string accessToken, UploadMediaFileType type, string file)
{
    string url = string.Format("http://api.weixin.qq.com/cgi-bin/material/add_material?access_token={0}&type={1}", accessToken, type.ToString());

    MaterialResult result = JsonHelper<MaterialResult>.PostFile(url, file);
    return result;
}

注意这个URL是http而不是https,有点特殊。
另外,我们在使用POST文件流的时候,HttpWebRequest对象的内容一定要设置好,主要是需要和微信定义的media这个保持一直才可以。如下是HttpHelper 辅助类里面的PostStream的部分代码,供参考。



永久素材上传后的结果可以在微信公众号后台进行查看到,具体界面如下所示。



对于永久素材的接口,我们还可以根据微信API的要求,完善永久素材的更新、删除、获取素材,以及获取素材总数、获取图文素材列表等功能,由于大多数操作类似,不需要一一列出,希望再次抛砖引玉,使得大家能够更好了解、利用好微信公众号的素材管理接口,从而实现我们更加丰富的数据管理。
如果对这个《C#开发微信门户及应用》系列感兴趣,可以关注我的其他文章
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容