Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Text.Json - Collection was of a fixed size. Error on IEnumerable property #31089

Closed
WayneHiller opened this issue Oct 7, 2019 · 10 comments · Fixed by #33819
Closed

System.Text.Json - Collection was of a fixed size. Error on IEnumerable property #31089

WayneHiller opened this issue Oct 7, 2019 · 10 comments · Fixed by #33819
Assignees
Milestone

Comments

@WayneHiller
Copy link

I have a class with this:

class Dealer {
        [JsonIgnore]
        [StringLength( MaxNetworksLength )]
        public string Networks {
            get => _Networks;
            set => _Networks = value ?? string.Empty;
        }

        public IEnumerable<string> NetworkCodeList {
            get => !string.IsNullOrEmpty( Networks ) ? Networks?.Split( ',' ) : new string[0];
            set => Networks = (value != null) ? string.Join( ",", value ) : string.Empty;
        }
}

The Networks property is used by Dapper to read/write to and from the database.
The NetworkCodeList is sent/received to and from a web page.

I am getting an error when ASP.NET is Deserializing the object. This worked fine with Json.Net.
Any ideas what I can do here?

System.NotSupportedException: Collection was of a fixed size.
   at System.SZArrayHelper.Add[T](T value)
   at System.Text.Json.JsonSerializer.ApplyValueToEnumerable[TProperty](TProperty& value, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonPropertyInfoNotNullable`4.OnReadEnumerable(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonPropertyInfo.ReadEnumerable(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
   at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
   at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
   at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
   at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
   at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
@am11
Copy link
Member

am11 commented Oct 8, 2019

Minimal steps to repro: https://dotnetfiddle.net/hdhEDG. Toggle comments on line 10 and 11; it works with get => null; and throws with get => Array.Empty<string>();

@ericstj
Copy link
Member

ericstj commented Nov 6, 2019

Thank you for the report. We understand the issue and @layomia is working on a fix.

Moved this to 5.0 since there is a workaround: make the backing data an IEnumerable and have the string property be the one doing the transformation.

@ahsonkhan
Copy link
Member

ahsonkhan commented Nov 13, 2019

Fixed in dotnet/corefx#42420. @WayneHiller, can you please verify that the issue you reported has been fixed by using the latest nightly build of .NET Core 5.0 (or by adding a PackageReference to the latest S.T.Json NuGet package, from this feed: https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json - version 5.0.0-alpha.1.19563.1 or higher).

@WayneHiller
Copy link
Author

I guess I need to wait until tomorrow to get version 5.0.0-alpha.1.19563.1, it is not avail yet

@ericstj
Copy link
Member

ericstj commented Nov 13, 2019

@WayneHiller it should be available. This worked for me:

  <ItemGroup>
    <PackageReference Include="System.Text.Json" Version="5.0.0-alpha.1.19563.1" />
  </ItemGroup>

Note, as @ahsonkhan mentioned, you'll need to pick it up from our nightly feed. Make sure you have a nuget.config with something like
https://github.com/dotnet/corefx/blob/1518fdc5cc94571bf3ce1bb95e1a60f789a67f18/NuGet.config#L9

@WayneHiller
Copy link
Author

@ericstj Thanks adding it directly to the csproj file worked. However I am still getting the error. Will aspnet core use the new System.Text.Json assembly by just adding it to the project?

@ericstj
Copy link
Member

ericstj commented Nov 14, 2019

It should, if you're still reproducing the issue can you share an isolated repro project for us to try?

@WayneHiller
Copy link
Author

It is pretty basic. I just created a new aspnet core 3 webapi project and added this controller:

namespace aspnetcore3.Controllers {
    [ApiController]
    [Route( "[controller]" )]
    public class TestController : ControllerBase {
        public class Test {
            private string _Networks = string.Empty;

            [JsonIgnore]
            public string Networks { 
                get => _Networks;
                set => _Networks = value ?? string.Empty;
            }

            public IEnumerable<string> NetworkList {
                get => Networks.Split( ',' );
                set => Networks = value != null ? string.Join( ',', value ) : "";
            }
        }

        private readonly ILogger<WeatherForecastController> _logger;

        public TestController( ILogger<WeatherForecastController> logger ) {
            _logger = logger;
        }

        [HttpPost]
        public void Post( [FromBody] Test test ) {
        }
    }
}

Added the newest System.Text.Json to the project:

<ItemGroup>
    <PackageReference Include="System.Text.Json" Version="5.0.0-alpha.1.19563.1" />
  </ItemGroup>

image

And then called POST to http://localhost:5000/test from Postman:

image

And the result is:

System.NotSupportedException: Collection was of a fixed size.
   at System.SZArrayHelper.Add[T](T value)
   at System.Text.Json.JsonSerializer.ApplyValueToEnumerable[TProperty](TProperty& value, ReadStack& state)
   at System.Text.Json.JsonPropertyInfoNotNullable`4.OnReadEnumerable(ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonPropertyInfo.ReadEnumerable(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
   at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
   at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
   at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
   at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
   at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

@ericstj
Copy link
Member

ericstj commented Nov 14, 2019

Confirmed that this isn't fixed. Looking at this issue and the fix, I don't think the fix was addressing the original issue but instead was addressing a related thing that @layomia found when investigating the original issue.

If I recall, @layomia mentioned that to fix the original issue we couldn't rely on the Getter to return back a mutable collection, even if we previously set a mutable collection with the setter. We needed to build up the muttable collection first, then only set once. I don't see the fix doing this.

@layomia
Copy link
Contributor

layomia commented Nov 19, 2019

Thanks @ericstj. dotnet/corefx#42420 fixes a different issue (discovered while debugging this one) described in that PR's description and illustrated in https://dotnetfiddle.net/hdhEDG. I've updated the PR's description to make it less confusing.

to fix the original issue we couldn't rely on the Getter to return back a mutable collection, even if we previously set a mutable collection with the setter. We needed to build up the muttable collection first, then only set once.

This is indeed the fix for this issue, which is not implemented just yet.

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the 5.0 milestone Feb 1, 2020
andry-tino added a commit to andry-tino/coding-challenges that referenced this issue Oct 3, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants