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;
            }
        }
예제 #3
0
        /// <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;
            }
        }