diff --git a/docfx/docs/proxies.md b/docfx/docs/proxies.md index 9546907e..9f5cf6af 100644 --- a/docfx/docs/proxies.md +++ b/docfx/docs/proxies.md @@ -14,6 +14,28 @@ This changes the above example to something like this: [!code-csharp[](../../samples/Proxies.cs#WithProxies)] +## Multiple proxies on one connection + +Do not call static `JsonRpc.Attach` multiple times on the same stream. Each static call creates a distinct instance, and multiple instances cannot safely share one transport. + +The following examples use this second RPC interface in addition to `ICalculator`. + +[!code-csharp[](../../samples/Proxies.cs#MultipleProxiesInterfaces)] + +When you need multiple client proxies over one connection, use one of these patterns: + +1. Create one proxy that implements multiple interfaces at once. + + [!code-csharp[](../../samples/Proxies.cs#MultipleProxiesPattern1)] + +1. Create the connection first, then call instance `Attach` for each proxy. + + [!code-csharp[](../../samples/Proxies.cs#MultipleProxiesPattern2)] + +1. Create the first proxy with the static `Attach` method, then get its instance through and create additional proxies with instance `Attach` calls. + + [!code-csharp[](../../samples/Proxies.cs#MultipleProxiesPattern3)] + ## Proxy traits Generated proxies have the following traits: diff --git a/samples/Proxies.cs b/samples/Proxies.cs index 64cc8c5b..946bb40f 100644 --- a/samples/Proxies.cs +++ b/samples/Proxies.cs @@ -27,6 +27,59 @@ internal partial interface ICalculator } #endregion + #region MultipleProxiesInterfaces + [JsonRpcContract, GenerateShape(IncludeMethods = MethodShapeFlags.PublicInstance)] + internal partial interface IAdvancedCalculator + { + Task MultiplyAsync(int a, int b); + } + #endregion + + static async Task MultipleProxiesOption1(Stream rpcStream) + { + #region MultipleProxiesPattern3 + ICalculator calculator = JsonRpc.Attach(rpcStream); + JsonRpc rpc = ((IJsonRpcClientProxy)calculator).JsonRpc; + IAdvancedCalculator advancedCalculator = rpc.Attach(); + using (calculator as IDisposable) + using (advancedCalculator as IDisposable) + { + int sum = await calculator.AddAsync(2, 5); + int product = await advancedCalculator.MultiplyAsync(2, 5); + } + #endregion + } + + static async Task MultipleProxiesOption2(Stream rpcStream) + { + #region MultipleProxiesPattern2 + using JsonRpc rpc = JsonRpc.Attach(rpcStream); + ICalculator calculator = rpc.Attach(); + IAdvancedCalculator advancedCalculator = rpc.Attach(); + using (calculator as IDisposable) + using (advancedCalculator as IDisposable) + { + int sum = await calculator.AddAsync(2, 5); + int product = await advancedCalculator.MultiplyAsync(2, 5); + } + #endregion + } + + static async Task MultipleProxiesOption3(Stream rpcStream) + { + #region MultipleProxiesPattern1 + using JsonRpc rpc = JsonRpc.Attach(rpcStream); + object combinedProxy = rpc.Attach([typeof(ICalculator), typeof(IAdvancedCalculator)], options: null); + ICalculator calculator = (ICalculator)combinedProxy; + IAdvancedCalculator advancedCalculator = (IAdvancedCalculator)combinedProxy; + using (combinedProxy as IDisposable) + { + int sum = await calculator.AddAsync(2, 5); + int product = await advancedCalculator.MultiplyAsync(2, 5); + } + #endregion + } + partial class ServerWithoutInterface { #region ServerWithoutInterface