refit icon indicating copy to clipboard operation
refit copied to clipboard

[BUG] Complex object not being flattened correctly

Open cryo75 opened this issue 5 years ago • 5 comments

NET5 Visual Studio 2019

I'm using DevExpress for Blazor and to get records from an external API I use this object:

    public class DataSourceLoadOptionsBase
    {
        public static bool? StringToLowerDefault { get; set; }
        public bool? PaginateViaPrimaryKey { get; set; }
        public bool? StringToLower { get; set; }
        public string DefaultSort { get; set; }
        public string[] PrimaryKey { get; set; }
        public bool? ExpandLinqSumType { get; set; }
        public bool? RemoteGrouping { get; set; }
        public bool? RemoteSelect { get; set; }
        public string[] PreSelect { get; set; }
        public string[] Select { get; set; }
        public SummaryInfo[] GroupSummary { get; set; }
        public SummaryInfo[] TotalSummary { get; set; }
        public IList Filter { get; set; }
        public GroupingInfo[] Group { get; set; }
        public SortingInfo[] Sort { get; set; }
        public int Take { get; set; }
        public int Skip { get; set; }
        public bool IsCountQuery { get; set; }
        public bool RequireGroupCount { get; set; }
        public bool RequireTotalCount { get; set; }
        public bool? SortByPrimaryKey { get; set; }
        public bool AllowAsyncOverSync { get; set; }
    }

My interface is:

        [Get("/api/Customers/{id}/Orders")]
        Task<LoadResult> GetOrdersAsync(int id, [Body] DataSourceLoadOptionsBase options, CancellationToken ct = default);

But an exception gets thrown:

{"An error occurred while sending the request."}
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146233079
    HelpLink: null
    InnerException: Message = "Should not get here."
    Message: "An error occurred while sending the request."
    Source: "System.Net.Http"
    StackTrace: "   at System.Net.Http.HttpConnection.<SendAsyncCore>d__56.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Net.Http.HttpConnectionPool.<SendWithRetryAsync>d__72.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Threading.Tasks.ValueTask`1.get_Result()\r\n   at System.Net.Http.RedirectHandler.<SendAsync>d__4.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.ConfiguredTaskAwait
able`1.ConfiguredTaskAwaiter.GetResult()\r\n   at System.Net.Http.DiagnosticsHandler.<SendAsyncCore>d__5.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()\r\n   at KeyAccount.Web.Config.AboServerHandler.<SendAsync>d__3.MoveNext() in C:\\xxxcs:line 44\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.Config
uredTaskAwaiter.GetResult()\r\n   at System.Net.Http.HttpClient.<SendAsyncCore>d__85.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()\r\n   at Refit.RequestBuilderImplementation.<>c__DisplayClass14_0`2.<<BuildCancellableTaskFuncForMethod>b__0>d.MoveNext() in /_/Refit/RequestBuilderImplementation.cs:line 291\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at ...."
    StatusCode: null
    TargetSite: {Void MoveNext()}

I also have the possibility to convert the object to a string with the query parameters. A simplified example would be:

        "requireTotalCount=true&take=10&filter=[[\"Number\",\"contains\",\"77\"]]"

        [Get("/api/Customers/{id}/Orders")]
        Task<LoadResult> GetOrdersAsync(int id, string query, CancellationToken ct = default);

But then what is the correct way to pass the string as a parameter?

cryo75 avatar Feb 16 '21 16:02 cryo75

It sounds like System.Text.Json isn't serializing the object you want. I'd recommend seeing the docs for that serializer: https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0#table-of-differences-between-newtonsoftjson-and-systemtextjson

You can also use the Newtonsoft.Json serailizer if you prefer: https://github.com/reactiveui/refit#breaking-changes-in-6x

Learn how to migrate from Newtonsoft.Json to System.Text.Json. Includes sample code.
GitHub
The automatic type-safe REST library for .NET Core, Xamarin and .NET. Heavily inspired by Square's Retrofit library, Refit turns your REST API into a live interface. - reactiveui/refit

clairernovotny avatar Feb 16 '21 16:02 clairernovotny

Did that. The object is serialized correctly. However an ApiException is thrown on the way back:

{"An error occured deserializing the response."}
    Content: null
    ContentHeaders: {Content-Length: 7181
Content-Type: application/json; charset=utf-8
}
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146233088
    HasContent: false
    Headers: {Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Tue, 16 Feb 2021 17:41:46 GMT
}
    HelpLink: null
    HttpMethod: {GET}
    InnerException: {"Cannot create and populate list type System.Collections.IEnumerable. Path 'data', line 1, position 9."}
    Message: "An error occured deserializing the response."
    ReasonPhrase: "OK"
    RefitSettings: {Refit.RefitSettings}
    RequestMessage: {Method: GET, RequestUri: 'https://localhost:44390/api/Customers/600/Orders?RequireTotalCount=True&RequireGroupCount=False&IsCountQuery=False&Skip=0&Take=10&Group=&AllowAsyncOverSync=True', Version: 1.1, Content: <null>, Headers:
{
  Authorization: Bearer xxx
  traceparent: 00-49a7c9118f190043aa49ebf69272fa1d-2e2f7b6d53309b49-00
}}
    Source: "Refit"
    StackTrace: "   at Refit.RequestBuilderImplementation.<DeserializeContentAsync>d__15`1.MoveNext() in /_/Refit/RequestBuilderImplementation.cs:line 332\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()\r\n   at Refit.RequestBuilderImplementation.<>c__DisplayClass14_0`2.<<BuildCancellableTaskFuncForMethod>b__0>d.MoveNext() in /_/Refit/RequestBuilderImplementation.cs:line 291\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at 
xxx.cs:line 23\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at xxx.razor:line 153"
    StatusCode: OK
    TargetSite: {Void MoveNext()}
    Uri: {https://localhost:44390/api/Customers/600/Orders?RequireTotalCount=True&RequireGroupCount=False&IsCountQuery=False&Skip=0&Take=10&Group=&AllowAsyncOverSync=True}

The JSON is valid. I also serialized the result server-side using Newtonsoft.Json and it was valid.

cryo75 avatar Feb 16 '21 17:02 cryo75

Any solutions to that problem?

FlyingDev55 avatar Sep 06 '21 08:09 FlyingDev55

Have you solved this problem yet?

Arsnj avatar Jan 26 '22 05:01 Arsnj

yes, but indirectly.

Arsnj ***@***.***> hat am 26.01.2022 06:40 geschrieben:

Have you solved this problem yet? —Reply to this email directly, view it on GitHub, or unsubscribe.Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.Message ID: @.***>

FlyingDev55 avatar Jan 26 '22 13:01 FlyingDev55