中转服务概要

中转服务是通过某个 IServiceBroker服务获取的服务,并公开为 RPC 兼容的接口,使服务及其客户端存在于不同的 AppDomains、进程甚至跨计算机(在 Live Share 的情况下)。 中转服务可以从 Visual Studio 主进程或其一些辅助进程中获取,并且可由 Visual Studio 扩展使用其中任何进程。

更多(非中转)Visual Studio 服务可通过IServiceProvider界面获取,如“使用和提供服务”中所述。 此类服务通常仅在主 Visual Studio 进程中可用,但公开的功能集比中转服务更大。

在 Live Share 来宾上运行的 Visual Studio 扩展可以通过访问 Live Share 主机提供的这些服务的子集来提供附加功能。 授权检查通过 Live Share 连接应用,以降低行为不力的 Live Share 来宾损害 Live Share 主机的安全性的风险。 选择通过 Live Share 公开其服务的中转服务作者应注意实施授权检查,如如何提供中转服务中所述

服务代理

Visual Studio 具有一个全局(类似于(可从中检索)GlobalProvider公开其他服务的全局IServiceBroker服务。 也可以通过 MEF 检索它。

可能有其他上下文特定的服务代理由特定的 Visual Studio 功能提供,这些功能希望使用自己的服务之一(或可能抑制某些服务)聚合全局代理。

IServiceBroker一个是(有意)一个黑匣子,它允许客户端获取可能位于本地、在另一进程中或其他计算机上的服务。 Service Broker 可能是一个或多个其他代理的聚合,其中应用了策略。

根据 Visual Studio 进程所处的上下文,此全局服务代理是更改的其他服务代理集的聚合。 进程中的上下文更改可能会更改可能激活的中转服务集。 例如,加载解决方案时,与活动解决方案专门相关的服务可能会可用。 同一服务也可在“打开文件夹”视图中使用,尽管采用不同的支持实现。 服务实现中的更改对于该服务的客户端是透明的,因为这两个实现必须满足相同的协定,但需要客户端在此上下文更改(通过这些更改通知服务 AvailabilityChanged)中重新查询服务以获取新实例。

Service Broker 通常用于获取服务的代理。 也就是说,客户端不直接接收对服务对象的引用,而是接收一个存根,该存根会将所有方法调用转发给服务,并将结果或异常转发回客户端。 它还可能会将服务引发的事件转发到客户端。 在某些情况下,服务可能支持或要求客户端提供一个“目标对象”,该服务可以调用方法以回调客户端。

中转服务容器

必须向服务提供 IBrokeredServiceContainer 服务才能从全局 IServiceBroker获取。 此服务容器不仅负责向服务代理公开服务工厂,还负责控制哪些客户端有权访问该服务,并在访问该服务时通知这些客户端。

中转服务的组合

中转服务由以下元素组成:

  • 声明服务功能并充当服务与其客户端之间的协定的接口。
  • 该接口的实现。
  • 用于 ServiceMoniker 向服务分配名称和版本。
  • 与在必要时处理 RPC 的行为相结合ServiceMoniker的 AServiceRpcDescriptor
  • 用于提供服务工厂的代码
  • 服务注册

服务接口

这可能是标准 .NET 接口(通常用 C# 编写)。 若要允许中转服务客户端和服务存在于不同的进程中并通过 RPC 进行通信,此接口必须遵守服务将使用的限制 ServiceRpcDescriptor 。 这些限制通常包括不允许属性和索引器,大多数或所有方法返回 Task 或另一个异步兼容的返回类型。

中转服务名字对象和描述符

激活服务需要知道其名字对象。 由于名字对象包含在服务的描述符中,因此客户端通常只需处理 。ServiceRpcDescriptor 描述符将添加在中转服务与其客户端之间设置 RPC 连接所需的行为,或在需要时对 RPC 调用进行序列化。Stream

Visual Studio 建议将 ServiceJsonRpcDescriptor 派生类型用于中转服务,当客户端和服务需要 RPC 进行通信时,该类型利用 StreamJsonRpc 库。 StreamJsonRpc 对服务接口应用某些限制,如下 所述

描述符很少需要直接使用。 相反,它通常从VisualStudioServices或提供服务的库获取,然后用作参数。GetProxyAsync

ServiceMonikerServiceJsonRpcDescriptor类都是不可变的,因此可以安全地作为static readonly字段或属性共享。 任何其他 ServiceRpcDescriptor派生类型都应不可变。

A ServiceMoniker 是可序列化的。 无法序列化 A ServiceJsonRpcDescriptor

服务受众

每个中转服务都注册到从 ServiceAudience中选择的标志。 这些标志控制将公开代理服务的客户端和连接。

典型的选择是 ServiceAudience.Local,它将服务公开给 Visual Studio 会话中的任何本地进程。 使用此设置时,即使实时共享会话处于活动状态,服务也始终在本地激活。

ServiceAudience.LiveShareGuest添加标志时,请求中转服务的 Live Share 来宾将通过与 Live Share 主机的远程连接向该中转服务获取代理。

定义的 ServiceAudience 标志的任意组合都是合法的。 LiveShareGuest可以在不同时设置标志的情况下设置Local标志,例如,仅向 Live Share 来宾(来自 Live Share 主机)公开中转服务,并且永远不会在本地可用(客户端和服务在同一进程中)。

RemoteExclusiveClient弃用标志。RemoteExclusiveServer

当客户端请求中转服务时,它不需要知道该服务或 ServiceAudience 服务将激活的位置。 但是,对于记录此值的服务以及正在使用该服务的开发人员了解服务可能激活的位置,以便他们可以预测可能来自该服务的各种上下文以及何时可用的服务,这一点非常有用。

中转客户端的构成

当客户端请求中转服务时,当 null 服务不可用、 ServiceActivationFailedException 服务在激活中失败时引发,或者它获取 服务的代理 时,会返回该服务。 代理是在同一进程中激活中转服务,还是激活客户端或其他代理。 此代理有助于协调本地和远程服务案例中的使用模式,以便客户端无需了解服务所在的位置。