episerver / netcore-preview

This repository is a preview providing early access to the latest Optimizely (formerly Episerver) product packages targeting .NET 5.
43 stars 9 forks source link

InvalidOperationException thrown when browsing long list of catalog items #35

Closed stefanolsen closed 3 years ago

stefanolsen commented 3 years ago

I am testing out a Commerce 12 installation, in which one of the catalog nodes contain more than 200 products, along with relevant sub-entries. When browsing this catalog node, the XHR-request fails with the below stack trace. When browsing any other (smaller) catalog node, the proper response is returned.

I have read that the quick-fix is to set AllowSynchronousIO to true. But I would prefer to have this block of code fixed to be completely async (as suggested in the exception message).

Build:

System.InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionBody.Write(Byte[] buffer, Int32 offset, Int32 count)
   at Microsoft.AspNetCore.WebUtilities.HttpResponseStreamWriter.Write(String value)
   at Newtonsoft.Json.Utilities.JavaScriptUtils.WriteEscapedJavaScriptString(TextWriter writer, String s, Char delimiter, Boolean appendDelimiters, Boolean[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IArrayPool`1 bufferPool, Char[]& writeBuffer)
   at Newtonsoft.Json.JsonTextWriter.WriteEscapedString(String value, Boolean quote)
   at Newtonsoft.Json.JsonTextWriter.WritePropertyName(String name, Boolean escape)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   at EPiServer.Formatters.Internal.ExtendedNewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, ResponseDecorator responseDecorator)
   at EPiServer.Formatters.Internal.ExtendedNewtonsoftJsonOutputFormatter.WriteAsync(OutputFormatterWriteContext context, ResponseDecorator responseDecorator)
   at EPiServer.Shell.Services.Rest.RestResultBase.ExecuteResultAsync(ActionContext context)
   at EPiServer.Shell.Services.Rest.RestResult.ExecuteResultAsync(ActionContext context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

REQUEST
=======
http://localhost:56789/EPiServer/cms/Stores/contentstructure/?referenceId=1073741831_1269_CatalogContent&query=getchildren&market=ALL&includeProperties=true&allLanguages=true&toplevel=false&currentCategory=1073741831_1269_CatalogContent&simplified=true&sortMode=false&sort(+typeSortIndex)&dojo.preventCache=1619506774044

HEADERS
=======
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Accept: application/javascript, application/json
Accept-Encoding: identity
Accept-Language: en-US,en;q=0.9,no;q=0.8
Host: localhost:56789
Referer: http://localhost:56789/EPiServer/Commerce/catalog
Range: items=0-24
sec-ch-ua-mobile: ?0
X-Requested-With: XMLHttpRequest
X-EPiContentLanguage: en
lunchin commented 3 years ago

Thanks for the report, I added to out internal tracking system,

stefanolsen commented 3 years ago

@lunchin: Maybe you could also replace Newtonsoft.Json with System.Text.Json in the future?

lunchin commented 3 years ago

It should be using System.Text.Json

stefanolsen commented 3 years ago

I tested it again. Newest packages still use Newtonsoft in Shell responses, which generates the same error with a large catalog node.

lunchin commented 3 years ago

No I meant it should, we just fixed the issue, will be in package drop today

jbearfoot commented 3 years ago

I have reported an issue that Newtonsoft should not be used in this scenario. An alternative workaround for now (to AlllowSynchronusIO = true) is to increase the buffer that is used when async write is not possible, Like: services.Configure(o => o.JsonResponseBuffer = ); The default value is 1000*256 (256kB)

lunchin commented 3 years ago

Fixed in EPiServer.Commerce.Core.14.0.0-inte-021024

stefanolsen commented 3 years ago

I saw this error again today. In Assets gallery, when expanding a folder with many subfolders.

lunchin commented 3 years ago

In the cms not commerce correct?

lunchin commented 3 years ago

I think this is related to this

https://github.com/episerver/netcore-preview/issues/97#issuecomment-897533932

stefanolsen commented 3 years ago

@lunchin: It was in CMS.