2
votes

I'm looking to retain a ton of functionality I used to have in my codebase from the service layer that I exposed previously using OData services but through ServiceStack, assuming I implement the service logic, I don't want to have to make a ton of new DTO's for requests when this is essentially what i'm trying to achieve unless the framework "forces" me to declare a bunch of extra classes for no functional gain ...

    [Route("~/{Type}")]
    public class GetRequest
    {
        public string Type {get; set; }
        public string Select { get; set; }
        public string Expand { get; set; }
        public string Filter { get; set; }
        public string GroupBy { get; set; }
        public string OrderBy { get; set; }
    }

    public ServiceBase<T> : Service
    {
       public virtual IEnumerable<T> Get(GetRequest<T> request) { ... }
    } 

    public FooService : ServiceBase<Foo> 
    { 
       public override IEnumerable<Foo> Get(GetRequest<Foo> request) { ... }
    } 

The only other way I can see to implement this is to basically have to create a FooRequest DTO that inherits from the generic one here and adds nothing.

Whilst this might be the case in some scenarios, for the bulk of the hundreds of endpoints I have to migrate this just seems wasteful and likely will require to me having to result to code generation, something Service Stack claims "isn't needed".

My situation is made worse because I have "multiple data contexts" to consider for example ...

// base implementation for all services, derives from ServiceStack Service
public abstract class ServiceBase<T> : Service { ... }

// core service then one concrete implementation off that 
public class CoreService<T> : ServiceBase<T> { ... }
public CoreFooService : CoreService<Foo> { ... }

/// b2b service then one concrete implementation off of that 
public class B2BService<T> : ServiceBase<T> { ... }
public class BarB2BService : B2BService<Bar> { ... }

... with my OData based implementation I only need to add each new class to add a point of customisation for that type of data in the stack.

With ServiceStack this still seems to be possible regarding service classes (i think, but i'm not clear on how the routing works) ... where I get confused is understanding the request DTOs which are basically the same in all get requests but seemingly not routeable based on some tpye information in the URL.

Ideally I would like to route a standard Request DTO to a service method by a combination of the HTTP verb used and then something like [Route("~/{Context}/{Type}")] in the url (with that being the attribute usage on the DTO).

I get the feeling though that ServiceStack doesn't work like this and is going to require me to define a new DTO for literally every method on every service and i'm going to have to define a bunch of new services that don't exist with no new implementation details in them just to satisfy the frameworks needs.

Or am i missing some trick in how to use the framework here to avoid this work?

1

1 Answers

1
votes

You can have multiple Service base classes but your Request DTO cannot be generic, it has to be a concrete Request DTO, but it can inherit base classes, e.g. All AutoQuery RDBMS Services inherit from QueryDb<T> or QueryDb.

Your Route should start with / (i.e. not ~/) and you could have a single Parameter that accepts any Type:


[Route("/data/{Type}")]
public class GetData
{
    public string Type {get; set; }
    public string Select { get; set; }
    public string Expand { get; set; }
    public string Filter { get; set; }
    public string GroupBy { get; set; }
    public string OrderBy { get; set; }
}

That can be called with:

GET /data/Anything

But your Service should have the same return Type (i.e. adhere to its Service Contract) so a wildcard Service is not going to be useful unless you return the same unstructured Data response like Dictionary<string,object>, List<object>, etc.

I get the feeling though that ServiceStack doesn't work like this and is going to require me to define a new DTO for literally every method on every service and i'm going to have to define a bunch of new services that don't exist with no new implementation details in them just to satisfy the frameworks needs.

Yes ServiceStack Requires every Service is defined by its Request DTO which is the master authority describing that Services contract. This is not just a requirement to appease the Framework, the Request DTO is the message that invokes a Service, which is the only thing generic Service Clients need to send to invoke a Service, which it can't send if it doesn't exist, nor can it have a Typed API (without code-gen) if there are no types.