/// <summary> /// Parse the XDocument to RequestMessage, decrypt it if needed. /// </summary> /// <param name="requestStream">WeChat RequestBody stream.</param> /// <param name="secretInfo">The secretInfo used to decrypt the message.</param> /// <returns>Decrypted WeChat RequestMessage instance.</returns> private IRequestMessageBase GetRequestMessage(Stream requestStream, SecretInfo secretInfo) { if (requestStream.CanSeek) { requestStream.Seek(0, SeekOrigin.Begin); } using (var xr = XmlReader.Create(requestStream)) { var postDataDocument = XDocument.Load(xr); // decrypt xml document message and parse to message var postDataStr = postDataDocument.ToString(); var decryptDoc = postDataDocument; if (secretInfo != null && !string.IsNullOrWhiteSpace(_settings.Token) && postDataDocument.Root.Element("Encrypt") != null && !string.IsNullOrEmpty(postDataDocument.Root.Element("Encrypt").Value)) { var msgCrype = new MessageCryptography(secretInfo, _settings); var msgXml = msgCrype.DecryptMessage(postDataStr); decryptDoc = XDocument.Parse(msgXml); } var requestMessage = WeChatMessageFactory.GetRequestEntity(decryptDoc, _logger); return requestMessage; } }
public static List <IRequestMessageBase> GetMockRequestMessageList() { var logger = GetMockLogger(); var requestList = new List <IRequestMessageBase> { WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlText), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlImage), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlVoice), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlVideo), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlShortVideo), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlLocation), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlLink), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlEventClick), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlEventLocation), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlEventView), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlEventSubscribe), logger), WeChatMessageFactory.GetRequestEntity(XDocument.Parse(XmlEventScan), logger), }; return(requestList); }
public void GetResponseXmlTest() { { // Text var result = WeChatMessageFactory.ConvertResponseToXml(MockDataUtility.TextResponse); Assert.Equal(MockDataUtility.PassiveXmlText, result); } { // Image var result = WeChatMessageFactory.ConvertResponseToXml(MockDataUtility.ImageResponse); Assert.Equal(MockDataUtility.PassiveXmlImage, result); } { // Voice var result = WeChatMessageFactory.ConvertResponseToXml(MockDataUtility.VoiceResponse); Assert.Equal(MockDataUtility.PassiveXmlVoice, result); } { // Video var result = WeChatMessageFactory.ConvertResponseToXml(MockDataUtility.VideoResponse); Assert.Equal(MockDataUtility.PassiveXmlVideo, result); } { // Music var result = WeChatMessageFactory.ConvertResponseToXml(MockDataUtility.MusicResponse); Assert.Equal(MockDataUtility.PassiveXmlMusic, result); } { // News var result = WeChatMessageFactory.ConvertResponseToXml(MockDataUtility.NewsResponse); Assert.Equal(MockDataUtility.PassiveXmlNews, result); } }
public void GetRequestEntityTest() { var logger = NullLogger.Instance; { // Text var doc = XDocument.Parse(MockDataUtility.XmlText); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is TextRequest); MessageBaseTest(result as TextRequest); var textRequest = result as TextRequest; Assert.Equal(RequestMessageTypes.Text, result.MsgType); Assert.Equal("this is a test", textRequest.Content); } { // Image var doc = XDocument.Parse(MockDataUtility.XmlImage); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is ImageRequest); Assert.Equal(RequestMessageTypes.Image, result.MsgType); MessageBaseTest(result as RequestMessage); var imageRequest = result as ImageRequest; Assert.Equal("this is a url", imageRequest.PicUrl); Assert.Equal("media_id", imageRequest.MediaId); } { // Voice var doc = XDocument.Parse(MockDataUtility.XmlVoice); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is VoiceRequest); Assert.Equal(RequestMessageTypes.Voice, result.MsgType); MessageBaseTest(result as RequestMessage); var voiceRequest = result as VoiceRequest; Assert.Equal("media_id", voiceRequest.MediaId); Assert.Equal("Format", voiceRequest.Format); } { // Video var doc = XDocument.Parse(MockDataUtility.XmlVideo); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is VideoRequest); Assert.Equal(RequestMessageTypes.Video, result.MsgType); MessageBaseTest(result as RequestMessage); var videoRequest = result as VideoRequest; Assert.Equal("media_id", videoRequest.MediaId); Assert.Equal("thumb_media_id", videoRequest.ThumbMediaId); } { // Short Video var doc = XDocument.Parse(MockDataUtility.XmlShortVideo); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is ShortVideoRequest); Assert.Equal(RequestMessageTypes.ShortVideo, result.MsgType); MessageBaseTest(result as RequestMessage); var shortvideoRequest = result as ShortVideoRequest; Assert.Equal("media_id", shortvideoRequest.MediaId); Assert.Equal("thumb_media_id", shortvideoRequest.ThumbMediaId); } { // Location var doc = XDocument.Parse(MockDataUtility.XmlLocation); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is LocationRequest); Assert.Equal(RequestMessageTypes.Location, result.MsgType); MessageBaseTest(result as RequestMessage); var locationRequest = result as LocationRequest; Assert.Equal(23.134521, locationRequest.Latitude); Assert.Equal(113.358803, locationRequest.Longtitude); Assert.Equal(20, locationRequest.Scale); Assert.Equal("LocationInfo", locationRequest.Label); } { // Link var doc = XDocument.Parse(MockDataUtility.XmlLink); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is LinkRequest); Assert.Equal(RequestMessageTypes.Link, result.MsgType); MessageBaseTest(result as RequestMessage); var linkRequest = result as LinkRequest; Assert.Equal("This is a link", linkRequest.Title); Assert.Equal("This is a link", linkRequest.Description); Assert.Equal("url", linkRequest.Url); } { // Click Event var doc = XDocument.Parse(MockDataUtility.XmlEventClick); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is ClickEvent); EventBaseTest(result as RequestEvent); var clickEvent = result as ClickEvent; Assert.Equal(EventTypes.Click, clickEvent.EventType); Assert.Equal(clickEvent.EventType, EventTypes.Click); Assert.Equal("EVENTKEY", clickEvent.EventKey); } { // Location Event var doc = XDocument.Parse(MockDataUtility.XmlEventLocation); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is LocationEvent); EventBaseTest(result as RequestEvent); var locationEvent = result as LocationEvent; Assert.Equal(EventTypes.Location, locationEvent.EventType); Assert.Equal(23.104105, locationEvent.Latitude); Assert.Equal(113.320107, locationEvent.Longitude); Assert.Equal(65.000000, locationEvent.Precision); } { // View Event var doc = XDocument.Parse(MockDataUtility.XmlEventView); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is ViewEvent); EventBaseTest(result as RequestEvent); var viewEvent = result as ViewEvent; Assert.Equal(EventTypes.View, viewEvent.EventType); Assert.Equal("www.qq.com", viewEvent.EventKey); } { // Subscribe Event var doc = XDocument.Parse(MockDataUtility.XmlEventSubscribe); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is SubscribeEvent); EventBaseTest(result as RequestEvent); var subscribeEvent = result as SubscribeEvent; Assert.Equal(EventTypes.Subscribe, subscribeEvent.EventType); Assert.Equal("qrscene_123123", subscribeEvent.EventKey); Assert.Equal("TICKET", subscribeEvent.Ticket); } { // Scan Event var doc = XDocument.Parse(MockDataUtility.XmlEventScan); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is ScanEvent); EventBaseTest(result as RequestEvent); var scanEvent = result as ScanEvent; Assert.Equal(EventTypes.Scan, scanEvent.EventType); Assert.Equal("SCENE_VALUE", scanEvent.EventKey); Assert.Equal("TICKET", scanEvent.Ticket); } { // ScanPush Event var doc = XDocument.Parse(MockDataUtility.XmlEventScanPush); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is ScanPushEvent); EventBaseTest(result as RequestEvent); var scanPushEvent = result as ScanPushEvent; Assert.Equal(EventTypes.ScanPush, scanPushEvent.EventType); Assert.Equal("6", scanPushEvent.EventKey); Assert.Equal("qrcode", scanPushEvent.ScanCodeInfo.ScanType); Assert.Equal("1", scanPushEvent.ScanCodeInfo.ScanResult); } { // WaitScanPush Event var doc = XDocument.Parse(MockDataUtility.XmlEventWaitScanPush); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is WaitScanPushEvent); EventBaseTest(result as RequestEvent); var waitScanPushEvent = result as WaitScanPushEvent; Assert.Equal(EventTypes.WaitScanPush, waitScanPushEvent.EventType); Assert.Equal("6", waitScanPushEvent.EventKey); Assert.Equal("qrcode", waitScanPushEvent.ScanCodeInfo.ScanType); Assert.Equal("2", waitScanPushEvent.ScanCodeInfo.ScanResult); } { // Camera Event var doc = XDocument.Parse(MockDataUtility.XmlEventCamera); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is CameraEvent); EventBaseTest(result as RequestEvent); var cameraEvent = result as CameraEvent; Assert.Equal(EventTypes.Camera, cameraEvent.EventType); Assert.Equal("6", cameraEvent.EventKey); Assert.Equal(1, cameraEvent.SendPicsInfo.Count); Assert.Equal("1b5f7c23b5bf75682a53e7b6d163e185", cameraEvent.SendPicsInfo.PicList[0].Item.PicMD5Sum); } { // CameraOrAlbum Event var doc = XDocument.Parse(MockDataUtility.XmlEventCameraOrAlbum); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is CameraOrAlbumEvent); EventBaseTest(result as RequestEvent); var cameraOrAlbumEvent = result as CameraOrAlbumEvent; Assert.Equal(EventTypes.CameraOrAlbum, cameraOrAlbumEvent.EventType); Assert.Equal("6", cameraOrAlbumEvent.EventKey); Assert.Equal(1, cameraOrAlbumEvent.SendPicsInfo.Count); Assert.Equal("5a75aaca956d97be686719218f275c6b", cameraOrAlbumEvent.SendPicsInfo.PicList[0].Item.PicMD5Sum); } { // WeChatAlbum Event var doc = XDocument.Parse(MockDataUtility.XmlEventWeChatAlbum); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is WeChatAlbumEvent); EventBaseTest(result as RequestEvent); var wechatAlbumEvent = result as WeChatAlbumEvent; Assert.Equal(EventTypes.WeChatAlbum, wechatAlbumEvent.EventType); Assert.Equal("6", wechatAlbumEvent.EventKey); Assert.Equal(1, wechatAlbumEvent.SendPicsInfo.Count); Assert.Equal("5a75aaca956d97be686719218f275c6b", wechatAlbumEvent.SendPicsInfo.PicList[0].Item.PicMD5Sum); } { // SelectLocation Event var doc = XDocument.Parse(MockDataUtility.XmlEventSelectLocation); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is SelectLocationEvent); EventBaseTest(result as RequestEvent); var selectLocationEvent = result as SelectLocationEvent; Assert.Equal(EventTypes.SelectLocation, selectLocationEvent.EventType); Assert.Equal("6", selectLocationEvent.EventKey); Assert.Equal("23", selectLocationEvent.SendLocationInfo.Latitude); Assert.Equal("113", selectLocationEvent.SendLocationInfo.Longtitude); Assert.Equal("15", selectLocationEvent.SendLocationInfo.Scale); Assert.Equal("No.328 Xinghu Street", selectLocationEvent.SendLocationInfo.Label); Assert.Equal("test", selectLocationEvent.SendLocationInfo.PoiName); } { // ViewMiniProgram Event var doc = XDocument.Parse(MockDataUtility.XmlEventViewMiniProgram); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is ViewMiniProgramEvent); EventBaseTest(result as RequestEvent); var viewMiniProgramEvent = result as ViewMiniProgramEvent; Assert.Equal(EventTypes.ViewMiniProgram, viewMiniProgramEvent.EventType); Assert.Equal("pages/index/index", viewMiniProgramEvent.EventKey); Assert.Equal("MENUID", viewMiniProgramEvent.MenuId); } { // MassSendJobFinished Event var doc = XDocument.Parse(MockDataUtility.XmlEventMassSendJobFinished); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is MassSendJobFinishedEvent); EventBaseTest(result as RequestEvent); var massSendJobFinishedEvent = result as MassSendJobFinishedEvent; Assert.Equal(EventTypes.MassSendJobFinished, massSendJobFinishedEvent.EventType); Assert.Equal(1000001625, massSendJobFinishedEvent.MsgID); Assert.Equal("err(30003)", massSendJobFinishedEvent.Status); Assert.Equal(0, massSendJobFinishedEvent.TotalCount); Assert.Equal(0, massSendJobFinishedEvent.FilterCount); Assert.Equal(0, massSendJobFinishedEvent.SentCount); Assert.Equal(0, massSendJobFinishedEvent.ErrorCount); Assert.Equal(2, massSendJobFinishedEvent.CopyrightCheckResult.Count); Assert.Equal(1, massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[0].ArticleIdx); Assert.Equal(0, massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[0].UserDeclareState); Assert.Equal(2, massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[0].AuditState); Assert.Equal("Url_1", massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[0].OriginalArticleUrl); Assert.Equal(1, massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[0].OriginalArticleType); Assert.Equal(1, massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[0].CanReprint); Assert.Equal(1, massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[0].NeedReplaceContent); Assert.Equal(1, massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[0].NeedShowReprintSource); Assert.Equal("Url_2", massSendJobFinishedEvent.CopyrightCheckResult.ResultList.Items[1].OriginalArticleUrl); Assert.Equal(2, massSendJobFinishedEvent.CopyrightCheckResult.CheckState); } { // TemplateSendFinished var doc = XDocument.Parse(MockDataUtility.XmlEventTemplateSendFinished); var result = WeChatMessageFactory.GetRequestEntity(doc, logger); Assert.True(result is TemplateSendFinishedEvent); EventBaseTest(result as RequestEvent); var templateSendFinishedEvent = result as TemplateSendFinishedEvent; Assert.Equal(EventTypes.TemplateSendFinished, templateSendFinishedEvent.EventType); Assert.Equal(200163840, templateSendFinishedEvent.MsgID); Assert.Equal("failed:user block", templateSendFinishedEvent.Status); } }
/// <summary> /// Process the request from WeChat. /// This method can be called from inside a POST method on any Controller implementation. /// </summary> /// <param name="httpRequest">The HTTP request object, typically in a POST handler by a Controller.</param> /// <param name="httpResponse">The HTTP response object.</param> /// <param name="bot">The bot implementation.</param> /// <param name="secretInfo">The secret info provide by WeChat.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A task that represents the work queued to execute.</returns> public async Task ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, SecretInfo secretInfo, CancellationToken cancellationToken = default(CancellationToken)) { _logger.LogInformation("Receive a new request from WeChat."); if (httpRequest == null) { throw new ArgumentNullException(nameof(httpRequest)); } if (httpResponse == null) { throw new ArgumentNullException(nameof(httpResponse)); } if (bot == null) { throw new ArgumentNullException(nameof(bot)); } if (secretInfo == null) { throw new ArgumentNullException(nameof(secretInfo)); } if (!VerificationHelper.VerifySignature(secretInfo.WebhookSignature, secretInfo.Timestamp, secretInfo.Nonce, _settings.Token)) { throw new UnauthorizedAccessException("Signature verification failed."); } // Return echo string when request is setting up the endpoint. if (!string.IsNullOrEmpty(secretInfo.EchoString)) { await httpResponse.WriteAsync(secretInfo.EchoString, cancellationToken).ConfigureAwait(false); return; } // Directly return OK header to prevent WeChat from retrying. if (!_settings.PassiveResponseMode) { httpResponse.StatusCode = (int)HttpStatusCode.OK; httpResponse.ContentType = "text/event-stream"; await httpResponse.WriteAsync(string.Empty).ConfigureAwait(false); await httpResponse.Body.FlushAsync().ConfigureAwait(false); } try { var wechatRequest = GetRequestMessage(httpRequest.Body, secretInfo); var wechatResponse = await ProcessWeChatRequest( wechatRequest, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false); // Reply WeChat(User) request have two ways, set response in http response or use background task to process the request async. if (_settings.PassiveResponseMode) { httpResponse.StatusCode = (int)HttpStatusCode.OK; httpResponse.ContentType = "text/xml"; var xmlString = WeChatMessageFactory.ConvertResponseToXml(wechatResponse); await httpResponse.WriteAsync(xmlString).ConfigureAwait(false); } } catch (Exception ex) { _logger.LogError(ex, "Process WeChat request failed."); throw; } }
/// <summary> /// Process the request from WeChat. /// This method can be called from inside a POST method on any Controller implementation. /// </summary> /// <param name="httpRequest">The HTTP request object, typically in a POST handler by a Controller.</param> /// <param name="httpResponse">The HTTP response object.</param> /// <param name="bot">The bot implementation.</param> /// <param name="secretInfo">The secret info provide by WeChat.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A task that represents the work queued to execute.</returns> public async Task ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, SecretInfo secretInfo, CancellationToken cancellationToken = default(CancellationToken)) { _logger.LogInformation("Receive a new request from WeChat."); if (httpRequest == null) { throw new ArgumentNullException(nameof(httpRequest)); } if (httpResponse == null) { throw new ArgumentNullException(nameof(httpResponse)); } if (bot == null) { throw new ArgumentNullException(nameof(bot)); } if (secretInfo == null) { throw new ArgumentNullException(nameof(secretInfo)); } if (false == string.IsNullOrEmpty(secretInfo.EchoString)) { var wXBizMsgCrypt = new WXBizMsgCrypt(_settings.Token, _settings.EncodingAesKey, _settings.CorpId); var replayEchoString = string.Empty; var code = wXBizMsgCrypt.VerifyURL(secretInfo.MessageSignature, secretInfo.Timestamp, secretInfo.Nonce, secretInfo.EchoString, ref replayEchoString); if (code != 0) { throw new UnauthorizedAccessException($"Signature verification failed. Code: {code}"); } // Return echo string when request is setting up the endpoint. if (!string.IsNullOrEmpty(replayEchoString)) { await httpResponse.WriteAsync(replayEchoString, cancellationToken).ConfigureAwait(false); return; } } // Directly return OK header to prevent WeChat from retrying. if (!_settings.PassiveResponseMode) { httpResponse.StatusCode = (int)HttpStatusCode.OK; httpResponse.ContentType = "text/event-stream"; await httpResponse.WriteAsync(string.Empty).ConfigureAwait(false); await httpResponse.Body.FlushAsync().ConfigureAwait(false); } try { var wechatRequest = GetRequestMessage(httpRequest.Body, secretInfo); var wechatResponse = await ProcessWeChatRequest( wechatRequest, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false); // Reply WeChat(User) request have two ways, set response in http response or use background task to process the request async. if (_settings.PassiveResponseMode) { httpResponse.StatusCode = (int)HttpStatusCode.OK; httpResponse.ContentType = "text/xml"; var xmlString = WeChatMessageFactory.ConvertResponseToXml(wechatResponse); var response = string.Empty; var timestemp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(); var nonce = Guid.NewGuid().ToString("N"); new WXBizMsgCrypt(_settings.Token, _settings.EncodingAesKey, _settings.CorpId).EncryptMsg(xmlString, timestemp, nonce, ref response); await httpResponse.WriteAsync(response).ConfigureAwait(false); } } catch (Exception ex) { _logger.LogError(ex, "Process WeChat request failed."); throw; } }