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); } }
/// <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; } }