JeffreySu / WeiXinMPSDK

微信全平台 .NET SDK, Senparc.Weixin for C#,支持 .NET Framework 及 .NET Core、.NET 8.0。已支持微信公众号、小程序、小游戏、微信支付、企业微信/企业号、开放平台、JSSDK、微信周边等全平台。 WeChat SDK for C#.
https://weixin.senparc.com
Apache License 2.0
8.43k stars 4.35k forks source link

使用CoreMvc的WeixinResult,ContentResultExecutor.ExecuteAsync() - set_ContentType()抛异常 #796

Closed kchanlee closed 7 years ago

kchanlee commented 7 years ago

( 此版块专为反馈bug及提交需求服务,不负责解答开发问题,请勿发表开发问题, 如果您需要这方面的帮助,请移步问答社区https://weixin.senparc.com/QA )

问题描述

使用CoreMvc的WeixinResult,ContentResultExecutor.ExecuteAsync() - set_ContentType()抛异常

看起来原因应该是:在WeixinResult.ExecuteResult()里写了一次context.HttpContext.Response.Body,随后调用ContentResult.ExecuteResult(),在那里面又写了一次context.HttpContext.Response.Body所导致。

异常详情如下:

System.InvalidOperationException: Headers are read-only, response has already started.
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.FrameHeaders.ThrowHeadersReadOnlyException()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.FrameHeaders.Microsoft.AspNetCore.Http.IHeaderDictionary.set_Item(String key, StringValues value)
   at Microsoft.AspNetCore.Http.Internal.DefaultHttpResponse.set_ContentType(String value)
   at Microsoft.AspNetCore.Mvc.Internal.ContentResultExecutor.<ExecuteAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeResultAsync>d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResultFilterAsync>d__24.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeFilterPipelineAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.<Invoke>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame`1.<ProcessRequestsAsync>d__2.MoveNext()
微信官方文档 URL
微信官方文档快照(直接复制关键内容到下方)
发现问题的模块
模块对应的.net版本
开发环境
缓存环境
JeffreySu commented 7 years ago

你用的解决方案文件(.sln)是哪个?

kchanlee commented 7 years ago

@JeffreySu 我用的是Developer-FullDotNet branch commit c9600a61,直接拿Senparc.Weixin、Senparc.Weixin.MP、Senparc.Weixin.MP.CoreMvcExtension的源码来用,把它们的.csproj加到我的.sln里面。

JeffreySu commented 7 years ago

你的Action是怎么写的可以给我看一下吗?

kchanlee commented 7 years ago

@JeffreySu

        [HttpPost]
        [ActionName("Index")]
        public async Task<ActionResult> Post(PostModel postModel)
        {
            if (!CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, _settings.WeChatToken))
            {
                _logger.LogError("Invalid Parameter received!");
                return Content("Invalid Parameter");
            }

            postModel.Token = _settings.WeChatToken;
            postModel.EncodingAESKey = _settings.WeChatEncodingAESKey;
            postModel.AppId = _settings.WeChatAppId;

            try
            {
                /**
                 * Some metheds/properties (e.g. Seek()) of Stream are not supported in Request.Body 
                 * but are invoked in WechatMessageHandler which cause exception. So we explicitly copy
                 * to a MemoryStream to avoid this.
                 */
                var stream = new MemoryStream();
                await Request.Body.CopyToAsync(stream);
                stream.Position = 0;

                var handler = new WechatMessageHandler(stream, postModel, _chatStore, _messagerHandlerLogger);
                await handler.ExecuteAsync();

                return new WeixinResult(handler);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Failed to process user's message.");
                return new WeixinResult(e.ToString());
            }
JeffreySu commented 7 years ago

参考 Senparc.Weixin.MP.CoreSample 项目中 WeixinController 里面,试试看这样写:

            return new FixWeixinBugWeixinResult(messageHandler);//v0.8+
kchanlee commented 7 years ago

@JeffreySu 谢谢你的及时解答,我用以下方法解决问题了

return Content(handler.FinalResponseDocument.ToString(), "text/xml");
kchanlee commented 7 years ago

@JeffreySu 我觉得这应该算是个bug,希望能在后续版本修复

JeffreySu commented 7 years ago

非常感谢这么细心且给我们建议! 实际开发的话,你直接用我上面这个FixWeixinBugWeixinResult取代WeixinResult就行了,WeixinResult当时是用来解决其他问题的,但是基本上已经不在Demo里面出现了。

JeffreySu commented 7 years ago

看 \src\Senparc.Weixin.MP.Sample.vs2017\Senparc.Weixin.MP.Sample.vs2017.sln 这个是从.NET 4.5移植过来的Sample,可以正常运行。