5 min read
Using proxies as Slice types.
Learn how to a create custom type to represent your proxy in Slice.
Transmitting a proxy as a service address This section is specific to the IceRPC + Slice integration.
Learn more
This section is specific to the IceRPC + Slice integration.
Learn more
A proxy is a Slice language-mapping construct that allows you to call operations on a remote service using IceRPC. A proxy is not a construct or type in the Slice language itself.
In each programming language, a proxy encapsulates an invocation pipeline and a service address.
If you want to transmit a proxy through a Slice operation, you can easily transmit its service address using the built-in custom type IceRpc::ServiceAddress
:
mode = Slice1
[cs::namespace("IceRpc.Slice")]module IceRpc
/// Represents the address of an RPC service that can be called using ice or icerpc. This custom type is/// compatible with both Slice1 and Slice2.[cs::type("IceRpc.ServiceAddress")]custom ServiceAddress
The recipient can then decode this service address and use it to create a proxy with the correct type. It can also set a suitable invoker and other options. For example:
interface Widget { spin(speed: int32)}
interface WidgetFactory { /// Creates a new @Widget and returns its service address. createWidget() -> IceRpc::ServiceAddress}
// Recipient
ServiceAddress serviceAddress = await widgetFactoryProxy.CreateWidgetAsync();
// Create new Widget proxy. We keep the invoker and encode options of the factory proxy.var widgetProxy = new WidgetProxy( widgetFactoryProxy.Invoker, serviceAddress, widgetFactoryProxy.EncodeOptions);
Representing a proxy in Slice This section is specific to the IceRPC + Slice integration.
Learn more
This section is specific to the IceRPC + Slice integration.
Learn more
Transmitting a service address in Slice works well but results in a fairly untyped API both in Slice and in the mapped programming languages.
A solution is to wrap the service address in a custom Slice type. This allows us to rewrite the example above as follows:
interface Widget { spin(speed: int32)}
interface WidgetFactory { /// Creates a new @Widget and returns a proxy to this new Widget. createWidget() -> WidgetProxy}
// A proxy to a service that implements Widget; it's encoded as a service address.[cs::type("Example.WidgetProxy")]custom WidgetProxy
// Recipient
WidgetProxy widgetProxy = await widgetFactoryProxy.CreateWidgetAsync();
The advantage with this custom proxy approach is we get a typed API and the invoker and other options can be set automatically by the decoding code (see below).
When you define a custom type, you need to provide methods that encode and decode this type in each programming language you want to support. See Custom types for details. As a convenience, the Slice compiler always generates these encode and decode methods for NameProxy. This way, if you decide to create a custom type NameProxy (where Name is the name of a Slice interface), you don't need to implement these methods. And that's exactly what we did in the example above.
Decoding a service address into a proxy This section is specific to the IceRPC + Slice integration.
Learn more
This section is specific to the IceRPC + Slice integration.
Learn more
The decode method generated for NameProxy decodes a service address and then creates:
- on the client side, a proxy with the invoker and
SliceEncodeOptions
of the proxy that sent the request - on the server side, a proxy with a null invoker and null
SliceEncodeOptions
You can override this default behavior by configuring a base proxy
in the ISliceFeature
of your outgoing request features or incoming request features.