How to disable urlencoding get-params in Refit?
Asked Answered
O

3

6

I use Refit for RestAPI. I need create query strings same api/item?c[]=14&c[]=74

In refit interface I created method

[Get("/item")]
Task<TendersResponse> GetTenders([AliasAs("c")]List<string> categories=null);

And create CustomParameterFormatter

string query = string.Join("&c[]=", values);

CustomParameterFormatter generated string 14&c[]=74

But Refit encoded parameter and generated url api/item?c%5B%5D=14%26c%5B%5D%3D74

How disable this feature?

Overcloud answered 16/11, 2016 at 13:0 Comment(0)
I
5

First of all was your api server able to parse the follow? api/item?c%5B%5D=14%26c%5B%5D%3D74

Encoding is great for avoiding code injection to your server.

This is something Refit is a bit opinionated about, i.e uris should be encoded, the server should be upgraded to read encoded uris.

But this clearly should be a opt-in settings in Refit but it´s not.

So you can currently can do that by using a DelegatingHandler:

/// <summary>
/// Makes sure the query string of an <see cref="System.Uri"/>
/// </summary>
public class UriQueryUnescapingHandler : DelegatingHandler
{   
    public UriQueryUnescapingHandler()
        : base(new HttpClientHandler()) { }
    public UriQueryUnescapingHandler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    { }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var uri = request.RequestUri;
        //You could also simply unescape the whole uri.OriginalString
        //but i don´t recommend that, i.e only fix what´s broken
        var unescapedQuery = Uri.UnescapeDataString(uri.Query);

        var userInfo = string.IsNullOrWhiteSpace(uri.UserInfo) ? "" : $"{uri.UserInfo}@";
        var scheme = string.IsNullOrWhiteSpace(uri.Scheme) ? "" : $"{uri.Scheme}://";

        request.RequestUri = new Uri($"{scheme}{userInfo}{uri.Authority}{uri.AbsolutePath}{unescapedQuery}{uri.Fragment}");
        return base.SendAsync(request, cancellationToken);
    }
}


Refit.RestService.For<IYourService>(new HttpClient(new UriQueryUnescapingHandler()))
Influential answered 26/11, 2016 at 19:29 Comment(0)
R
2

For anyone who stumbles across this old question you can use [QueryUriFormat(UriFormat.Unescaped)] attribute.

Romish answered 20/9, 2021 at 10:52 Comment(0)
C
0

🙋‍♀️ In my case I had to some work on a legacy .NET 2.2 Core ASP app (i.e. couldn't use the fancy attribute mentioned in mmoon's answer.

To complete Ahmed Alejo's answer, and in particular if you're taking the ASP.NET Core DI container road, I've noticed that if I left the two ctors as they were in the original answer, the whole thing was kabooming (i.e. getting the infamous exception: The 'DelegatingHandler' list is invalid because the property 'InnerHandler' of 'handler' is not null).

So what I ended up doing was to not write any ctors, just as below 👇

public class UriQueryUnescapingHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var uri = request.RequestUri;
        var unescapedQuery = Uri.UnescapeDataString(uri.Query);

        var userInfo = string.IsNullOrWhiteSpace(uri.UserInfo) ? string.Empty : $"{uri.UserInfo}@";
        var scheme = string.IsNullOrWhiteSpace(uri.Scheme) ? string.Empty : $"{uri.Scheme}://";

        request.RequestUri = new Uri($"{scheme}{userInfo}{uri.Authority}{uri.AbsolutePath}{unescapedQuery}{uri.Fragment}");
        return base.SendAsync(request, cancellationToken);
    }
}

and then it just works like a charm when you're configuring the services that way 👇:

services.AddTransient<UriQueryUnescapingHandler>();
// whatever other services you need to set up beforehand
services
    .AddRefitClient<IMyRefitService>(myRefitSettings)
    .ConfigureHttpClient(c =>
    {
        // whatever relevant HttpClient-related configuration action goes here
    })
    .AddHttpMessageHandler<UriQueryUnescapingHandler>();
Chloroplast answered 11/3, 2022 at 7:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.