Encoding in routing

Need a solution for some default routing behavior… (using ServiceStack 4.0.40)

(I didn’t want to debate what is the right/wrong approach here. I am happy to accept whatever view the framework has on routing and encoding. I am just looking for a solution to a problem). By hopefully overriding some default behaviour - presumably.

I am consuming some businesses api, and they define a route like this:

https://banana:port/api/anapiky?a=foo&b=bar
where **anapik
y** is a token that they give us to consume their service, that happens to contain an asterisk character.

The DTO I have built to consume this service looks like this:

[Route("/api/{ApiKey}", “GET”)
public class RequestDto
{
public string ApiKey {get;set;}
public string A {get;set;}
public string B {get;set;}
}

The problem is that when I call .ToGetUrl() on an instance of this DTO, I get back this URL:
https:/banana:port/api/anapik%2Ay?a=foo&b=bar

Which is rejected by the service (with 401 - invalid APIKey). However, they accept this URL:
https:/banana:port/api/anapik*y?a=foo&b=bar
Notice the asterisk is now unencoded.

I have no control here on their behaviours.
How do I prevent the asterisk from being encoded in the URL? Can it be done?

Strange, this:

var dto = new RequestDto { ApiKey = "anapik*y", A = "foo", B = "bar" };
var url = dto.ToGetUrl();
url.Print();

Prints:

/api/anapik*y?a=foo&b=bar

But you have a chance to override the default behavior with:

RestRoute.FormatVariable = val => ...;

How would I use RestRoute.FormatVariable and where? any examples?

Can’t find anything about it.

It’s not really meant to be used but it’s an available extension point if required. Like any configuration you would configure it in AppHost.Configure().

Here’s the existing implementation where since you no longer want variables encoded, the new impl would look something like:

RestRoute.FormatVariable = value => {
    if (value == null) return null;
    var valueString = value as string;
    valueString = valueString ?? value.ToJsv();
    return valueString;
};

Which will now prevent any path variables from being encoded.

OK, so this looks to me to be a global extension for the whole service, which would affect reverse routing of all DTO’s. Which, might be troublesome.

I’ll do some testing, but I think I’ll add an new variant of ToPostUrl(filter, filter) that does the reverse routing within a scope that swaps out the current RestRoute.FormatVariable delegate for our new one, does the formatting, and then swaps back the previous delegate. That way I wont pollute all routing.

Of course, longer term, it might be better to customise the RestRoute.FormatVariable for each type of DTO, rather then having a global one? no?

This feature should really never be needed since all path variables should be automatically encoded, but this does allow you to change how it’s formatted if you want to change the default behavior. But we wouldn’t expand this to allow customization per DTO which would add unnecessary overhead and complexity for a rare/unused extensibility point.

If you need more customization you could instead manually construct the URL which you can then use in HTTP Utils or ServiceClient API’s which accept a url, e.g Post(url,requestDto).

Yeah, I could construct URL manually which is very painful and tedious code. Which is why we like reverse routing.
OK, I hear ya, moving on.