2

我的问题是...

...我有这样的 DTO

[Route("/route/to/dto/{Id}", "GET")]
public class Foo : IReturn<Bar>
{
  public string Id { get; set; }
}

并且需要使用此签名调用实现该方法的服务

public Bar Get(Foo)

来自请求和/或响应过滤器。我不知道哪个类实现了它(不想知道)。我需要的是类似于下面示例中的 LocalServiceClient 类:

var client = new LocalServiceClient();
Bar bar = client.Get(new Foo());

这个 LocalServiceClient 东西存在吗?JsonServiceClient 有一个非常相似的接口,但是使用它是无用的(我需要调用我自己的服务,我不应该需要额外的往返,甚至到本地主机,只是为了做到这一点)。

我知道来自 Service 类的 ResolveService 方法,但它要求我有一个服务实例并知道哪个类将处理请求。

我认为这个 LocalServiceClient 是可能的,因为我拥有远程客户端(例如 JsonServiceClient)调用服务所需的所有数据——请求 DTO、路由、动词——但找不到如何去做。实际上,它应该比 JsonServiceClient 更容易实现。

JsonServiceClient 会这样做,但必须有更好的方法,使用相同的请求上下文。

我想做什么(如果你不好奇我为什么这样做,请跳过这个)

实际上,我的 DTO 是这样的:

[EmbedRequestedLinks]
[Route("/route/to/dto/{Id}", "GET")]
public class MyResponseDto
{
  public string Id { get; set; }
  public EmbeddableLink<AResponseDto> RelatedResource { get; set; }
  public EmbeddableLink<AnotherResponteDto> AnotherRelatedResource { get; set; }
}

EmbedRequestedLinksAttribute 是一个请求/响应过滤器。此过滤器检查请求中是否存在名为“embed”的查询参数。如果是这样,过滤器需要将参数引用的逗号分隔的相关资源“嵌入”到对该请求的响应中。EmbeddableLink<T> 实例可以通过使用如下扩展方法获得:

1) public static EmbeddableLink<T> ToEmbeddableLink<T>(this IReturn<T> requestDto)
2) public static EmbeddableLink<T> ToEmbeddableLink<T>(this T resource)

假设客户端发出此请求:

GET /route/to/dto/123456?embed=relatedResource HTTP/1.1

将处理此请求的服务将返回 MyResponseDto 的实例,其中包含使用签名 (1) 创建的 EmbeddableLinks。然后我的响应过滤器将看到嵌入查询参数,并将调用相应服务的 Get 方法,将 RelatedResource 替换为 EmbeddableLink 的另一个实例,这次使用扩展方法 (2) 创建:

var client = new LocalServiceClient();
response.RelatedResource = client.Get(response.RelatedResource.RequestDto)
                                 .ToEmbeddableLink();

EmbeddableLink 的序列化例程负责其余的工作。

如果嵌入列表中不包含可嵌入链接,则序列化例程将调用扩展方法 ToUrl(由 ServiceStack 提供),该方法采用动词并将请求 DTO 转换为 URL。在此示例中,客户端将收到以下响应:

{
  "id": "9asc09dcd80a98",
  "relatedResource": { "id": "ioijo0909801", ... },
  "anotherRelatedResource":
  {
    "$link": { "href": "/route/to/another/dto/1sdf89879s" }
  }
}

我知道 ServiceStack 的创建者认为多态请求/响应是坏事,但这种情况对我来说似乎没问题,因为我不是在创建服务,而是在扩展框架以帮助我以我(可能还有其他用户)的方式创建服务ServiceStack) 需要。我还在为 ServiceStack 创建其他超媒体扩展。(希望老板允许我在github上发布这些扩展)

4

2 回答 2

4

如果您真的想这样做,请查看 ServiceStack 的源代码。查看 ServiceManager 和 ServiceController。这些类负责注册和解析服务。您甚至可以使用反射通过静态 EndpointHost.Metadata 动态创建服务,如下所示:

var operation = EndpointHost.Metadata.Operations
                       .FirstOrDefault(x => x.RequestType == typeof(Person));
if (operation != null)
{
    var svc = Activator.CreateInstance(operation.ServiceType);
    var method = operation.ServiceType.GetMethod("Get");
    var response = method.Invoke(svc, new[] { new Person() });
}

这有点工作,但如果有其他代码调用,你会得到 NULL 异常

var httpRequest = RequestContext.Get<IHttpRequest>();

但我不建议这样做。

相反,如果您创建自己的业务服务类来执行所有 CRUD 操作(POST/PUT/GET 等)。然后在它们之上制作 ServiceStack Services 瘦包装器。现在,您可以随时调用自己的服务,而不必担心 HTTP 请求和 ServiceStack。仅在处理 HTTP 请求时使用 ServiceStack 服务

于 2013-08-08T13:40:39.567 回答
3

您可以调用静态 AppHostBase.Resolve() 方法,如此处所示从 MVC 控制器调用 SeviceStack 服务:

var helloService = AppHostBase.Resolve<HelloService>();
helloService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var response = (HelloResponse)helloService.Any(new HelloRequest { Name = User.Identity.Name });

但是,我会采用@kampsj 的方法,使您的 ServiceStack 服务成为您的应用程序服务类的瘦包装器,并且只处理 ServiceStack 服务中的 HTTP/Session 特定内容。

于 2013-08-09T19:55:11.117 回答