サービス アカウントの説明: 企業や組織に、より強力なビジネス サービスとユーザー管理機能を提供し、企業が新しいパブリック アカウント サービス プラットフォームを迅速に実装できるように支援します。
.NETSDK: Loogn.WeiXinSDK (net2.0 ソース コード、次のコードはおおよそのものであり、あまり正確ではありません。ソース コードは自分でダウンロードしてください)
私はまだ NOKIA-C5 を使用しており、WeChat を使用したことがないので、 WeChat についてまったく理解していません。あなたにはもっとたくさんのことがありますが、会社にはニーズがあるので、私はしっかりとインターフェイスのドキュメントを読む必要があります。
読んでみて、非常に便利な機能は、ユーザーが公開アカウントにメッセージを送信すると、ユーザーが送信した内容に基づいてプログラムが自動的にユーザーに返信できることです。運送状番号を物流会社の公開アカウントに送信します。
相手はこの運送状番号の物流詳細を自動的に返信します。これは非常にクールです。説明の便宜上、最初に適用された公開アカウント情報を与えます:
以下の図は、上記のロジスティクスを表示する詳細なメッセージプロセスを示しています (点線内の数字はプロセスの順序を示します):
WeChat から送信される URL は、主に 2 種類のメッセージです。
1 つ目は、上記のユーザーが送信した運送状番号などのユーザーの一般的なメッセージです
2 つ目は、ユーザーの行動 (つまり、イベント)ユーザーがあなたの公開アカウントをフォローした、公開アカウントの QR コードをスキャンした、カスタマイズされたメニューをクリックしたなど)。
URL は、受信した メッセージ タイプとコンテンツ に基づいて応答し、上記で返された物流の詳細などの強力なビジネス サービスを実現できます。すべてのメッセージは XML 形式で配信され、SDK は XML を .NET オブジェクトに変換して、ビジネス ロジックの作成を容易にします。メッセージのフレームワーク クラス図は次のように表されます (クリックすると、サブクラスを含む全体図が表示されます):
最初にメッセージの基本クラスがあり、次に受信メッセージ (RecEventBaseMsg) と応答メッセージ (ReplyBaseMsg) があります。上で説明したように、受信メッセージは、一般メッセージ (RecBaseMsg) とイベント メッセージ (EventBaseMsg) の 2 つのカテゴリに分類されます。受信メッセージのタイプは列挙によって表すことができます。他のタイプは言及されていません。MsgType が指定されている場合は、 Event、メッセージは EventBaseMsg のサブクラスです。すべての EventBaseMsg サブクラスの MsgType は Event です。したがって、EventBaseMsg タイプには、さまざまなイベントを区別するための EventType もあります。そのイベントのタイプは ではないことがわかります。 QR コードのスキャン イベントは、ユーザーがフォローしている場合とフォローしていない場合の 2 つの状況に分けられます。ユーザーがイベントをフォローしている場合、EventType はスキャンです。注目していないため、EventType は購読であり、ユーザーがフォローしたイベントの EventType も購読であるため、別の MyEventType が SDK に追加されました:
これで、返信するための SDK の呼び出しプロセスは基本的に明確になりました。メッセージは次のとおりです:
using System.Web;using Loogn.WeiXinSDK;using Loogn.WeiXinSDK.Message;namespace WebTest { /// <summary> /// 微信->服务器配置URL /// </summary> public class WeiXinAPI : IHttpHandler { static string Token = "Token";//这里是Token不是Access_Token public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; var signature = context.Request["signature"]; var timestamp = context.Request["timestamp"]; var nonce = context.Request["nonce"]; if (WeiXin.CheckSignature(signature, timestamp, nonce, Token))//验证是微信给你发的消息 { //根据注册的消息、事件处理程序回复, //如果得到没用注册的消息或事件,会返回ReplyEmptyMsg.Instance,即GetXML()为string.Empty,符合微信的要求 var replyMsg = WeiXin.ReplyMsg(); var xml = replyMsg.GetXML(); //WriteLog(xml); //这里可以查看回复的XML消息 context.Response.Write(xml); } else { context.Response.Write("fuck you!"); } } static WeiXinAPI() { WeiXin.ConfigGlobalCredential("appid", "appSecret"); //注册一个消息处理程序,当用户发"ABC",你回复“你说:ABC”; WeiXin.RegisterMsgHandler<RecTextMsg>((msg) => { return new ReplyTextMsg { Content = "你说:" + msg.Content //FromUserName = msg.ToUserName, 默认就是这样,不用设置! //ToUserName = msg.FromUserName, 默认就是这样,不用设置! //CreateTime = DateTime.Now.Ticks 默认就是这样,不用设置! }; }); //注册一个用户关注的事件处理程序,当用户关注你的公众账号时,你回复“Hello!” WeiXin.RegisterEventHandler<EventAttendMsg>((msg) => { return new ReplyTextMsg { Content = "Hello !" }; }); //还可以继续注册你感兴趣的消息、事件处理程序 } public bool IsReusable { get { return false; } } } }
SDK には (OAuth2.0 Web 認証) を除くすべてのインターフェイスのカプセル化が含まれています。クラス名とメソッド名は非常に明白なので、ここでは 1 つずつ説明しません。 DLL をダウンロードして自分でテストできます。これは有料の認定済みインターフェイス図です:
次に、いくつかの実装について説明します:
1. 資格情報 (access_token) の有効期限
「Access_token はグローバルに有効です」パブリックアカウントは、各インターフェースを呼び出す際に access_token を使用する必要があります。通常の状況では、access_token は 7200 秒間有効です。今回取得した access_token は無効になります。 AppID と AppSecret はこのインターフェイスを呼び出して access_token を取得します。AppID と AppSecret は開発モードで取得できます (開発者である必要があり、アカウントに異常がないことが必要です)。キャッシュを使用する (毎回使用して取得するのは不可能です!)、キャッシュ コードは非常に単純です。主にこのケースでは、キャッシュを使用することを考える必要があります。以下は
不完全なコードです:
access_token { ; expires_in { ; Dictionary<, Credential> creds = Dictionary<, Credential> TokenUrl = Credential GetCredential( appId, = (creds.TryGetValue(appId, (cred.add_time.AddSeconds(cred.expires_in - ) <= json = Util.HttpGet2(= Util.JsonTo<Credential>
2. エラー コード情報 前述したように、WeChat エラー コードは次のような json 形式で返されるため、認証情報を取得するコードは不完全です。エラーコードの形式は、通常返されるデータ形式とはまったく異なります。まず、呼び出すエラーコードのモデルクラスを定義します。リクエストが成功したときの {"errcode":0,"errmsg":"ok"} 状況も含まれているため、ここに ReturnCode を記述します:
{"errcode":40013,"errmsg":"invalid appid"}
エラー コードを含むリターン メッセージ クラスを定義する場合、二次元の Code インターフェイスを作成するなど、ReturnCode タイプの属性を含めることができます: errcode { ; errmsg { ; + errcode + + errmsg +
public class QRCodeTicket
{ public string ticket { get; set; } public int expire_seconds { get; set; } public ReturnCode error { get; set; }
}
var qrcode = WeiXin.CreateQRCode(true, 23); if (qrcode.error == null) { //返回错误,可以用qrcode.error查看错误消息 } else { //返回正确,可以操作qrcode.ticket }
三、反序列化
微信接口返回的json有时候对我们映射到对象并不太直接(json格式太灵活了!),比如创建分组成功后返回的json:
{ "group": { "id": 107, "name": "test" } }
如果想直接用json通过反序列化得到对象,那么这个对象的类的定义有可能会是这样:
public class GroupInfo { public Group group { get; set; } public class Group { public int id { get; set; } public string name { get; set; } } }
访问的时候也会是gp.group.name,所以我说不太直接,我们想要的类的定义肯定是只有上面那个子类的样子:
public class GroupInfo { public int id { get; set; } public string name { get; set; } }
如果微信接口返回的是这样:
{ "id": 107, "name": "test" }
就再好不过了,但人家的代码,我们修改不了,我们只有自己想办法.
1,要简单类,2不手动分析json(如正则),3,不想多定义一个类,你有想到很好的方法吗?如果有可以回复给我,而我选择用字典来做中间转换。
因为基本所有的json格式都可以反序列化为字典(嵌套字典,嵌套字典集合等),比如上面微信返回的json就可以用以下的类型来表示:
Dictionary<string, Dictionary<string, object>>
json--->dict--->GroupInfo
var dict = Util.JsonTo(json);var gi = new GroupInfo();var gpdict = dict["group"]; gi.id = Convert.ToInt32(gpdict["id"]); gi.name = gpdict["name"].ToString();
四、消息处理的优化
"万物简单为美",我就是一个非常非常喜欢简单的程序员。还记得最开始的那个消息(事件属于消息,这里统称为消息)处理吧,我感觉是很简单的,需要处理哪个消息就注册哪个消息的处理程序。但一开始的时候不是这样的,开始的时候要手动判断消息类型,就像:
using System.Web;using Loogn.WeiXinSDK;using Loogn.WeiXinSDK.Message;namespace WebTest { /// <summary> /// 微信->服务器配置URL /// </summary> public class WeiXinAPI : IHttpHandler { static string Token = "Token";//这里是Token不是Access_Token public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; var signature = context.Request["signature"]; var timestamp = context.Request["timestamp"]; var nonce = context.Request["nonce"]; if (WeiXin.CheckSignature(signature, timestamp, nonce, Token))//验证是微信给你发的消息 { var replyMsg = WeiXin.ReplyMsg((recEvtMsg) => { switch (recEvtMsg.MsgType) { case MsgType.text: { var msg = recEvtMsg as RecTextMsg; //这里要转型,麻烦 return new ReplyTextMsg { Content = "你说:" + msg.Content }; } case MsgType.Event: { var evtMsg = recEvtMsg as EventBaseMsg;//这里要转型到事件消息的基本,麻烦 switch (evtMsg.MyEventType) { case MyEventType.Attend: var msg = evtMsg as EventAttendMsg;//这个例子不需要这行代码,但其他要用消息内容还是要转型,麻烦 return new ReplyTextMsg { Content = "Hello !" }; default: break; } break; } default: break; } return ReplyEmptyMsg.Instance; //嵌套switch,而且每个case都有好几个,这也不优雅 }); var xml = replyMsg.GetXML(); //WriteLog(xml); //这里可以查看回复的XML消息 context.Response.Write(xml); } else { context.Response.Write("fuck you!"); } } public bool IsReusable { get { return false; } } } }
做优化的时候,先是试着看能不能在MsgType和MyEventType上做文章,比如注册时传入MsgType和处理程序(lamba)两个参数:
public static void RegisterMsgHandler(MsgType type, Func<RecEventBaseMsg, ReplyBaseMsg> handler) { //add handler}
这样的确是可以行的通的,但是在调用SDK注册的时候还是要手动转换类型:
WeiXin.RegisterMsgHandler(MsgType.text, (recEvtMsg) => msg = recEvtMsg ReplyTextMsg { Content = +
那么能不能每个子类型写一个呢?
public static void RegisterMsgHandler(MsgType type, Func<RecTextMsg, ReplyBaseMsg> handler) { //add handler } public static void RegisterMsgHandler(MsgType type, Func<RecImageMsg, ReplyBaseMsg> handler) { //add handler } //.............
定义是可以的,来看看调用:
//可以RegisterMsgHandler(MsgType.text, new Func<RecTextMsg, ReplyBaseMsg>((msg) =>{ return new ReplyTextMsg { Content = "你说:" + msg.Content }; }));//可以RegisterMsgHandler(MsgType.text, new Func<RecImageMsg, ReplyBaseMsg>((msg) =>{ return new ReplyTextMsg { Content = "你发的图片:" + msg.PicUrl }; }));//可以,注意这里msg的智能提示是RecTextMsg类型RegisterMsgHandler(MsgType.text, (msg) =>{ return new ReplyTextMsg { Content = "你说:" +msg.Content}; });//可以,注意这里msg的智能提示还是RecTextMsg类型,但用了类型推断,运行时可以确定是RecImageMsg,所以可以RegisterMsgHandler(MsgType.text, (msg) =>{ return new ReplyTextMsg { Content = "你发的图片:" + msg.PicUrl }; });//不可以,注意这里msg的智能提示还是RecTextMsg类型,但lamba body里没有用msg的特定子类的属性,类型推断不了,所以调用不明RegisterMsgHandler(MsgType.text, (msg) =>{ return new ReplyTextMsg { Content = "你发了个消息" }; });
从上面调用可知,想用这种方法调用,就不能随意的用lamba表达式,我所不欲也!最后,终于用泛型搞定了
public static void RegisterMsgHandler<TMsg>(Func<TMsg, ReplyBaseMsg> handler) where TMsg : RecBaseMsg { var type = typeof(TMsg); var key = string.Empty; if (type == typeof(RecTextMsg)) { key = MsgType.text.ToString(); } else if (type == typeof(RecImageMsg)) { key = MsgType.image.ToString(); } else if (type == typeof(RecLinkMsg)) { key = MsgType.link.ToString(); } else if (type == typeof(RecLocationMsg)) { key = MsgType.location.ToString(); } else if (type == typeof(RecVideoMsg)) { key = MsgType.video.ToString(); } else if (type == typeof(RecVoiceMsg)) { key = MsgType.voice.ToString(); } else { return; } m_msgHandlers[key] = (Func<RecEventBaseMsg, ReplyBaseMsg>)handler; }
经过这样的变换,我们才可以像开始那样用简洁的lamba表达式注册。
以上がWeChatパブリックプラットフォームSDKプロセスの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。