/*---------------------------------------------------------------- Copyright (C) 2018 Senparc 文件名:CustomMessageHandler.cs 文件功能描述:微信公众号自定义MessageHandler 创建标识:Senparc - 20150312 修改标识:Senparc - 20171027 修改描述:v14.8.3 添加OnUnknownTypeRequest()方法Demo ----------------------------------------------------------------*/ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using Senparc.Weixin.MP.Entities; using Senparc.Weixin.MP.Entities.Request; using Senparc.Weixin.MP.MessageHandlers; using Senparc.Weixin.MP.AdvancedAPIs; using System.Threading.Tasks; using Senparc.NeuChar.Entities.Request; using Senparc.NeuChar.Helpers; using Senparc.NeuChar.Entities; using Senparc.Weixin; using Senparc.Weixin.MP; using BotSharp.Platform.Models.AiRequest; using BotSharp.Platform.Abstractions; using BotSharp.Platform.Dialogflow.Models; using Microsoft.Extensions.Configuration; #if NET45 using System.Web; using System.Configuration; using System.Web.Configuration; using Senparc.Weixin.MP.Sample.CommonService.Utilities; #else using Microsoft.AspNetCore.Http; #endif namespace BotSharp.Channel.Weixin.Models { /// /// 自定义MessageHandler /// 把MessageHandler作为基类,重写对应请求的处理方法 /// public partial class CustomMessageHandler : MessageHandler { /* * 重要提示:v1.5起,MessageHandler提供了一个DefaultResponseMessage的抽象方法, * DefaultResponseMessage必须在子类中重写,用于返回没有处理过的消息类型(也可以用于默认消息,如帮助信息等); * 其中所有原OnXX的抽象方法已经都改为虚方法,可以不必每个都重写。若不重写,默认返回DefaultResponseMessage方法中的结果。 */ #if !DEBUG || NETSTANDARD1_6 || NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 string agentUrl = "http://localhost:12222/App/Weixin/4"; string agentToken = "27C455F496044A87"; string wiweihiKey = "CNadjJuWzyX5bz5Gn+/XoyqiqMa5DjXQ"; #else //下面的Url和Token可以用其他平台的消息,或者到www.weiweihi.com注册微信用户,将自动在“微信营销工具”下得到 private string agentUrl = Config.SenparcWeixinSetting.AgentUrl;//这里使用了www.weiweihi.com微信自动托管平台 private string agentToken = Config.SenparcWeixinSetting.AgentToken;//Token private string wiweihiKey = Config.SenparcWeixinSetting.SenparcWechatAgentKey;//WeiweihiKey专门用于对接www.Weiweihi.com平台,获取方式见:http://www.weiweihi.com/ApiDocuments/Item/25#51 #endif #if NET45 private string appId = Config.SenparcWeixinSetting.WeixinAppId; private string appSecret = Config.SenparcWeixinSetting.WeixinAppSecret; #else private string appId = "appId"; private string appSecret = "appSecret"; #endif /// /// 模板消息集合(Key:checkCode,Value:OpenId) /// public static Dictionary TemplateMessageCollection = new Dictionary(); private IPlatformBuilder nluPlatform = null; private readonly IConfiguration config; public CustomMessageHandler(IPlatformBuilder nluPlatform, IConfiguration configuration, Stream inputStream, PostModel postModel, int maxRecordCount = 0) : base(inputStream, postModel, maxRecordCount) { this.nluPlatform = nluPlatform; this.config = configuration; //这里设置仅用于测试,实际开发可以在外部更全局的地方设置, //比如MessageHandler.GlobalGlobalMessageContext.ExpireMinutes = 3。 GlobalMessageContext.ExpireMinutes = 3; if (!string.IsNullOrEmpty(postModel.AppId)) { appId = postModel.AppId;//通过第三方开放平台发送过来的请求 } //在指定条件下,不使用消息去重 base.OmitRepeatedMessageFunc = requestMessage => { var textRequestMessage = requestMessage as RequestMessageText; if (textRequestMessage != null && textRequestMessage.Content == "容错") { return false; } return true; }; } public override void OnExecuting() { //测试MessageContext.StorageData if (CurrentMessageContext.StorageData == null) { CurrentMessageContext.StorageData = 0; } base.OnExecuting(); } public override void OnExecuted() { base.OnExecuted(); CurrentMessageContext.StorageData = ((int)CurrentMessageContext.StorageData) + 1; } /// /// 处理文字请求 /// /// public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage) { var defaultResponseMessage = base.CreateResponseMessage(); var requestHandler = requestMessage.StartHandler() .Keyword("BotSharp",() => { var result = new StringBuilder(); result.AppendFormat("{0}", "你好!欢迎使用BotSharp NLU服务,BotSharp通过强大的自然语言理解技术让你更轻松的处理智能回复。"); defaultResponseMessage.Content = result.ToString(); return defaultResponseMessage; }) .Keyword("再见", () => { var result = new StringBuilder(); result.AppendFormat("{0}", "谢谢使用,再见!"); defaultResponseMessage.Content = result.ToString(); return defaultResponseMessage; }) .Default(() => { var result = new StringBuilder(); // send text to BotSharp platform emulator var aIResponse = nluPlatform.TextRequest(new AiRequest { Text = requestMessage.Content, AgentId = config.GetValue("weixinChannel:agentId"), SessionId = requestMessage.FromUserName }); result.AppendFormat("{0}", aIResponse.Result.Fulfillment.Speech); defaultResponseMessage.Content = result.ToString(); return defaultResponseMessage; }); return requestHandler.GetResponseMessage() as IResponseMessageBase; } /// /// 处理位置请求 /// /// /// public override IResponseMessageBase OnLocationRequest(RequestMessageLocation requestMessage) { var locationService = new LocationService(); var responseMessage = locationService.GetResponseMessage(requestMessage as RequestMessageLocation); return responseMessage; } public override IResponseMessageBase OnShortVideoRequest(RequestMessageShortVideo requestMessage) { var responseMessage = this.CreateResponseMessage(); responseMessage.Content = "您刚才发送的是小视频"; return responseMessage; } /// /// 处理图片请求 /// /// /// public override IResponseMessageBase OnImageRequest(RequestMessageImage requestMessage) { //一隔一返回News或Image格式 if (base.GlobalMessageContext.GetMessageContext(requestMessage).RequestMessages.Count() % 2 == 0) { var responseMessage = CreateResponseMessage(); responseMessage.Articles.Add(new Article() { Title = "您刚才发送了图片信息", Description = "您发送的图片将会显示在边上", PicUrl = requestMessage.PicUrl, Url = "http://sdk.weixin.senparc.com" }); responseMessage.Articles.Add(new Article() { Title = "第二条", Description = "第二条带连接的内容", PicUrl = requestMessage.PicUrl, Url = "http://sdk.weixin.senparc.com" }); return responseMessage; } else { var responseMessage = CreateResponseMessage(); responseMessage.Image.MediaId = requestMessage.MediaId; return responseMessage; } } /// /// 处理语音请求 /// /// /// public override IResponseMessageBase OnVoiceRequest(RequestMessageVoice requestMessage) { var responseMessage = CreateResponseMessage(); //上传缩略图 //var accessToken = Containers.AccessTokenContainer.TryGetAccessToken(appId, appSecret); var uploadResult = Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadTemporaryMedia(appId, UploadMediaFileType.image, Server.GetMapPath("~/Images/Logo.jpg")); //设置音乐信息 responseMessage.Music.Title = "天籁之音"; responseMessage.Music.Description = "播放您上传的语音"; responseMessage.Music.MusicUrl = "http://sdk.weixin.senparc.com/Media/GetVoice?mediaId=" + requestMessage.MediaId; responseMessage.Music.HQMusicUrl = "http://sdk.weixin.senparc.com/Media/GetVoice?mediaId=" + requestMessage.MediaId; responseMessage.Music.ThumbMediaId = uploadResult.media_id; //推送一条客服消息 try { CustomApi.SendText(appId, WeixinOpenId, "本次上传的音频MediaId:" + requestMessage.MediaId); } catch { } return responseMessage; } /// /// 处理视频请求 /// /// /// public override IResponseMessageBase OnVideoRequest(RequestMessageVideo requestMessage) { var responseMessage = CreateResponseMessage(); responseMessage.Content = "您发送了一条视频信息,ID:" + requestMessage.MediaId; #region 上传素材并推送到客户端 Task.Factory.StartNew(async () => { //上传素材 var dir = Server.GetMapPath("~/App_Data/TempVideo/"); var file = await MediaApi.GetAsync(appId, requestMessage.MediaId, dir); var uploadResult = await MediaApi.UploadTemporaryMediaAsync(appId, UploadMediaFileType.video, file, 50000); await CustomApi.SendVideoAsync(appId, base.WeixinOpenId, uploadResult.media_id, "这是您刚才发送的视频", "这是一条视频消息"); }).ContinueWith(async task => { if (task.Exception != null) { WeixinTrace.Log("OnVideoRequest()储存Video过程发生错误:", task.Exception.Message); var msg = string.Format("上传素材出错:{0}\r\n{1}", task.Exception.Message, task.Exception.InnerException != null ? task.Exception.InnerException.Message : null); await CustomApi.SendTextAsync(appId, base.WeixinOpenId, msg); } }); #endregion return responseMessage; } /// /// 处理链接消息请求 /// /// /// public override IResponseMessageBase OnLinkRequest(RequestMessageLink requestMessage) { var responseMessage = ResponseMessageBase.CreateFromRequestMessage(requestMessage); responseMessage.Content = string.Format(@"您发送了一条连接信息: Title:{0} Description:{1} Url:{2}", requestMessage.Title, requestMessage.Description, requestMessage.Url); return responseMessage; } public override IResponseMessageBase OnFileRequest(RequestMessageFile requestMessage) { var responseMessage = requestMessage.CreateResponseMessage(); responseMessage.Content = string.Format(@"您发送了一个文件: 文件名:{0} 说明:{1} 大小:{2} MD5:{3}", requestMessage.Title, requestMessage.Description, requestMessage.FileTotalLen, requestMessage.FileMd5); return responseMessage; } /// /// 处理事件请求(这个方法一般不用重写,这里仅作为示例出现。除非需要在判断具体Event类型以外对Event信息进行统一操作 /// /// /// public override IResponseMessageBase OnEventRequest(IRequestMessageEventBase requestMessage) { var eventResponseMessage = base.OnEventRequest(requestMessage);//对于Event下属分类的重写方法,见:CustomerMessageHandler_Events.cs //TODO: 对Event信息进行统一操作 return eventResponseMessage; } public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) { /* 所有没有被处理的消息会默认返回这里的结果, * 因此,如果想把整个微信请求委托出去(例如需要使用分布式或从其他服务器获取请求), * 只需要在这里统一发出委托请求,如: * var responseMessage = MessageAgent.RequestResponseMessage(agentUrl, agentToken, RequestDocument.ToString()); * return responseMessage; */ var responseMessage = this.CreateResponseMessage(); responseMessage.Content = "这条消息来自DefaultResponseMessage。"; return responseMessage; } public override IResponseMessageBase OnUnknownTypeRequest(RequestMessageUnknownType requestMessage) { /* * 此方法用于应急处理SDK没有提供的消息类型, * 原始XML可以通过requestMessage.RequestDocument(或this.RequestDocument)获取到。 * 如果不重写此方法,遇到未知的请求类型将会抛出异常(v14.8.3 之前的版本就是这么做的) */ var msgType = Senparc.NeuChar.Helpers.MsgTypeHelper.GetRequestMsgTypeString(requestMessage.RequestDocument); var responseMessage = this.CreateResponseMessage(); responseMessage.Content = "未知消息类型:" + msgType; WeixinTrace.SendCustomLog("未知请求消息类型", requestMessage.RequestDocument.ToString());//记录到日志中 return responseMessage; } } }