C#微信公众平台账号开发,从零到整,步骤详细。
想到微信的火热,想到其他公司开发手游,如雷电,酷跑类的,都不是很火,但是弱智的“打飞机”和“天天酷跑”却是那么火热。于是乎,想做个微信营销的软件。
首先想到的是手机连电脑wifi,用抓包工具抓微信的包,然后分析。奋斗2星期,基本一无所获,得到一个结论,腾讯的东西真的不好破解。就算千辛万苦破解一个,只要一更新,前面的努力全部白费。
于是只能老老实实的去用官方提供的接口。也就是微信公众平台。
C#开发公众平台,需要在官网mp.weixin.qq.com注册一个账号,审核通过后,就可以开始了。
第一步
点开高级功能,关闭弱智的编辑模式,打开高级的开发模式。
第二部
进入开发模式,填写接口配置信息。这里也是刚开始困扰我的地方。URL就是服务器地址,刚开始想用自己电脑做服务器,让微信服务器访问,但是我是在内网里,路由器权限也没有,无法端口映射到自己电脑,所以只好网上买了一个服务器空间,一年不到200的那种,空间只有100M,数据库50M。但是够用了。
Token是验证用的令牌,随便填一个字符串,但是要记住。程序里也要用这个Token字符串来验证是否微信服务器发来请求。不然别人可以模拟请求,伪造信息。
填好后,还不能通过验证,因为你没写代码。微信服务器访问你的时候,无法获取结果,自然不能通过验证。
服务器地址填写后,微信服务器会提交get请求,访问你的URL并且带上4个参数。
1,signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
2,timestamp 时间戳
3,nonce 随机数
4,echostr 随机字符串
他的signature加密方式为
1. 将token、timestamp、nonce三个参数进行字典序排序2. 将三个参数字符串拼接成一个字符串进行sha1加密3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
通过这些介绍,我们就可以开始在默认页面那里:比如Default.aspx.cs写page_load事件,获取4个参数,按加密算法,获得signature结果,再对比微信发过来的signature,相同,原样输出echostr。这样,就能通过微信服务器验证。以后每次收到消息后,微信就会发送消息到服务器,服务器经过处理后,就可以回复一定的内容给发送过来的那个人消息。
下面详细介绍如何通过代码,来通过刚才的url接口配置。
ASP.NET DEFAULT.ASPX页面的page_load事件里。
首先获取四个参数。
string signature = Request["signature"];
string timestamp = Request["timestamp"];
string nonce = Request["nonce"];
string echostr = Request["echostr"];
按照前面说的加密过程,获得加密结果。
var arr = new[] { token, timestamp, nonce }.OrderBy(z => z).ToArray();
var arrString = string.Join("", arr);
var sha1 = System.Security.Cryptography.SHA1.Create();
var sha1Arr = sha1.ComputeHash(Encoding.UTF8.GetBytes(arrString));
StringBuilder enText = new StringBuilder();
foreach (var b in sha1Arr)
{
enText.AppendFormat("{0:x2}", b);
}
对比,
if( enText.ToString() == signature )
{
Response.Output.Write(echostr);
}
这样,就完成了简单的一步验证。微信就能通过校验,以后所有信息都会发到你填写的这个url服务器上去了。
校验完后,以后的消息都是post请求你的服务器。请求里包含一段xml数据。xml数据里包含了用户发过来的数据,和这个用户的openid.你获取了这些信息后,就可以发送自动回复的内容,发给这个openid的用户。
只要某个用户发过来一个消息,微信服务器就会发送一个post请求到你填写的服务器url上,然后每次都会触发page_load事件。接收用户信息,和处理要回复的内容,都在page_load里。
if (Request.HttpMethod == "POST")
{
string weixin = "";//获取xml数据
weixin = PostInput();//自定义方法,获取xml数据
if (!string.IsNullOrEmpty(weixin))
{
ResponseMsg(weixin);//根据获取的内容,自动回复一定的内容。
}
}
这样,我们的微信功能就完成了。教程到此结束。。。。。。是不可能的。
先讲postinput方法,
private string PostInput()/// 获取post请求数据
{
Stream s = System.Web.HttpContext.Current.Request.InputStream;
byte[] b = new byte[s.Length];
s.Read(b, 0, (int)s.Length);
return Encoding.UTF8.GetString(b);
}
四行代码,就获取了xml数据。asp.net很少用,所以不知道有没有更好的方法。
然后就是最重要的ResponseMsg方法了。上源码。
private void ResponseMsg(string weixin)// 服务器响应微信请求
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(weixin);//读取xml字符串
XmlElement root = doc.DocumentElement;
XmlNode MsgType = root.SelectSingleNode("MsgType");//获取收到的消息类型。文本(text),图片(image),语音等。
string messageType = MsgType.InnerText;
try
{
switch (messageType)
{
case "text":
WriteContent(ResponseText.GetResponseMessage(weixin));
break;
case "image":
break;
case "voice":
break;
case "vedio":
break;
case "location":
break;
case "link":
break;
default:
break;
}
Response.End();
}
catch (Exception)
{
}
}
其实前面讲的都不重要。重要的是分支语句,
switch (messageType)
{
case "text":
Response.Output.Write(ResponseText.GetResponseMessage(weixin));
break;
就是如果用户发过来的是文本请求,调用ResponseText.GetResponseMessage()方法。
这个方法里,就是根据具体的文本关键字,经过处理,设置自动回复的内容。
教程其实快结束了。
只有一个自动回复的方法没讲。直接贴源码了。在代码里注释着讲。
public static string GetResponseMessage(string weixin)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(weixin);//读取xml字符串
XmlElement root = doc.DocumentElement;
string message = "对不起,无法识别您发送的命令。请发送“帮助”来获取已经实现的功能。";
string resxml = "";
var model = new
{
ToUserName = root.SelectSingleNode("ToUserName").InnerText,//本公众账号
FromUserName = root.SelectSingleNode("FromUserName").InnerText,//用户
CreateTime = root.SelectSingleNode("CreateTime").InnerText,//创建时间
Content = root.SelectSingleNode("Content").InnerText,//消息内容
MsgId = root.SelectSingleNode("MsgId").InnerText//消息ID,64位整型
};//获取xml数据里各个结点的内容。
MySQL sql = new MySQL();//这里是我记录用户发送的内容到数据库的,不写也没事。
string str_insert = "insert into ChatRecord values('" + model.FromUserName + "','" + model.Content + "','" + DateTime.Now.ToString().Substring(2) + "')";
if (sql.ExecuteCommand(str_insert) < 0)//插入失败,记录日志
{
StreamWriter sw = new StreamWriter(HttpContext.Current.Request.PhysicalApplicationPath + "/Log/log.txt", true, Encoding.UTF8);
sw.WriteLine(DateTime.Now.ToString().Substring(2) + ": 插入ChatRecord表失败[" + model.FromUserName + "----" + model.Content + "]");
sw.Close();
}
//这里就是关键的设置自动回复的内容。回复的格式,要按照官方提供的来填写,也是一段xml数据。具体格式,注册了微信公众平台账号后,看API文档就有了。这里稍微简单的介绍一下。ToUserName,就是刚才发过来的那个用户的openid,fromusername一般就是我们的公众账号。CREATETIME就是一个整型时间,unix格式的,转成距离1970年1月1日0点0分有多少秒就行了。MsgType就是回复的类型。你可以回复图片,新闻链接,语音,视频,音乐等。这里我们是文本,所以是text。content就是自动回复的内容。funcflag不管,填写0.
resxml += "<xml><ToUserName><![CDATA[" + model.FromUserName + "]]></ToUserName><FromUserName><![CDATA[";
resxml += model.ToUserName + "]]></FromUserName><CreateTime>" + MyAPI.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";
////////////////////////////////////已实现功能////////////////////已实现功能//////////////////////////////////////////////
//这里如果对方发过来“帮助”,我们设置常量文本(暂时这么叫。。),自动回复给用户。
if (model.Content == "帮助")
{
message = "目前实现功能有:" + CRLF + "1,帮助:获取发送命令菜单" + CRLF;
message += "2,翻译功能。只要发送“翻译”+空格+需要翻译的内容,即可实现翻译功能。" + CRLF;
message += "3,天气预报。发送 “天气”+空格+城市名 ,即可查询该城市6天内天气预报。如发送“天气 北京”。" + CRLF;
}
//这里。如果是“翻译+空格+词语”,我们就调用百度翻译API,获取翻译结果后,再发给用户。关于这些内容,就不在教程的范围里了。种类太多,毕竟你有可能要操作数据库,请求别的网站,等等各种各种的功能。发送“笑话”,“鬼故事”等等,查数据库也可以,请求别的网站也可以。这里实现方法就不在这个地方讲拉。我也不是很清楚。查了很多资料,才实现了翻译。
else if (model.Content.Trim().StartsWith("翻译 "))
{
string str = model.Content.Trim().Substring(3);
MyAPI api = new MyAPI();
MyJSON json = new MyJSON();
BaiDuFanYiResult obj = json.FromJson<BaiDuFanYiResult>(api.BaiduTanslate(str, "auto", "auto"));
message = obj.trans_result[0].dst;
}
//这里是天气预报。用户发“天气+空格+城市”,
else if (model.Content.Trim().StartsWith("天气 "))
{
string str = model.Content.Trim().Substring(3);
MyAPI api = new MyAPI();
MyJSON json = new MyJSON();
string strjson = api.WeatherReport(str);
if (strjson.Length < 10)
{
message = "对不起,找不到[" + str + "]的天气,请正确输入城市名字,如果城市确实存在,请发送“BUG 城市名”提交BUG";
resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + message + "]]></Content><FuncFlag>0</FuncFlag></xml>";
return resxml;
}
RootObject report = json.FromJson<RootObject>(strjson);
message = "今天: " + report.weatherinfo.temp1 + ", " + report.weatherinfo.weather1 + CRLF;
message += "明天开始接下来5天天气预报如下:" + CRLF;
message += report.weatherinfo.temp2 + ", " + report.weatherinfo.weather2 + CRLF;
message += report.weatherinfo.temp3 + ", " + report.weatherinfo.weather3 + CRLF;
message += report.weatherinfo.temp4 + ", " + report.weatherinfo.weather4 + CRLF;
message += report.weatherinfo.temp5 + ", " + report.weatherinfo.weather5 + CRLF;
message += report.weatherinfo.temp6 + ", " + report.weatherinfo.weather6 + CRLF;
message += report.weatherinfo.index_d;
}
else if (model.Content.Trim().StartsWith(""))
{
}
//这里本来是想写个在线的纯文字(可以带图片)的在线多人RPG游戏。。。暂时还没开始。。个人能力问题。
else if (model.Content.Trim().StartsWith("游戏 "))
{
string gamename = model.Content.Trim().Substring(3);
message = Game.GetBackground(gamename);
}
else
{
message = "对不起,无法识别您发送的命令。请发送“帮助”来获取已经实现的功能。";
}
resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + message + "]]></Content><FuncFlag>0</FuncFlag></xml>";
return resxml;//回复内容有了哦。基本实现了
}
还有其他更多的接口,比如发过来图片,语音,音乐,视频等等,还可以获取用户信息,用户地理位置,等等。这里应该又可以想出不少的功能。