为什么 ServiceStack 会给 DTO 增加路由问题的负担?

Why does ServiceStack burden the DTOs with routing concerns?

我正在学习 ServiceStack,通过阅读 this page,有几件事我不太清楚。

所以,考虑这个 DTO 对:

    [Route("/hello")]
    [Route("/hello/{Name}")]
    public class Hello : IReturn<HelloResponse>
    {
        public string Name { get; set; }
    }

    public class HelloResponse
    {
        public string Result { get; set; }
    }

而这项服务:

    public class MyService : Service
    {
        public object Any(Hello request)
        {
            return new HelloResponse { Result = $"Hello, {request.Name}!" };
        }
    }

为什么 Hello 有责任使用标记界面 IReturn<HelloResponse> 指定 return 类型?

这似乎可以从 MyService 的 return 类型推断出来——除了通常使用 object 的 return 类型,这还需要在测试和客户端代码中进行类型转换。为什么?

为什么 Route 属性应用于模型 Hello,而不是实际处理请求的服务 MyService

似乎这两个事实与服务的相关性比与模型的相关性更高。

一方面,阅读服务声明的人会更容易找到与服务相关的信息,而不必在模型中找到它。

另一方面,接受的 HTTP 方法是由服务通过方法命名约定隐式声明的 - 因此关于服务 routing/dispatch 的事实似乎分散在两层之间。

从这个角度来看,我可能期待更多类似的东西:

    // NON-VALID EXAMPLE

    public class Hello
    {
        public string Name { get; set; }
    }

    public class HelloResponse
    {
        public string Result { get; set; }
    }

    public class MyService : Service
    {
        [Route("/hello")]
        [Route("/hello/{Name}")]
        public HelloResponse Any(Hello request)
        {
            return new HelloResponse { Result = $"Hello, {request.Name}!" };
        }
    }

约定背后的原因或设计思想是什么?

(请不要把这仅仅看作是一种批评尝试 - 这个框架有很多我喜欢的地方,我真的在试图理解这些约定背后的想法。)

Why does ServiceStack burden the DTOs with routing concerns?

请注意,在 ServiceStack 中根本不需要路由问题负担,所有用户定义的路由都是可选的,所有客户端都可以使用其自动 pre-defined routes.

调用服务

Why is it the responsibility of Hello to specify the return-type using the marker interface IReturn?

它为像 generic C#/.NET Service Clients 这样的客户端库提供了更好的类型化访问,它们能够重新使用现有的 SericeModel DTO 以启用其最佳类型化 API,而无需任何代码生成,例如:

var client = new JsonServiceClient(baseUrl);
var response = client.Get(new Hello { Name = "World" });

或者,如果您不共享 DTO,它对 Add ServiceStack Reference 生成的客户端也很有用。

服务实现上的 return 类型在 ServiceStack 中没有意义,即没有行为差异,并且会阻止相同的服务实现 returning 相同的响应 DTO,或用自定义 HTTP 响应,例如:

public object Any(Hello request)
{
    return new HelloResponse { Result = $"Hello, {request.Name}!" };
    //...
    return new HttpResult(new HelloResponse { Result = $"Hello, {request.Name}!" }) {
      //... custom
    };
}

both return types adhere to the API's IReturn<HelloResponse> contract

它只对调用 inter-process Services using the older ResolveService method, but for inter-prcess requests it's recommended to use the Service Gateway 有用,它也使用类型 IReturn<T> 接口标记作为其类型 APIs.

路由不是实现细节,它们是您的 public 服务合同的一部分,应该在用于定义服务合同的 DTO 上进行注释。

[Route("/hello")]
[Route("/hello/{Name}")]
public class Hello : IReturn<HelloResponse>
{
    public string Name { get; set; }
}

public class HelloResponse
{
    public string Result { get; set; }
}

.NET ServiceStack 客户端使用它们发送服务客户端请求的位置。

var response = client.Get(new Hello { Name = "World" });

For another, accepted HTTP methods are implicitly declared by the service via method-naming conventions - so it seems like the facts about service routing/dispatch are sort of scattered between two layers.

请参阅 Routing 上的文档,路由定义定义了特定路由在哪些方法上处于活动状态,同时根据请求调用最合适的服务实现,例如:

public object GetJson(Customers request) => ... // ONLY GET JSON Requests
public object Get(Customers request) => ...     // All other GET Requests
public object Post(Customers request) => ...    // ONLY POST Requests
public object Any(Customers request) => ...     // ALL other Requests

What is the reason or the design thinking behind the conventions?

很多这些问题试图模糊你的 API 的显式类型服务契约及其具体实现,在 ServiceStack 中,这些是不同的显式概念,其中关于你的 public 的所有信息服务合同应在您的 implementation-free ServiceModel project.

中维护

请阅读 Background Concepts docs 以熟悉 ServiceStack 的目的和目标。