Refit: Request object collection not serialized correctly

Created on 10 Jul 2018  路  17Comments  路  Source: reactiveui/refit

I have a search request class which has a collection which needs to be serialized as a comma delimited list, but it is currently being sent as System.String%5B%5D

public class Request {
    [Query(CollectionFormat.Csv)]
    public string[] Wibble { get; set; } = new string[] { "a", "b" }
}

the client is

    public interface ISearchApiClient
    {
        [Get("search")]
        Task<Response> Search(Request request);
    }

But the uri it ends up as is/search?Wibble=System.String%5B%5D. Any ideas what I'm doing wrong?

outdated

Most helpful comment

If I change the collection type to be object[] then it will serialise using the Multi style (e.g. A=1&A=2&A=3...), so it looks like there is a bug for serialising collections where the type is known and a possible enhancement to allow using the QueryAttribute for properties on classes used as request objects. Does that sound right?

All 17 comments

I'm not sure the Query attribute is designed to work inside request objects. It definitely works for a parameter.

I still have the same issue without the Query attribute

I think you misunderstood. What I meant was that AFAIK the query attribute only works for method parameters -- not on properties of a request class.

If the Request class were

public class Request {
    public string[] Wibble { get; set; } = new string[] { "a", "b" }
}

I still get the same issue.
But also the Query attribute is marked for use as a parameter or property

I've taken a look at the code and unit tests and it looks like what I'm doing should work. I'll try and take a proper look later.

If you look at RequestBuilderImplementation.cs, it converts request objects to querystring parameters in the BuildQueryMap method.

However, the only reference to QueryAttribute is here -- before the call to BuildQueryMap: https://github.com/reactiveui/refit/blob/master/Refit/RequestBuilderImplementation.cs#L504

GitHub
refit - The automatic type-safe REST library for Xamarin and .NET

The QueryAttribute is a bit of a red herring. If you have a collection on a request object it is serialized using the .ToString() implementation instead of being put onto the query string using either the CSV or Multi type options. I can reproduce with a unit test, but have yet to figure out what needs to change to fix it.

The unit test is

        [Fact]
        public async Task B()
        {
            var mockHttp = new MockHttpMessageHandler();
            var settings = new RefitSettings
            {
                HttpMessageHandlerFactory = () => mockHttp
            };
            HttpRequestMessage request = null;
            mockHttp.Expect(HttpMethod.Get, "http://wibble.com/get").Respond(x =>
            {
                request = x;
                return new HttpResponseMessage(HttpStatusCode.Accepted);
            });

            var client = RestService.For<TestApi>("http://wibble.com", settings);

            var testRequest = new TestRequest
            {
                TestCollection = new List<string>()
                {
                    "A",
                    "B"
                }
            };

            // When
            await client.Get(testRequest).ConfigureAwait(false);

            // Then
            var query = request.RequestUri.Query;
            Assert.Equal("TestCollection=A,B", query);
        }

With the following interface and class set up as well

    internal interface TestApi
    {
        [Get("/get")]
        Task Get(TestRequest request);
    }

    internal class TestRequest
    {
        public ICollection<string> TestCollection { get; set; } = new List<string>();
    }

You would need to look for QueryAttribute when enumerating an object's properties in BuildQueryMap.

If I change the collection type to be object[] then it will serialise using the Multi style (e.g. A=1&A=2&A=3...), so it looks like there is a bug for serialising collections where the type is known and a possible enhancement to allow using the QueryAttribute for properties on classes used as request objects. Does that sound right?

I believe an object array:
{"value": [ {"a": 1, "b": 2}, {"a": 3, "b": 4} ] }

...should be serialised into the query string as:

?value[0].a=1&value[0].b=2&value[1].a=3&value[1].b=4

This should be fixed in the latest (4.9.20) release on Myget. Recommend closing.

@benjaminhowarth1 any idea when this is available via nuget?

@teresaritorto if you're comfortable with it, you can use the MyGet feed to install the "bleeding edge" release of Refit. Add this to your package repository in Visual Studio: https://www.myget.org/F/refit/api/v3/index.json

Regarding an official Nuget release, I don't know what the release cycle is. @bennor or @onovotny will probably know when they're planning the next release.

@benjaminhowarth1 i'm only seeing 4.7.40 as the latest version in myget, is the correct version to use this fix? thanks so much!

@moliver-bb any version after 4.7.20 should have this fixed, so yes, 4.7.40 should have it. My pleasure! 馃檪

How was this fixed? Do I add the Query attribute to the property declaration (in the request object) now? I'm still getting the .ToString() encoding as Wozzo mentioned

same here, doesn't appear to be working on 5.0.23

Was this page helpful?
0 / 5 - 0 ratings

Related issues

omares picture omares  路  6Comments

SWarnberg picture SWarnberg  路  4Comments

martincostello picture martincostello  路  3Comments

sahinyyurt picture sahinyyurt  路  5Comments

ColKrumpler picture ColKrumpler  路  3Comments