I’m trying to write a plugin that will act almost like a reverse proxy sitting infront of a number of services (there are various other ServiceStack plugins in the pipeline so it’s not just a reverse proxy but that is one of it’s jobs). The approach I’m looking at is:
Take incoming request
Find DTO type from incoming request
Lookup Consul using DTO type (services are tagged with this in Consul) to find uri of service that will fulfil this request.
Redirect request to appropriate service.
This is currently in it’s infancy and I’m trying to figure out the best way to achieve this. I am thinking that I will use the pre-defined routes only as it will give a convention that can be used to identify DTO type etc (e.g. Request.RawUrl.SplitOnLast("/")[0]; ) should give DTO type. I’m using the DTO type rather than serializing to strongly typed DTO to avoid needing to add a reference to every possible downstream service.
I’m trying to use a FallbackRoute to catch the requests using the following:
[FallbackRoute("/{Path*}")]
public class Fallback
{
public string Path { get; set; }
}
public class FallBackService : Service
{
public void Any(Fallback fallback){ ... }
}
While testing this I’ve found that any routes that have [xml|json|html|jsv|csv] as first slug and [reply|oneway] as second don’t fallback but instead return a 405. Is there a way round this?
One option that I’ve looked at is having [FallbackRoute(“api/{Path*}”)] as this seems to play well with it but wondering if there’s a way to use the ‘normal’ predefined routes.
Fallback routes are only for providing a fallback to handle unmatched routes which doesn’t sound like it’s what you want.
Why aren’t you just using a normal Global Request Filter? The Request DTO for the service is already matched and populated so you already have the Request DTO for the service which you can use to find the url to direct to, then you can just use the ReirectToUrl extension method to redirect to it, e.g:
As I’m using this as a gateway I was looking to use the fallback route to capture all routes and then redirect them to the downstream service, the alternative I was looking at was having a request filter and having a whitelist to ignore specific routes (e.g. /metadata).
I was trying to avoid this gateway having references to every individual service as there will be many and I want to avoid having to update the gateway if I update an individual service which is why I was looking at a fallback route and using DTO name (rather than serialised DTO object) to lookup the appropriate service using Consul for service discovery.
E.g. this service will run as api.mysite.com and there will be 2 downstream services:
Actually you want this for unknown requests where PreRequestFilters only gets called for matching requests, so you’d need to use a Raw HttpHandler, e.g:
RawHttpHandlers.Add(req => req.PathInfo.Contains("/reply/")
? new CustomActionHandler((httpReq, httpRes) =>
{
var parts = req.PathInfo.Split('/');
var operation = parts[parts.Length - 1];
string redirectUrl = "";
httpRes.RedirectToUrl(redirectUrl);
})
: null);
The different hooks and filters available throughout the Request Pipeline is documented in the Order of Operations docs.
I need to run some other plugins as part of the request so the RawHttpHandler might not be an option.
I’ve got something running with a FallbackRoute of [FallbackRoute(“api/{Path*}”)] which should allow me to achieve the proxy/gateway functionality I need.