Phillip Powers - 272 - May 10, 2014

Register and rerouting routes:  Is there any built-in way to register multiple routes and then have 1 route basically map itself to another?

For example, in a multi-tenant scenario with the following Request DTO:

Route["/api/{Tenant}/resource/{ResourceType}"]
public class TenantRequest : IReturn<TenantResponse>
{
public string Tenant { get; set; }
public string ResourceType { get; set; }
}

I’d like to add a route: /api/tenant1/resourceOne

And have that map to TenantRequest with “Tenant” property set to “tenant1” and “ResourceType” property set to “resourceOne”.

I could probably do this by redirecting the URL, but I’d rather just accept the request and redirect internally to the original service.

Thanks.

Stefan Tsalapatis:

+Demis Bellot
 As I remember from  your previous answers( maybe I have not understood them well  and did not test it yet ) , we can reroute a service call, from Action Request Filters, instead to call another service from  the first one. This would be very useful in a tenant’s scenario, If I have understood well. Can you remind us  if it is true or not and  how.

Not sure if this is what you’re after, but the automated routing strategy is documented here:
https://github.com/ServiceStack/ServiceStack/wiki/Routing#auto-route-generation-strategies

Note: [Route("/api/{Tenant}/resource/{ResourceType}")] doesn’t match:
/api/tenant1/resourceOne, it would match:
/api/tenant1/resource/resourceOne

The definition you’ll need is: [Route("/api/{Tenant}/{ResourceType}")]

Phillip Powers:

No, that’s not quite what I meant.

Here’s the scenario:  I have one “central” web service that I want to be accessible to multiple tenants. However, what’s considered a “subresource” to this central web resource is a first-class resource to each individual tenant. Because each tenant might have different resources, the {Tenant}/{ResourceType} would be ambiguous, so those have to be absolute paths and not variables.

Basically what I think I’m after is for a way to create specialized versions of a pre-existing route:

Route["/api/{Tenant}/resourceA/{SubResourceType}"]
Route["/api/TenantOne/ResourceOne", “Tenant=TenantOne;SubResourceType=ResourceOne”]
public class TenantRequest : IReturn<TenantResponse>
{
public string Tenant { get; set; }
public string SubResourceType { get; set; }
}

That way I could have a separate “api/{Tenant}/resourceB/…” handled by a different “central” web service and use the same tenant-specific routing conventions without there being any sort of ambiguity.

I’m still having a hard time trying to figure out whats needed.
Maybe if we can map from exact routes to the target Request DTO and to highlight what ambiguity you want to avoid, is this right?

/api/TenantOne/ResourceOne => new TenantRequest { Tenant = “TenantOne”, SubResourceType = “ResourceOne” }
/api/TenantTwo/ResourceTwo => new TenantRequest { Tenant = “TenantTwo”, SubResourceType = “ResourceTwo” }

Do you also know how to call a Service internally with:

using (var service = base.ResolveService<ServiceOne>())
{
    var response = service.Any(request.ConvertTo<InternalRequest>());
}

Phillip Powers:

The ambiguity is possible when the single TenantRequest can map to multiple centralized services:

/api/TenantOne/TenantOneSubType -> /api/tenant/{TenantName}/ResourceA/{SubResourceType}  (“SubResourceType = TenantOneSubType”)
/api/TenantTwo/TenantTwoSubType -> /api/tenant/{TenantName}/ResourceB/{SubResourceType}  (“SubResourceType = TenantTwoSubType”)

I was wondering if there was any way to specify these route specializations - essentially what’s variable to the centralized services are constants to the tenants. Basically, add a route to an existing DTO and provide constants for some subset of variables.

Your suggestion of ResolveService<>() might work, though. I think I should be able to have the tenant-specific requests hit a single service and then do my own routing from there?  

Thanks!

Not from an action filter, but from inside the Service you can use base.ResolveService<TService>() to delegate into another service.

Phillip Powers:

Created a Pull Request with desired functionality: https://github.com/ServiceStack/ServiceStack/pull/916

It’s pretty straight-forward, and the unit tests I added make it pretty clear.  This lets you include constants that are to be bound to a REST request’s variables, making the intermediate service unnecessary.

Sir Thomas:

+Phillip Powers could you post a couple of sample sevice files online for us to take a look at, along with the sample urls you’d want?  I am curious to visualize the intended feature