diff --git a/.gitignore b/.gitignore index 9088c8ec2..3dcd6d3d2 100644 --- a/.gitignore +++ b/.gitignore @@ -250,4 +250,5 @@ paket-files/ # JetBrains Rider .idea/ -*.sln.iml \ No newline at end of file +*.sln.iml +*.project.lock.json \ No newline at end of file diff --git a/NuGet/WampSharp.WebSocket4Net.nuspec b/NuGet/WampSharp.WebSocket4Net.nuspec index 251f57bc8..2239f9408 100644 --- a/NuGet/WampSharp.WebSocket4Net.nuspec +++ b/NuGet/WampSharp.WebSocket4Net.nuspec @@ -15,9 +15,7 @@ - - - + WampSharp.WebSocket4Net diff --git a/NuGet/WampSharp.nuspec b/NuGet/WampSharp.nuspec index e2fd61d3c..33f5eac0e 100644 --- a/NuGet/WampSharp.nuspec +++ b/NuGet/WampSharp.nuspec @@ -10,6 +10,7 @@ + @@ -21,6 +22,7 @@ + @@ -37,6 +39,7 @@ + @@ -53,6 +56,7 @@ + WampSharp diff --git a/src/mono/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj b/src/mono/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj index db2cebf2f..87ae0a647 100644 --- a/src/mono/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj +++ b/src/mono/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj @@ -46,7 +46,7 @@ - ..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True @@ -54,12 +54,18 @@ Properties\AssemblyInfo.cs + + WAMP2\V2\Fluent\IWebSocket4NetTransportSyntax.cs + WAMP2\V2\Fluent\WebSocket4NetActivator.cs WAMP2\V2\Fluent\WebSocket4NetChannelFactoryExtensions.cs + + WAMP2\V2\Fluent\WebSocket4NetTransportSyntax.cs + WebSocket4Net\WebSocket4NetBinaryConnection.cs diff --git a/src/mono/Default/WampSharp.WebSocket4Net/packages.config b/src/mono/Default/WampSharp.WebSocket4Net/packages.config index 50f0d072c..230303925 100644 --- a/src/mono/Default/WampSharp.WebSocket4Net/packages.config +++ b/src/mono/Default/WampSharp.WebSocket4Net/packages.config @@ -1,5 +1,5 @@ - + diff --git a/src/mono/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj b/src/mono/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj index ca39e6be9..a789153a8 100644 --- a/src/mono/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj +++ b/src/mono/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj @@ -59,7 +59,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/Samples/WAMP1/WampSharp.CraClientSample/packages.config b/src/mono/Samples/WAMP1/WampSharp.CraClientSample/packages.config index cd4b177ad..3ab5628f2 100644 --- a/src/mono/Samples/WAMP1/WampSharp.CraClientSample/packages.config +++ b/src/mono/Samples/WAMP1/WampSharp.CraClientSample/packages.config @@ -2,5 +2,5 @@ - + diff --git a/src/mono/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj b/src/mono/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj index 203ea4af7..5f7fa5588 100644 --- a/src/mono/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj +++ b/src/mono/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj @@ -60,7 +60,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/Samples/WAMP1/WampSharp.RpcClientSample/packages.config b/src/mono/Samples/WAMP1/WampSharp.RpcClientSample/packages.config index cd4b177ad..3ab5628f2 100644 --- a/src/mono/Samples/WAMP1/WampSharp.RpcClientSample/packages.config +++ b/src/mono/Samples/WAMP1/WampSharp.RpcClientSample/packages.config @@ -2,5 +2,5 @@ - + diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj b/src/mono/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj index f647313c2..3d283d753 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj @@ -76,7 +76,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.Callee/packages.config b/src/mono/Samples/WAMP2/WampSharp.Samples.Callee/packages.config index df6d87db6..246b2dc2c 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.Callee/packages.config +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.Callee/packages.config @@ -6,5 +6,5 @@ - + diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj b/src/mono/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj index 10785557b..56376fab8 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj @@ -76,7 +76,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.Caller/packages.config b/src/mono/Samples/WAMP2/WampSharp.Samples.Caller/packages.config index df6d87db6..246b2dc2c 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.Caller/packages.config +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.Caller/packages.config @@ -6,5 +6,5 @@ - + diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.EdgeJs/WampSharp.Samples.EdgeJs.csproj b/src/mono/Samples/WAMP2/WampSharp.Samples.EdgeJs/WampSharp.Samples.EdgeJs.csproj index 2af0ee265..0042686f9 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.EdgeJs/WampSharp.Samples.EdgeJs.csproj +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.EdgeJs/WampSharp.Samples.EdgeJs.csproj @@ -79,7 +79,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.EdgeJs/packages.config b/src/mono/Samples/WAMP2/WampSharp.Samples.EdgeJs/packages.config index c088044a8..fcb7e2002 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.EdgeJs/packages.config +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.EdgeJs/packages.config @@ -7,5 +7,5 @@ - + diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj b/src/mono/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj index 9dc0455b5..571bd09ab 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj @@ -76,7 +76,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config b/src/mono/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config index df6d87db6..246b2dc2c 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config @@ -6,5 +6,5 @@ - + diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj b/src/mono/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj index f1eb3ad97..24ed84ae7 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj @@ -72,7 +72,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config b/src/mono/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config index d955552c0..9cae0f8ed 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config @@ -5,5 +5,5 @@ - + diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj b/src/mono/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj index 4c7f90a56..d7bd8d59a 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj @@ -54,7 +54,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config b/src/mono/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config index 50f0d072c..230303925 100644 --- a/src/mono/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config +++ b/src/mono/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config @@ -1,5 +1,5 @@ - + diff --git a/src/mono/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj b/src/mono/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj index 212f5e96c..92011e156 100644 --- a/src/mono/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj +++ b/src/mono/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj @@ -19,15 +19,16 @@ full false bin\Debug\ - TRACE;DEBUG;NET45;MONO + TRACE;DEBUG;NET45;MONO WAMPCRA prompt 4 + false pdbonly true bin\Release\ - TRACE;NET45;MONO + TRACE;NET45;MONO WAMPCRA prompt 4 @@ -60,6 +61,10 @@ True + + ..\..\packages\System.ValueTuple.4.0.0-rc3-24212-01\lib\netstandard1.1\System.ValueTuple.dll + True + @@ -136,6 +141,12 @@ Integration\RpcProxies\IErrorsService.cs + + Integration\RpcProxies\ILongValueTuplesServiceProxy.cs + + + Integration\RpcProxies\INamedTupleComplexResultService.cs + Integration\RpcProxies\ISlowSquareService.cs @@ -151,12 +162,27 @@ Integration\RpcServices\ErrorsService.cs + + Integration\RpcServices\LongValueTuplesCalleeService.cs + + + Integration\RpcServices\LongValueTuplesService.cs + + + Integration\RpcServices\NamedTupleComplexResultService.cs + + + Integration\RpcServices\PositionalTupleComplexResultService.cs + Integration\RpcServices\SlowSquareService.cs Integration\RpcServices\TimeService.cs + + Integration\PubSubSubjectTupleTests.cs + Integration\SerializedValue.cs diff --git a/src/mono/Tests/WampSharp.Tests.Wampv2/packages.config b/src/mono/Tests/WampSharp.Tests.Wampv2/packages.config index 5c753a17e..35da4bee2 100644 --- a/src/mono/Tests/WampSharp.Tests.Wampv2/packages.config +++ b/src/mono/Tests/WampSharp.Tests.Wampv2/packages.config @@ -4,4 +4,5 @@ + diff --git a/src/mono/WampSharp.Default.Client/WampSharp.Default.Client.csproj b/src/mono/WampSharp.Default.Client/WampSharp.Default.Client.csproj index 5616b9d90..c99718c0a 100644 --- a/src/mono/WampSharp.Default.Client/WampSharp.Default.Client.csproj +++ b/src/mono/WampSharp.Default.Client/WampSharp.Default.Client.csproj @@ -51,7 +51,7 @@ - ..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/WampSharp.Default.Client/packages.config b/src/mono/WampSharp.Default.Client/packages.config index cd4b177ad..3ab5628f2 100644 --- a/src/mono/WampSharp.Default.Client/packages.config +++ b/src/mono/WampSharp.Default.Client/packages.config @@ -2,5 +2,5 @@ - + diff --git a/src/mono/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj b/src/mono/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj index 1b3df1234..239f5f8a8 100644 --- a/src/mono/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj +++ b/src/mono/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj @@ -54,7 +54,7 @@ - ..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/mono/WampSharp.WAMP1.Default/packages.config b/src/mono/WampSharp.WAMP1.Default/packages.config index 755dd83c3..3c44de189 100644 --- a/src/mono/WampSharp.WAMP1.Default/packages.config +++ b/src/mono/WampSharp.WAMP1.Default/packages.config @@ -3,5 +3,5 @@ - + diff --git a/src/mono/WampSharp/WampSharp.csproj b/src/mono/WampSharp/WampSharp.csproj index 24e86f9ce..f96636706 100644 --- a/src/mono/WampSharp/WampSharp.csproj +++ b/src/mono/WampSharp/WampSharp.csproj @@ -59,8 +59,12 @@ True - - ..\packages\Microsoft.Tpl.Dataflow.4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll + + ..\packages\System.Threading.Tasks.Dataflow.4.6.0\lib\netstandard1.1\System.Threading.Tasks.Dataflow.dll + True + + + ..\packages\System.ValueTuple.4.0.0-rc3-24212-01\lib\netstandard1.1\System.ValueTuple.dll True @@ -283,6 +287,24 @@ Core\Utilities\ThreadSafeRandom.cs + + Core\Utilities\ValueTuple\ValueTuple.cs + + + Core\Utilities\ValueTuple\ValueTupleArrayConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleDictionaryConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleDictionaryConverterBuilder.cs + + + Core\Utilities\ValueTuple\ValueTupleTypeExtensions.cs + Properties\AssemblyInfo.cs @@ -295,6 +317,9 @@ WAMP2\V2\Api\CalleeProxy\CachedCalleeProxyInterceptor.cs + + WAMP2\V2\Api\CalleeProxy\Callbacks\Async\OperationResultExtractor.cs + WAMP2\V2\Api\CalleeProxy\CalleeProxyBase.cs @@ -334,9 +359,15 @@ WAMP2\V2\Api\CalleeProxy\ClientInvocationHandler.cs + + WAMP2\V2\Api\CalleeProxy\Callbacks\Async\ValueTupleValueExtractor.cs + WAMP2\V2\Api\CalleeProxy\WampIncompatibleCalleeProxyMethodException.cs + + WAMP2\V2\Api\Rx\WampTupleTopicSubject.cs + WAMP2\V2\Api\DelegatePubSub\EventHandlerGenerator.cs @@ -358,9 +389,21 @@ WAMP2\V2\Api\DelegatePubSub\WampSubscriberRegistrar.cs + + WAMP2\V2\Api\Rx\IWampEventValueTupleConverter.cs + + + WAMP2\V2\Api\Rx\SerializedValueFormatter.cs + + + WAMP2\V2\Api\Rx\WampEventValueTupleConverter.cs + WAMP2\V2\Authentication\Restriction\WampRestrictedUris.cs + + WAMP2\V2\Core\ArgumentUnpackerHelper.cs + WAMP2\V2\Core\Contracts\WampAuthenticationMethods.cs @@ -532,6 +575,9 @@ WAMP2\V2\Client\Session\WampAuthenticationNotImplementedException.cs + + WAMP2\V2\Core\Contracts\WampInvalidArgumentException.cs + WAMP2\V2\Core\Contracts\WampInvokePolicy.cs @@ -799,9 +845,6 @@ WAMP2\V2\Rpc\Callee\Reflection\ICalleeRegistrationInterceptor.cs - - WAMP2\V2\Rpc\Callee\Reflection\CallerProgress.cs - WAMP2\V2\Rpc\Callee\Reflection\MethodInfoValidation.cs @@ -811,6 +854,27 @@ WAMP2\V2\Rpc\Callee\Reflection\ProgressiveAsyncMethodInfoRpcOperation.cs + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\EmptyResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\IWampResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\MultiResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\NamedTupleExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\PositionalTupleExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\SingleResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\WampResultExtractor.cs + WAMP2\V2\Rpc\Dealer\ExactRpcOperationCatalog.cs diff --git a/src/mono/WampSharp/packages.config b/src/mono/WampSharp/packages.config index d15a875a6..cfb220def 100644 --- a/src/mono/WampSharp/packages.config +++ b/src/mono/WampSharp/packages.config @@ -1,6 +1,7 @@ - + + diff --git a/src/net40/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj b/src/net40/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj index 1c15f5ca1..12fcaee9f 100644 --- a/src/net40/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj +++ b/src/net40/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj @@ -46,7 +46,7 @@ - ..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True @@ -54,12 +54,18 @@ Properties\AssemblyInfo.cs + + WAMP2\V2\Fluent\IWebSocket4NetTransportSyntax.cs + WAMP2\V2\Fluent\WebSocket4NetActivator.cs WAMP2\V2\Fluent\WebSocket4NetChannelFactoryExtensions.cs + + WAMP2\V2\Fluent\WebSocket4NetTransportSyntax.cs + WebSocket4Net\WebSocket4NetBinaryConnection.cs diff --git a/src/net40/Default/WampSharp.WebSocket4Net/packages.config b/src/net40/Default/WampSharp.WebSocket4Net/packages.config index aaed1eaf2..a9341805a 100644 --- a/src/net40/Default/WampSharp.WebSocket4Net/packages.config +++ b/src/net40/Default/WampSharp.WebSocket4Net/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/src/net40/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj b/src/net40/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj index a0d7c593a..3bb0b1148 100644 --- a/src/net40/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj +++ b/src/net40/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj @@ -65,7 +65,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/Samples/WAMP1/WampSharp.CraClientSample/packages.config b/src/net40/Samples/WAMP1/WampSharp.CraClientSample/packages.config index 6c5b9bfd2..585b78e11 100644 --- a/src/net40/Samples/WAMP1/WampSharp.CraClientSample/packages.config +++ b/src/net40/Samples/WAMP1/WampSharp.CraClientSample/packages.config @@ -7,5 +7,5 @@ - + \ No newline at end of file diff --git a/src/net40/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj b/src/net40/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj index 0e9d532a6..5063646c0 100644 --- a/src/net40/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj +++ b/src/net40/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj @@ -55,7 +55,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/Samples/WAMP1/WampSharp.RpcClientSample/packages.config b/src/net40/Samples/WAMP1/WampSharp.RpcClientSample/packages.config index dd2fadccd..ffdcd9559 100644 --- a/src/net40/Samples/WAMP1/WampSharp.RpcClientSample/packages.config +++ b/src/net40/Samples/WAMP1/WampSharp.RpcClientSample/packages.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj b/src/net40/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj index 956de01d4..95b8f6981 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj @@ -83,7 +83,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.Callee/packages.config b/src/net40/Samples/WAMP2/WampSharp.Samples.Callee/packages.config index eb198a249..4e4288622 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.Callee/packages.config +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.Callee/packages.config @@ -11,5 +11,5 @@ - + \ No newline at end of file diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj b/src/net40/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj index c6da87f69..2b63d2998 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj @@ -83,7 +83,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.Caller/packages.config b/src/net40/Samples/WAMP2/WampSharp.Samples.Caller/packages.config index eb198a249..4e4288622 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.Caller/packages.config +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.Caller/packages.config @@ -11,5 +11,5 @@ - + \ No newline at end of file diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj b/src/net40/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj index 4d4653b5b..16cbd4913 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj @@ -82,7 +82,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config b/src/net40/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config index eb198a249..4e4288622 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config @@ -11,5 +11,5 @@ - + \ No newline at end of file diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj b/src/net40/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj index 30960e295..10b20ba7e 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj @@ -79,7 +79,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config b/src/net40/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config index fca5bfda0..8611c2c11 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config @@ -10,5 +10,5 @@ - + \ No newline at end of file diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj b/src/net40/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj index e6efdd009..44547f4a8 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj @@ -57,7 +57,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config b/src/net40/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config index 830a106cb..dd35a73fe 100644 --- a/src/net40/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config +++ b/src/net40/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config @@ -4,5 +4,5 @@ - + \ No newline at end of file diff --git a/src/net40/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj b/src/net40/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj index 779c1e7c6..211c1f8bc 100644 --- a/src/net40/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj +++ b/src/net40/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj @@ -135,6 +135,12 @@ Integration\RpcProxies\IErrorsService.cs + + Integration\RpcProxies\ILongValueTuplesServiceProxy.cs + + + Integration\RpcProxies\INamedTupleComplexResultService.cs + Integration\RpcProxies\ISlowSquareService.cs @@ -150,12 +156,27 @@ Integration\RpcServices\ErrorsService.cs + + Integration\RpcServices\LongValueTuplesCalleeService.cs + + + Integration\RpcServices\LongValueTuplesService.cs + + + Integration\RpcServices\NamedTupleComplexResultService.cs + + + Integration\RpcServices\PositionalTupleComplexResultService.cs + Integration\RpcServices\SlowSquareService.cs Integration\RpcServices\TimeService.cs + + Integration\PubSubSubjectTupleTests.cs + Integration\SerializedValue.cs diff --git a/src/net40/WampSharp.Default.Client/WampSharp.Default.Client.csproj b/src/net40/WampSharp.Default.Client/WampSharp.Default.Client.csproj index b86537ca3..fb8418e64 100644 --- a/src/net40/WampSharp.Default.Client/WampSharp.Default.Client.csproj +++ b/src/net40/WampSharp.Default.Client/WampSharp.Default.Client.csproj @@ -51,7 +51,7 @@ - ..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/WampSharp.Default.Client/packages.config b/src/net40/WampSharp.Default.Client/packages.config index e5f7d731a..44153b851 100644 --- a/src/net40/WampSharp.Default.Client/packages.config +++ b/src/net40/WampSharp.Default.Client/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/src/net40/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj b/src/net40/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj index d00c88acb..3eca2a74f 100644 --- a/src/net40/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj +++ b/src/net40/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj @@ -54,7 +54,7 @@ - ..\packages\WebSocket4Net.0.15.0-beta4\lib\net40\WebSocket4Net.dll + ..\packages\WebSocket4Net.0.15.0-beta5\lib\net40\WebSocket4Net.dll True diff --git a/src/net40/WampSharp.WAMP1.Default/packages.config b/src/net40/WampSharp.WAMP1.Default/packages.config index 782750eb0..4ffb17b34 100644 --- a/src/net40/WampSharp.WAMP1.Default/packages.config +++ b/src/net40/WampSharp.WAMP1.Default/packages.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/src/net40/WampSharp/WampSharp.csproj b/src/net40/WampSharp/WampSharp.csproj index 7435b4430..951d8b381 100644 --- a/src/net40/WampSharp/WampSharp.csproj +++ b/src/net40/WampSharp/WampSharp.csproj @@ -290,6 +290,24 @@ Core\Utilities\ThreadSafeRandom.cs + + Core\Utilities\ValueTuple\ValueTuple.cs + + + Core\Utilities\ValueTuple\ValueTupleArrayConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleDictionaryConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleDictionaryConverterBuilder.cs + + + Core\Utilities\ValueTuple\ValueTupleTypeExtensions.cs + Properties\AssemblyInfo.cs @@ -302,6 +320,9 @@ WAMP2\V2\Api\CalleeProxy\CachedCalleeProxyInterceptor.cs + + WAMP2\V2\Api\CalleeProxy\Callbacks\Async\OperationResultExtractor.cs + WAMP2\V2\Api\CalleeProxy\CalleeProxyBase.cs @@ -341,9 +362,15 @@ WAMP2\V2\Api\CalleeProxy\ClientInvocationHandler.cs + + WAMP2\V2\Api\CalleeProxy\Callbacks\Async\ValueTupleValueExtractor.cs + WAMP2\V2\Api\CalleeProxy\WampIncompatibleCalleeProxyMethodException.cs + + WAMP2\V2\Api\Rx\WampTupleTopicSubject.cs + WAMP2\V2\Api\DelegatePubSub\EventHandlerGenerator.cs @@ -365,9 +392,21 @@ WAMP2\V2\Api\DelegatePubSub\WampSubscriberRegistrar.cs + + WAMP2\V2\Api\Rx\IWampEventValueTupleConverter.cs + + + WAMP2\V2\Api\Rx\SerializedValueFormatter.cs + + + WAMP2\V2\Api\Rx\WampEventValueTupleConverter.cs + WAMP2\V2\Authentication\Restriction\WampRestrictedUris.cs + + WAMP2\V2\Core\ArgumentUnpackerHelper.cs + WAMP2\V2\Core\Contracts\WampAuthenticationMethods.cs @@ -539,6 +578,9 @@ WAMP2\V2\Client\Session\WampAuthenticationNotImplementedException.cs + + WAMP2\V2\Core\Contracts\WampInvalidArgumentException.cs + WAMP2\V2\Core\Contracts\WampInvokePolicy.cs @@ -806,9 +848,6 @@ WAMP2\V2\Rpc\Callee\Reflection\ICalleeRegistrationInterceptor.cs - - WAMP2\V2\Rpc\Callee\Reflection\CallerProgress.cs - WAMP2\V2\Rpc\Callee\Reflection\MethodInfoValidation.cs @@ -818,6 +857,27 @@ WAMP2\V2\Rpc\Callee\Reflection\ProgressiveAsyncMethodInfoRpcOperation.cs + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\EmptyResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\IWampResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\MultiResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\NamedTupleExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\PositionalTupleExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\SingleResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\WampResultExtractor.cs + WAMP2\V2\Rpc\Dealer\ExactRpcOperationCatalog.cs diff --git a/src/net45/.nuget/NuGet.exe b/src/net45/.nuget/NuGet.exe index 9ca66594f..6bb79fe53 100644 Binary files a/src/net45/.nuget/NuGet.exe and b/src/net45/.nuget/NuGet.exe differ diff --git a/src/net45/Default/WampSharp.NewtonsoftJson/Newtonsoft/JTokenMessageParser.cs b/src/net45/Default/WampSharp.NewtonsoftJson/Newtonsoft/JTokenMessageParser.cs index 901972df8..ccefccc37 100644 --- a/src/net45/Default/WampSharp.NewtonsoftJson/Newtonsoft/JTokenMessageParser.cs +++ b/src/net45/Default/WampSharp.NewtonsoftJson/Newtonsoft/JTokenMessageParser.cs @@ -26,12 +26,12 @@ public WampMessage Parse(string text) { try { - mLogger.DebugFormat("Trying to parse message {0}", text); + mLogger.DebugFormat("Trying to parse message {JsonMessage}", text); return mMessageFormatter.Parse(JToken.Parse(text)); } catch (Exception ex) { - mLogger.ErrorFormat(ex, "Failed parsing message {0}", text); + mLogger.ErrorFormat(ex, "Failed parsing message {JsonMessage}", text); throw; } } @@ -45,7 +45,7 @@ public string Format(WampMessage message) mSerializer.Serialize(jsonWriter, array); string result = writer.ToString(); - mLogger.DebugFormat("Formatted message {0}", result); + mLogger.DebugFormat("Formatted message {JsonMessage}", result); return result; } diff --git a/src/net45/Default/WampSharp.NewtonsoftMsgpack/MsgPack/MessagePackParser.cs b/src/net45/Default/WampSharp.NewtonsoftMsgpack/MsgPack/MessagePackParser.cs index 4885685bb..cb0e3c15b 100644 --- a/src/net45/Default/WampSharp.NewtonsoftMsgpack/MsgPack/MessagePackParser.cs +++ b/src/net45/Default/WampSharp.NewtonsoftMsgpack/MsgPack/MessagePackParser.cs @@ -32,13 +32,19 @@ public WampMessage Parse(byte[] raw) { try { - mLogger.Debug(() => string.Format("Trying to parse msgpack message: {0}", - Convert.ToBase64String(raw))); + if (mLogger.IsDebugEnabled()) + { + mLogger.DebugFormat("Trying to parse msgpack message: {MsgPackMessage}", + Convert.ToBase64String(raw)); + } JToken token = JToken.Load(reader); - mLogger.Debug(() => string.Format("Parsed msgpack message: {0}", - token.ToString(Formatting.None))); + if (mLogger.IsDebugEnabled()) + { + mLogger.DebugFormat("Parsed msgpack message: {Message}", + token.ToString(Formatting.None)); + } WampMessage message = mMessageFormatter.Parse(token); @@ -46,7 +52,7 @@ public WampMessage Parse(byte[] raw) } catch (Exception ex) { - mLogger.ErrorFormat(ex, "Failed parsing msgpack message: {0}", + mLogger.ErrorFormat(ex, "Failed parsing msgpack message: {MsgPackMessage}", Convert.ToBase64String(raw)); throw; @@ -59,8 +65,11 @@ public byte[] Format(WampMessage message) { object[] array = mMessageFormatter.Format(message); - mLogger.Debug(() => string.Format("Formatting message: {0}", - JToken.FromObject(array).ToString(Formatting.None))); + if (mLogger.IsDebugEnabled()) + { + mLogger.DebugFormat("Formatting message: {Message}", + JToken.FromObject(array).ToString(Formatting.None)); + } using (MemoryStream memoryStream = new MemoryStream()) { @@ -70,9 +79,12 @@ public byte[] Format(WampMessage message) memoryStream.Position = 0; byte[] result = memoryStream.ToArray(); - mLogger.Debug(() => string.Format("Formatted message: {0}", - Convert.ToBase64String(result))); - + if (mLogger.IsDebugEnabled()) + { + mLogger.DebugFormat("Formatted message: {MsgPackMessage}", + Convert.ToBase64String(result)); + } + return result; } } diff --git a/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/IWebSocket4NetTransportSyntax.cs b/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/IWebSocket4NetTransportSyntax.cs new file mode 100644 index 000000000..e55701599 --- /dev/null +++ b/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/IWebSocket4NetTransportSyntax.cs @@ -0,0 +1,10 @@ +using System; +using SuperSocket.ClientEngine; + +namespace WampSharp.V2.Fluent +{ + public interface IWebSocket4NetTransportSyntax : ChannelFactorySyntax.ITransportSyntax + { + ChannelFactorySyntax.ITransportSyntax SetSecurityOptions(Action configureSecurityOptions); + } +} \ No newline at end of file diff --git a/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetActivator.cs b/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetActivator.cs index 8d0954288..fbdd6cfe4 100644 --- a/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetActivator.cs +++ b/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetActivator.cs @@ -1,4 +1,5 @@ using System; +using SuperSocket.ClientEngine; using WampSharp.Core.Listener; using WampSharp.V2.Binding; using WampSharp.WebSocket4Net; @@ -26,6 +27,8 @@ public WebSocket4NetActivator(string serverAddress) : { } + public Action SecurityOptionsConfigureAction { get; set; } + public IControlledWampConnection Activate(IWampBinding binding) { Func> factory = @@ -63,7 +66,19 @@ protected IControlledWampConnection CreateBinaryConnection(I protected IControlledWampConnection CreateTextConnection(IWampTextBinding textBinding) { - return new WebSocket4NetTextConnection(mWebSocketFactory(textBinding.Name), textBinding); + return new WebSocket4NetTextConnection(ActivateWebSocket(textBinding), textBinding); + } + + private WebSocket ActivateWebSocket(IWampTextBinding textBinding) + { + WebSocket webSocket = mWebSocketFactory(textBinding.Name); + + if (SecurityOptionsConfigureAction != null) + { + SecurityOptionsConfigureAction(webSocket.Security); + } + + return webSocket; } } } \ No newline at end of file diff --git a/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetChannelFactoryExtensions.cs b/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetChannelFactoryExtensions.cs index f9894e3d6..9a292a3e3 100644 --- a/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetChannelFactoryExtensions.cs +++ b/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetChannelFactoryExtensions.cs @@ -7,13 +7,11 @@ public static class WebSocket4NetChannelFactoryExtensions /// connect to a given address. /// /// The server's address. - public static ChannelFactorySyntax.ITransportSyntax WebSocketTransport(this ChannelFactorySyntax.IRealmSyntax realmSyntax, string address) + public static IWebSocket4NetTransportSyntax WebSocketTransport(this ChannelFactorySyntax.IRealmSyntax realmSyntax, string address) { - ChannelState state = realmSyntax.State; - - state.ConnectionActivator = new WebSocket4NetActivator(address); + WebSocket4NetActivator activator = new WebSocket4NetActivator(address); - return state; + return GetWebSocketSyntax(realmSyntax, activator); } /// @@ -21,13 +19,22 @@ public static ChannelFactorySyntax.ITransportSyntax WebSocketTransport(this Chan /// WebSocket4Net factory. /// /// The custom to use to create the WebSocket. - public static ChannelFactorySyntax.ITransportSyntax WebSocketTransport(this ChannelFactorySyntax.IRealmSyntax realmSyntax, WebSocket4NetFactory factory) + public static IWebSocket4NetTransportSyntax WebSocketTransport(this ChannelFactorySyntax.IRealmSyntax realmSyntax, WebSocket4NetFactory factory) + { + WebSocket4NetActivator activator = new WebSocket4NetActivator(factory); + + return GetWebSocketSyntax(realmSyntax, activator); + } + + private static IWebSocket4NetTransportSyntax GetWebSocketSyntax(ChannelFactorySyntax.IRealmSyntax realmSyntax, WebSocket4NetActivator activator) { ChannelState state = realmSyntax.State; - state.ConnectionActivator = new WebSocket4NetActivator(factory); + state.ConnectionActivator = activator; + + WebSocket4NetTransportSyntax syntax = new WebSocket4NetTransportSyntax(state); - return state; + return syntax; } } } \ No newline at end of file diff --git a/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetTransportSyntax.cs b/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetTransportSyntax.cs new file mode 100644 index 000000000..b0cd63638 --- /dev/null +++ b/src/net45/Default/WampSharp.WebSocket4Net/WAMP2/V2/Fluent/WebSocket4NetTransportSyntax.cs @@ -0,0 +1,29 @@ +using System; +using SuperSocket.ClientEngine; + +namespace WampSharp.V2.Fluent +{ + internal class WebSocket4NetTransportSyntax : IWebSocket4NetTransportSyntax + { + private readonly ChannelState mState; + + public WebSocket4NetTransportSyntax(ChannelState state) + { + mState = state; + } + + public ChannelState State + { + get + { + return mState; + } + } + + public ChannelFactorySyntax.ITransportSyntax SetSecurityOptions(Action configureSecurityOptions) + { + ((WebSocket4NetActivator) State.ConnectionActivator).SecurityOptionsConfigureAction = configureSecurityOptions; + return State; + } + } +} \ No newline at end of file diff --git a/src/net45/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj b/src/net45/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj index 188112722..c8756b4a2 100644 --- a/src/net45/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj +++ b/src/net45/Default/WampSharp.WebSocket4Net/WampSharp.WebSocket4Net.csproj @@ -46,14 +46,16 @@ - ..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True + + diff --git a/src/net45/Default/WampSharp.WebSocket4Net/packages.config b/src/net45/Default/WampSharp.WebSocket4Net/packages.config index e33e78aa2..d7216bcb2 100644 --- a/src/net45/Default/WampSharp.WebSocket4Net/packages.config +++ b/src/net45/Default/WampSharp.WebSocket4Net/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/src/net45/Default/WampSharp.WebSocket4Net/project.json b/src/net45/Default/WampSharp.WebSocket4Net/project.json index a47a8d9c1..aa4e9cb98 100644 --- a/src/net45/Default/WampSharp.WebSocket4Net/project.json +++ b/src/net45/Default/WampSharp.WebSocket4Net/project.json @@ -15,8 +15,7 @@ }, "dependencies": { "WampSharp": { "target": "project" }, - "WebSocket4Net": "0.15.0-beta4", - "SuperSocket.ClientEngine.Core": "0.8.0.6" + "WebSocket4Net": "0.15.0-beta5" } } } diff --git a/src/net45/Extensions/WampSharp.RawSocket/WAMP2/V2/Fluent/RawSocketChannelFactoryExtensions.cs b/src/net45/Extensions/WampSharp.RawSocket/WAMP2/V2/Fluent/RawSocketChannelFactoryExtensions.cs index 59a42ebba..444efd6a1 100644 --- a/src/net45/Extensions/WampSharp.RawSocket/WAMP2/V2/Fluent/RawSocketChannelFactoryExtensions.cs +++ b/src/net45/Extensions/WampSharp.RawSocket/WAMP2/V2/Fluent/RawSocketChannelFactoryExtensions.cs @@ -14,7 +14,7 @@ public static class RawSocketChannelFactoryExtensions /// The port of the listening router public static IRawSocketTransportSyntax RawSocketTransport(this ChannelFactorySyntax.IRealmSyntax realmSyntax, string address, int port) { - return InnterRawSocket(realmSyntax, client => client.ConnectAsync(address, port)); + return InnerRawSocket(realmSyntax, client => client.ConnectAsync(address, port)); } /// @@ -24,7 +24,7 @@ public static IRawSocketTransportSyntax RawSocketTransport(this ChannelFactorySy /// The port of the listening router public static IRawSocketTransportSyntax RawSocketTransport(this ChannelFactorySyntax.IRealmSyntax realmSyntax, IPAddress[] addresses, int port) { - return InnterRawSocket(realmSyntax, client => client.ConnectAsync(addresses, port)); + return InnerRawSocket(realmSyntax, client => client.ConnectAsync(addresses, port)); } /// @@ -34,10 +34,10 @@ public static IRawSocketTransportSyntax RawSocketTransport(this ChannelFactorySy /// The port of the listening router public static IRawSocketTransportSyntax RawSocketTransport(this ChannelFactorySyntax.IRealmSyntax realmSyntax, IPAddress address, int port) { - return InnterRawSocket(realmSyntax, client => client.ConnectAsync(address, port)); + return InnerRawSocket(realmSyntax, client => client.ConnectAsync(address, port)); } - private static IRawSocketTransportSyntax InnterRawSocket(ChannelFactorySyntax.IRealmSyntax realmSyntax, Func connector) + private static IRawSocketTransportSyntax InnerRawSocket(ChannelFactorySyntax.IRealmSyntax realmSyntax, Func connector) { ChannelState state = realmSyntax.State; diff --git a/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/IWebSocketTransportSyntax.cs b/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/IWebSocketTransportSyntax.cs new file mode 100644 index 000000000..c914c43fc --- /dev/null +++ b/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/IWebSocketTransportSyntax.cs @@ -0,0 +1,11 @@ +using System; +using System.Net.WebSockets; + +namespace WampSharp.V2.Fluent +{ + public interface IWebSocketTransportSyntax : ChannelFactorySyntax.ITransportSyntax + { + ChannelFactorySyntax.ITransportSyntax SetClientWebSocketOptions + (Action configureClientWebSocketOptions); + } +} \ No newline at end of file diff --git a/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketActivator.cs b/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketActivator.cs index d5b03ec3a..d202ab9d3 100644 --- a/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketActivator.cs +++ b/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketActivator.cs @@ -1,4 +1,5 @@ using System; +using System.Net.WebSockets; using WampSharp.Core.Listener; using WampSharp.V2.Binding; using WampSharp.WebSockets; @@ -12,8 +13,13 @@ internal class WebSocketActivator : IWampConnectionActivator public WebSocketActivator(Uri serverAddress) { mServerAddress = serverAddress; + WebSocketFactory = () => new ClientWebSocket(); } + public WebSocketFactory WebSocketFactory { get; set; } + + public Action ConfigureOptions { get; set; } + public IControlledWampConnection Activate(IWampBinding binding) { Func> factory = @@ -46,12 +52,24 @@ private IControlledWampConnection GetConnectionFactory(IWamp protected IControlledWampConnection CreateBinaryConnection(IWampBinaryBinding binaryBinding) { - return new ControlledBinaryWebSocketConnection(mServerAddress, binaryBinding); + return new ControlledBinaryWebSocketConnection(ActivateWebSocket(), mServerAddress, binaryBinding); } protected IControlledWampConnection CreateTextConnection(IWampTextBinding textBinding) { - return new ControlledTextWebSocketConnection(mServerAddress, textBinding); + return new ControlledTextWebSocketConnection(ActivateWebSocket(), mServerAddress, textBinding); + } + + private ClientWebSocket ActivateWebSocket() + { + ClientWebSocket result = WebSocketFactory(); + + if (ConfigureOptions != null) + { + ConfigureOptions(result.Options); + } + + return result; } } } diff --git a/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketChannelFactoryExtensions.cs b/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketChannelFactoryExtensions.cs index fa61ed866..627854df7 100644 --- a/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketChannelFactoryExtensions.cs +++ b/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketChannelFactoryExtensions.cs @@ -1,17 +1,38 @@ using System; +using System.Net.WebSockets; +using WampSharp.WebSockets; namespace WampSharp.V2.Fluent { public static class WebSocketChannelFactoryExtensions { - public static ChannelFactorySyntax.ITransportSyntax WebSocketTransport( + public static IWebSocketTransportSyntax WebSocketTransport( this ChannelFactorySyntax.IRealmSyntax realmSyntax, Uri address) + { + IWampConnectionActivator connectionActivator = new WebSocketActivator(address); + + return GetWebSocketTransportSyntax(realmSyntax, connectionActivator); + } + + public static IWebSocketTransportSyntax WebSocketTransport( + this ChannelFactorySyntax.IRealmSyntax realmSyntax, WebSocketFactory webSocketFactory, Uri address) + { + WebSocketActivator connectionActivator = new WebSocketActivator(address) {WebSocketFactory = webSocketFactory}; + + return GetWebSocketTransportSyntax(realmSyntax, connectionActivator); + } + + private static IWebSocketTransportSyntax GetWebSocketTransportSyntax + (ChannelFactorySyntax.IRealmSyntax realmSyntax, + IWampConnectionActivator connectionActivator) { ChannelState state = realmSyntax.State; - state.ConnectionActivator = new WebSocketActivator(address); + state.ConnectionActivator = connectionActivator; + + WebSocketTransportSyntax result = new WebSocketTransportSyntax(state); - return state; + return result; } } } \ No newline at end of file diff --git a/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketTransportSyntax.cs b/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketTransportSyntax.cs new file mode 100644 index 000000000..5a8130fca --- /dev/null +++ b/src/net45/Extensions/WampSharp.WebSockets/WAMP2/V2/Fluent/WebSocketTransportSyntax.cs @@ -0,0 +1,29 @@ +using System; +using System.Net.WebSockets; + +namespace WampSharp.V2.Fluent +{ + internal class WebSocketTransportSyntax : IWebSocketTransportSyntax + { + private readonly ChannelState mState; + + public WebSocketTransportSyntax(ChannelState state) + { + mState = state; + } + + public ChannelFactorySyntax.ITransportSyntax SetClientWebSocketOptions(Action configureClientWebSocketOptions) + { + ((WebSocketActivator) State.ConnectionActivator).ConfigureOptions = configureClientWebSocketOptions; + return this; + } + + public ChannelState State + { + get + { + return mState; + } + } + } +} \ No newline at end of file diff --git a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/BinaryWebSocketConnection.cs b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/BinaryWebSocketConnection.cs index 7c8939ec2..72bc9343b 100644 --- a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/BinaryWebSocketConnection.cs +++ b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/BinaryWebSocketConnection.cs @@ -16,8 +16,8 @@ public BinaryWebSocketConnection(WebSocket webSocket, IWampBinaryBinding binding) : - base(addressUri, binding.Name, binding) + protected BinaryWebSocketConnection(ClientWebSocket clientWebSocket, Uri addressUri, IWampBinaryBinding binding) : + base(clientWebSocket, addressUri, binding.Name, binding) { mBinding = binding; } diff --git a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/ControlledBinaryWebSocketConnection.cs b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/ControlledBinaryWebSocketConnection.cs index d92e2cfc3..4bd8d00b7 100644 --- a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/ControlledBinaryWebSocketConnection.cs +++ b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/ControlledBinaryWebSocketConnection.cs @@ -1,4 +1,5 @@ using System; +using System.Net.WebSockets; using WampSharp.Core.Listener; using WampSharp.V2.Binding; @@ -6,7 +7,11 @@ namespace WampSharp.WebSockets { public class ControlledBinaryWebSocketConnection : BinaryWebSocketConnection, IControlledWampConnection { - public ControlledBinaryWebSocketConnection(Uri addressUri, IWampBinaryBinding binding) : base(addressUri, binding) + public ControlledBinaryWebSocketConnection(Uri addressUri, IWampBinaryBinding binding) : this(new ClientWebSocket(), addressUri, binding) + { + } + + public ControlledBinaryWebSocketConnection(ClientWebSocket clientWebSocket, Uri addressUri, IWampBinaryBinding binding) : base(clientWebSocket, addressUri, binding) { } diff --git a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/ControlledTextWebSocketConnection.cs b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/ControlledTextWebSocketConnection.cs index 4d1cf0803..786da5599 100644 --- a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/ControlledTextWebSocketConnection.cs +++ b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/ControlledTextWebSocketConnection.cs @@ -1,6 +1,5 @@ using System; using System.Net.WebSockets; -using System.Threading.Tasks; using WampSharp.Core.Listener; using WampSharp.V2.Binding; @@ -8,7 +7,11 @@ namespace WampSharp.WebSockets { public class ControlledTextWebSocketConnection : TextWebSocketConnection, IControlledWampConnection { - public ControlledTextWebSocketConnection(Uri addressUri, IWampTextBinding binding) : base(addressUri, binding) + public ControlledTextWebSocketConnection(Uri addressUri, IWampTextBinding binding) : this(new ClientWebSocket(), addressUri, binding) + { + } + + public ControlledTextWebSocketConnection(ClientWebSocket clientWebSocket, Uri addressUri, IWampTextBinding binding) : base(clientWebSocket, addressUri, binding) { } diff --git a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/TextWebSocketConnection.cs b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/TextWebSocketConnection.cs index 8fa873783..5ba939bef 100644 --- a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/TextWebSocketConnection.cs +++ b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/TextWebSocketConnection.cs @@ -17,8 +17,8 @@ public TextWebSocketConnection(WebSocket webSocket, IWampTextBinding b mBinding = binding; } - protected TextWebSocketConnection(Uri addressUri, IWampTextBinding binding) : - base(addressUri, binding.Name, binding) + protected TextWebSocketConnection(ClientWebSocket clientWebSocket, Uri addressUri, IWampTextBinding binding) : + base(clientWebSocket, addressUri, binding.Name, binding) { mBinding = binding; } diff --git a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/WebSocketConnection.cs b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/WebSocketConnection.cs index 567f582ae..65347bbf2 100644 --- a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/WebSocketConnection.cs +++ b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/WebSocketConnection.cs @@ -27,10 +27,10 @@ public WebSocketConnection(WebSocket webSocket, IWampStreamingMessageParser parser) : - this(new ClientWebSocket(), parser, null, null) + protected WebSocketConnection(ClientWebSocket clientWebSocket, Uri addressUri, string protocolName, IWampStreamingMessageParser parser) : + this(clientWebSocket, parser, null, null) { - ClientWebSocket.Options.AddSubProtocol(protocolName); + clientWebSocket.Options.AddSubProtocol(protocolName); mAddressUri = addressUri; } diff --git a/src/net45/Extensions/WampSharp.WebSockets/WebSocket/WebSocketFactory.cs b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/WebSocketFactory.cs new file mode 100644 index 000000000..edca3b7a7 --- /dev/null +++ b/src/net45/Extensions/WampSharp.WebSockets/WebSocket/WebSocketFactory.cs @@ -0,0 +1,9 @@ +using System.Net.WebSockets; + +namespace WampSharp.WebSockets +{ + /// + /// A delegate that creates a new instance of a . + /// + public delegate ClientWebSocket WebSocketFactory(); +} \ No newline at end of file diff --git a/src/net45/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj b/src/net45/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj index fe463c995..808d8c4a5 100644 --- a/src/net45/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj +++ b/src/net45/Samples/WAMP1/WampSharp.CraClientSample/WampSharp.CraClientSample.csproj @@ -62,7 +62,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/Samples/WAMP1/WampSharp.CraClientSample/packages.config b/src/net45/Samples/WAMP1/WampSharp.CraClientSample/packages.config index 3c5d0c4e1..72eb02832 100644 --- a/src/net45/Samples/WAMP1/WampSharp.CraClientSample/packages.config +++ b/src/net45/Samples/WAMP1/WampSharp.CraClientSample/packages.config @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/src/net45/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj b/src/net45/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj index 5fea9f0f2..d86fe371b 100644 --- a/src/net45/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj +++ b/src/net45/Samples/WAMP1/WampSharp.RpcClientSample/WampSharp.RpcClientSample.csproj @@ -63,7 +63,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/Samples/WAMP1/WampSharp.RpcClientSample/packages.config b/src/net45/Samples/WAMP1/WampSharp.RpcClientSample/packages.config index 3c5d0c4e1..72eb02832 100644 --- a/src/net45/Samples/WAMP1/WampSharp.RpcClientSample/packages.config +++ b/src/net45/Samples/WAMP1/WampSharp.RpcClientSample/packages.config @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/Program.cs b/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/Program.cs index 1a29479c5..cb6c70d69 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/Program.cs +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/Program.cs @@ -128,7 +128,7 @@ private static IEnumerable GetSampleOperations(Type sampleTyp .Where(x => x.IsDefined(typeof (WampProcedureAttribute), true))) { string procedure = method.GetCustomAttribute().Procedure; - yield return new SyncMethodInfoRpcOperation(instance, method, procedure); + yield return new SyncMethodInfoRpcOperation(() => instance, method, procedure); } foreach (Type nestedType in diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj b/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj index 96e9f5038..d2b0e4114 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/WampSharp.Samples.Callee.csproj @@ -79,7 +79,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/packages.config b/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/packages.config index 7f79e5080..9992ab29f 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/packages.config +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Callee/packages.config @@ -9,5 +9,5 @@ - + \ No newline at end of file diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj b/src/net45/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj index 61bdb4017..e5880f490 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Caller/WampSharp.Samples.Caller.csproj @@ -79,7 +79,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Caller/packages.config b/src/net45/Samples/WAMP2/WampSharp.Samples.Caller/packages.config index 7f79e5080..9992ab29f 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Caller/packages.config +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Caller/packages.config @@ -9,5 +9,5 @@ - + \ No newline at end of file diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.EdgeJs/WampSharp.Samples.EdgeJs.csproj b/src/net45/Samples/WAMP2/WampSharp.Samples.EdgeJs/WampSharp.Samples.EdgeJs.csproj index 578367e8b..a234a7b42 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.EdgeJs/WampSharp.Samples.EdgeJs.csproj +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.EdgeJs/WampSharp.Samples.EdgeJs.csproj @@ -82,7 +82,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.EdgeJs/packages.config b/src/net45/Samples/WAMP2/WampSharp.Samples.EdgeJs/packages.config index d3ae1d480..0eb98fcdf 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.EdgeJs/packages.config +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.EdgeJs/packages.config @@ -10,5 +10,5 @@ - + \ No newline at end of file diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj b/src/net45/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj index 7938846ad..ec15027c7 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Publisher/WampSharp.Samples.Publisher.csproj @@ -79,7 +79,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config b/src/net45/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config index 7f79e5080..9992ab29f 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Publisher/packages.config @@ -9,5 +9,5 @@ - + \ No newline at end of file diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj b/src/net45/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj index 789db5931..250845c03 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Subscriber/WampSharp.Samples.Subscriber.csproj @@ -75,7 +75,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config b/src/net45/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config index db23c7fa5..d1c1d803a 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.Subscriber/packages.config @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj b/src/net45/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj index 48e02f7ed..fe1c17174 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.WampCra.Client/WampSharp.Samples.WampCra.Client.csproj @@ -57,7 +57,7 @@ - ..\..\..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\..\..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config b/src/net45/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config index a056c84da..b7ac8e31e 100644 --- a/src/net45/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config +++ b/src/net45/Samples/WAMP2/WampSharp.Samples.WampCra.Client/packages.config @@ -4,5 +4,5 @@ - + \ No newline at end of file diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/CallerDealerTests.cs b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/CallerDealerTests.cs index 401f6adca..1c73e6cfa 100644 --- a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/CallerDealerTests.cs +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/CallerDealerTests.cs @@ -149,6 +149,289 @@ public async Task ComplexServiceAddComplex() Assert.That(ci, Is.EqualTo(8)); } + + // TODO: Move these to a separate file +#if !NET40 + [Test] + public async Task ComplexServiceTupleSplitName() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + IPositionalTupleComplexResultService proxy = + channel.RealmProxy.Services.GetCalleeProxyPortable(); + + var splitName = proxy.SplitName("Homer Simpson"); + // var (firstName, surName) = proxy.SplitName("Homer Simpson"); + string firstName = splitName.Item1; + string surName = splitName.Item2; + + Assert.That(firstName, Is.EqualTo("Homer")); + Assert.That(surName, Is.EqualTo("Simpson")); + } + + [Test] + public async Task ComplexServiceTupleSplitNameTask() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + IPositionalTupleComplexResultService proxy = + channel.RealmProxy.Services.GetCalleeProxyPortable(); + + var splitName = await proxy.SplitNameAsync("Homer Simpson"); + // var (firstName, surName) = await proxy.SplitNameAsync("Homer Simpson"); + string firstName = splitName.Item1; + string surName = splitName.Item2; + + Assert.That(firstName, Is.EqualTo("Homer")); + Assert.That(surName, Is.EqualTo("Simpson")); + } + + [Test] + public async Task ComplexServiceAddComplex_TupleCalleeProxy() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + INamedTupleComplexResultService proxy = + channel.RealmProxy.Services.GetCalleeProxyPortable(); + + int c; + int ci; + ValueTuple result = proxy.AddComplex(2, 3, 4, 5); + c = result.Item1; + ci = result.Item2; + //var (c, ci) = proxy.AddComplex(2, 3, 4, 5); + + Assert.That(c, Is.EqualTo(6)); + Assert.That(ci, Is.EqualTo(8)); + } + + + [Test] + public async Task ComplexServiceAddComplex_TupleCalleeProxyTask() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + INamedTupleComplexResultService proxy = + channel.RealmProxy.Services.GetCalleeProxyPortable(); + + int c; + int ci; + ValueTuple result = await proxy.AddComplexAsync(2, 3, 4, 5); + c = result.Item1; + ci = result.Item2; + //var (c, ci) = await proxy.AddComplexAsync(2, 3, 4, 5); + + Assert.That(c, Is.EqualTo(6)); + Assert.That(ci, Is.EqualTo(8)); + } + + + [Test] + public async Task ComplexNamedTupleServiceAddComplex() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + IComplexResultService proxy = + channel.RealmProxy.Services.GetCalleeProxyPortable(); + + int c; + int ci; + proxy.AddComplex(2, 3, 4, 5, out c, out ci); + + Assert.That(c, Is.EqualTo(6)); + Assert.That(ci, Is.EqualTo(8)); + } + + [Test] + public async Task ComplexPositionalTupleServiceAddComplex() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + MockRawCallback callback = new MockRawCallback(); + + Dictionary argumentsKeywords = + new Dictionary() + { + {"a", 2}, + {"ai", 3}, + {"b", 4}, + {"bi", 5} + }; + + channel.RealmProxy.RpcCatalog.Invoke + (callback, + new CallOptions(), + "com.myapp.add_complex", + new object[0], + argumentsKeywords); + + Assert.That(callback.Arguments.Select(x => x.Deserialize()), + Is.EquivalentTo(new[] {6, 8})); + } + + [Test] + public async Task LongPositionalTupleServiceCalleeProxy() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + ILongValueTuplesServiceProxy proxy = + channel.RealmProxy.Services.GetCalleeProxyPortable(); + + string name = "Homer Simpson"; + + //(string item1, string item2, string item3, string item4, string item5, string item6, string item7, string item8, string item9, string item10, int length) = + // proxy.GetLongPositionalTuple(name); + ValueTuple> expr_3E = + proxy.GetLongPositionalTuple(name); + + string item1 = expr_3E.Item1; + string item2 = expr_3E.Item2; + string item3 = expr_3E.Item3; + string item4 = expr_3E.Item4; + string item5 = expr_3E.Item5; + string item6 = expr_3E.Item6; + string item7 = expr_3E.Item7; + string item8 = expr_3E.Rest.Item1; + string item9 = expr_3E.Rest.Item2; + string item10 = expr_3E.Rest.Item3; + int length = expr_3E.Rest.Item4; + + Assert.That(item1, Is.EqualTo(name + " " + 0)); + Assert.That(item10, Is.EqualTo(name + " " + 9)); + Assert.That(length, Is.EqualTo(name.Length)); + } + + [Test] + public async Task LongKeywordTupleServiceCalleeProxy() + { + WampPlayground playground = new WampPlayground(); + + CallerCallee dualChannel = await playground.GetCallerCalleeDualChannel(); + + IWampChannel calleeChannel = dualChannel.CalleeChannel; + + var registration = + await calleeChannel.RealmProxy.RpcCatalog.Register(new LongValueTuplesService.KeywordTupleOperation(), + new RegisterOptions()); + + IWampChannel callerChannel = dualChannel.CallerChannel; + + ILongValueTuplesServiceProxy proxy = + callerChannel.RealmProxy.Services.GetCalleeProxyPortable(); + + string name = "Homer Simpson"; + + //(string item1, string item2, string item3, string item4, string item5, string item6, string item7, string item8, int count, string item9, string item10) = + // proxy.GetLongPositionalTuple(name); + ValueTuple < string, string, string, string, string, string, string, ValueTuple> expr_3E = + proxy.GetLongKeywordTuple(name); + + string item1 = expr_3E.Item1; + string item2 = expr_3E.Item2; + string item3 = expr_3E.Item3; + string item4 = expr_3E.Item4; + string item5 = expr_3E.Item5; + string item6 = expr_3E.Item6; + string item7 = expr_3E.Item7; + string item8 = expr_3E.Rest.Item1; + int length = expr_3E.Rest.Item2; + string item9 = expr_3E.Rest.Item3; + string item10 = expr_3E.Rest.Item4; + + Assert.That(item1, Is.EqualTo(name + " " + 0)); + Assert.That(item10, Is.EqualTo(name + " " + 9)); + Assert.That(length, Is.EqualTo(name.Length)); + } + + [Test] + public async Task LongPositionalTupleServiceCallee() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + MockRawCallback callback = new MockRawCallback(); + + string name = "Homer Simpson"; + + channel.RealmProxy.RpcCatalog.Invoke + (callback, + new CallOptions(), + "com.myapp.get_long_positional_tuple", + new object[] { name }, + new Dictionary()); + + int count = callback.Arguments.Count() - 1; + + Assert.That(callback.Arguments.Take(count).Select(x => x.Deserialize()), + Is.EquivalentTo(Enumerable.Range(1, 10).Select(index => name + " " + index))); + + Assert.That(callback.Arguments.Last().Deserialize(), + Is.EqualTo(name.Length)); + + Assert.That(callback.ArgumentsKeywords, + Is.Null); + } + + [Test] + public async Task LongKeywordTupleServiceCallee() + { + WampPlayground playground = new WampPlayground(); + + var channel = await SetupService(playground); + + MockRawCallback callback = new MockRawCallback(); + + string name = "Homer Simpson"; + + channel.RealmProxy.RpcCatalog.Invoke + (callback, + new CallOptions(), + "com.myapp.get_long_keyword_tuple", + new object[] { name }, + new Dictionary()); + + int count = callback.Arguments.Count() - 1; + + Dictionary resultDictionary = + callback.ArgumentsKeywords.Where(x => x.Key.StartsWith("item")) + .ToDictionary(x => x.Key, x => (object)x.Value.Deserialize()); + + resultDictionary["length"] = callback.ArgumentsKeywords["length"].Deserialize(); + + Dictionary expectedDicionary = + Enumerable.Range(1, 10) + .ToDictionary(index => "item" + index, + index => (object) (name + " " + index)); + + expectedDicionary["length"] = name.Length; + + Assert.That(callback.ArgumentsKeywords.Keys, + Is.EquivalentTo(expectedDicionary.Keys)); + + Assert.That(resultDictionary, + Is.EquivalentTo(expectedDicionary)); + + Assert.That(callback.Arguments, + Is.Empty); + } + +#endif + [Test] public async Task ComplexServiceSplitName() { diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/PubSubSubjectTupleTests.cs b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/PubSubSubjectTupleTests.cs new file mode 100644 index 000000000..272e50c96 --- /dev/null +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/PubSubSubjectTupleTests.cs @@ -0,0 +1,388 @@ +#if !NET40 +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using SystemEx; +using Newtonsoft.Json; +using NUnit.Framework; +using WampSharp.Core.Serialization; +using WampSharp.Tests.Wampv2.TestHelpers.Integration; +using WampSharp.V2; +using WampSharp.V2.Client; +using WampSharp.V2.Core; +using WampSharp.V2.Core.Contracts; +using WampSharp.V2.PubSub; + +namespace WampSharp.Tests.Wampv2.Integration +{ + public class PubSubSubjectTupleTests + { + [Test] + public async Task PositionalTupleObservableOnNextPublishesEventWithPositionalArguments() + { + WampPlayground playground = new WampPlayground(); + + PublisherSubscriber dualChannel = await playground.GetPublisherSubscriberDualChannel(); + IWampChannel publisher = dualChannel.Publisher; + IWampChannel subscriber = dualChannel.Subscriber; + + var subject = + publisher.RealmProxy.Services.GetSubject + ("com.myapp.mytopic2", + new MyPositionalTupleEventConverter()); + + IWampTopicProxy topicProxy = + subscriber.RealmProxy.TopicContainer.GetTopicByUri("com.myapp.mytopic2"); + + MyCustomSubscriber myCustomSubscriber = new MyCustomSubscriber(); + + IAsyncDisposable subscribe = + await topicProxy.Subscribe(myCustomSubscriber, + new SubscribeOptions()); + + // subject.OnNext(("Hello", 37, 23)); + subject.OnNext(ValueTuple.Create("Hello", 37, 23)); + + Assert.That(myCustomSubscriber.ArgumentsKeywords, Is.Null.Or.Empty); + + ISerializedValue[] arguments = myCustomSubscriber.Arguments; + + Assert.That(arguments[0].Deserialize(), Is.EqualTo("Hello")); + Assert.That(arguments[1].Deserialize(), Is.EqualTo(37)); + Assert.That(arguments[2].Deserialize(), Is.EqualTo(23)); + } + + [Test] + public async Task KeywordTupleObservableOnNextPublishesEventWithPositionalArguments() + { + WampPlayground playground = new WampPlayground(); + + PublisherSubscriber dualChannel = await playground.GetPublisherSubscriberDualChannel(); + IWampChannel publisher = dualChannel.Publisher; + IWampChannel subscriber = dualChannel.Subscriber; + + var subject = + publisher.RealmProxy.Services.GetSubject + ("com.myapp.topic2", + new MyKeywordTupleEventConverter()); + + IWampTopicProxy topicProxy = + subscriber.RealmProxy.TopicContainer.GetTopicByUri("com.myapp.topic2"); + + MyCustomSubscriber myCustomSubscriber = new MyCustomSubscriber(); + + IAsyncDisposable subscribe = + await topicProxy.Subscribe(myCustomSubscriber, + new SubscribeOptions()); + + MyClass instance = new MyClass() + { + Counter = 1, + Foo = new[] { 1, 2, 3 } + }; + + // subject.OnNext((37, 23, "Hello", instance)) + subject.OnNext(ValueTuple.Create(37, 23, "Hello", instance)); + + Assert.That(myCustomSubscriber.Arguments, Is.Empty); + + IDictionary argumentsKeywords = + myCustomSubscriber.ArgumentsKeywords; + + Assert.That(argumentsKeywords["number1"].Deserialize(), Is.EqualTo(37)); + Assert.That(argumentsKeywords["number2"].Deserialize(), Is.EqualTo(23)); + Assert.That(argumentsKeywords["c"].Deserialize(), Is.EqualTo("Hello")); + Assert.That(argumentsKeywords["d"].Deserialize(), Is.EqualTo(instance)); + } + + [Test] + public async Task SubscriberGetsArgumentsArrayEventAsPositionalTuple() + { + WampPlayground playground = new WampPlayground(); + + PublisherSubscriber dualChannel = await playground.GetPublisherSubscriberDualChannel(); + IWampChannel publisher = dualChannel.Publisher; + IWampChannel subscriber = dualChannel.Subscriber; + + var subject = + subscriber.RealmProxy.Services.GetSubject + ("com.myapp.topic2", + new MyPositionalTupleEventConverter()); + + MyPositionalSubscriber mySubscriber = new MyPositionalSubscriber(); + + subject.Subscribe(mySubscriber); + + IWampTopicProxy topicProxy = + publisher.RealmProxy.TopicContainer.GetTopicByUri("com.myapp.topic2"); + + long? publish = + await topicProxy.Publish(new PublishOptions(), new object[] + { + "Hello", + 47, + 23, + }); + + Assert.That(mySubscriber.Number1, Is.EqualTo(47)); + Assert.That(mySubscriber.Number2, Is.EqualTo(23)); + Assert.That(mySubscriber.C, Is.EqualTo("Hello")); + } + + [Test] + public async Task SubscriberGetsArgumentsKeywordsEventAsKeywordTuple() + { + WampPlayground playground = new WampPlayground(); + + PublisherSubscriber dualChannel = await playground.GetPublisherSubscriberDualChannel(); + IWampChannel publisher = dualChannel.Publisher; + IWampChannel subscriber = dualChannel.Subscriber; + + var subject = + subscriber.RealmProxy.Services.GetSubject + ("com.myapp.topic2", + new MyKeywordTupleEventConverter()); + + MyKeywordSubscriber mySubscriber = new MyKeywordSubscriber(); + + subject.Subscribe(mySubscriber); + + IWampTopicProxy topicProxy = + publisher.RealmProxy.TopicContainer.GetTopicByUri("com.myapp.topic2"); + + MyClass instance = new MyClass() + { + Counter = 1, + Foo = new[] { 1, 2, 3 } + }; + + long? publish = + await topicProxy.Publish(new PublishOptions(), + new object[0], + new Dictionary() + { + {"number1", 47}, + {"d", instance}, + {"c", "Hello"}, + {"number2", 23}, + }); + + Assert.That(mySubscriber.Number1, Is.EqualTo(47)); + Assert.That(mySubscriber.Number2, Is.EqualTo(23)); + Assert.That(mySubscriber.C, Is.EqualTo("Hello")); + Assert.That(mySubscriber.D, Is.EqualTo(instance)); + } + + public class MyCustomSubscriber : LocalSubscriber + { + private EventDetails mDetails; + private ISerializedValue[] mArguments; + private IDictionary mArgumentsKeywords; + + public MyCustomSubscriber() : base() + { + } + + public override LocalParameter[] Parameters + { + get { return new LocalParameter[0]; } + } + + public EventDetails Details + { + get { return mDetails; } + } + + public ISerializedValue[] Arguments + { + get { return mArguments; } + } + + public IDictionary ArgumentsKeywords + { + get { return mArgumentsKeywords; } + } + + protected override void InnerEvent(IWampFormatter formatter, long publicationId, EventDetails details, TMessage[] arguments, + IDictionary argumentsKeywords) + { + if (arguments != null) + { + mArguments = arguments.Select(x => new SerializedValue(formatter, x)).ToArray(); + } + + if (argumentsKeywords != null) + { + mArgumentsKeywords = + argumentsKeywords.ToDictionary(x => x.Key, + x => (ISerializedValue)new SerializedValue(formatter, x.Value)); + } + + mDetails = details; + } + } + + public class MyClass + { + [JsonProperty("counter")] + public int Counter { get; set; } + + [JsonProperty("foo")] + public int[] Foo { get; set; } + + protected bool Equals(MyClass other) + { + return Counter == other.Counter && Foo.SequenceEqual(other.Foo); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((MyClass)obj); + } + + public override int GetHashCode() + { + unchecked + { + return (Counter * 397) ^ (Foo != null ? Foo.GetHashCode() : 0); + } + } + } + + //public class MyPositionalSubscriber : IObserver<(string, int, int)> + //{ + // public string C { get; set; } + // + // public int Number1 { get; set; } + // + // public int Number2 { get; set; } + // + // public void OnNext((string c, int number1, int number2) value) + // { + // (C, Number1, Number2) = value; + // } + // + // public void OnError(Exception error) + // { + // throw new NotImplementedException(); + // } + // + // public void OnCompleted() + // { + // throw new NotImplementedException(); + // } + //} + public class MyPositionalSubscriber : IObserver> + { + public string C { get; set; } + public int Number1 { get; set; } + public int Number2 { get; set; } + + public void OnNext([TupleElementNames(new string[] + { + "c", + "number1", + "number2" + })] ValueTuple value) + { + this.C = value.Item1; + this.Number1 = value.Item2; + this.Number2 = value.Item3; + } + + public void OnError(Exception error) + { + throw new NotImplementedException(); + } + + public void OnCompleted() + { + throw new NotImplementedException(); + } + } + + //public class MyKeywordSubscriber : IObserver<(int number1, int number2, string c, MyClass d)> + //{ + // public int Number1 { get; set; } + // + // public int Number2 { get; set; } + // + // public string C { get; set; } + // + // public MyClass D { get; set; } + // + // public void OnNext((int number1, int number2, string c, MyClass d) value) + // { + // (Number1, Number2, C, D) = value; + // } + // + // public void OnError(Exception error) + // { + // throw new NotImplementedException(); + // } + // + // public void OnCompleted() + // { + // throw new NotImplementedException(); + // } + //} + public class MyKeywordSubscriber : IObserver> + { + public int Number1 { get; set; } + public int Number2 { get; set; } + public string C { get; set; } + public MyClass D { get; set; } + + public void OnNext([TupleElementNames(new string[] + { + "number1", + "number2", + "c", + "d" + })] ValueTuple value) + { + this.Number1 = value.Item1; + this.Number2 = value.Item2; + this.C = value.Item3; + this.D = value.Item4; + } + + public void OnError(Exception error) + { + throw new NotImplementedException(); + } + + public void OnCompleted() + { + throw new NotImplementedException(); + } + } + + //public class MyPositionalTupleEventConverter : WampEventValueTupleConverter<(string, int, int)> + //{ + //} + public class MyPositionalTupleEventConverter : WampEventValueTupleConverter> + { + } + + //public class MyKeywordTupleEventConverter : WampEventValueTupleConverter<(int number1, int number2, string c, MyClass d)> + //{ + //} + [TupleElementNames(new string[] + { + "number1", + "number2", + "c", + "d" + })] + public class MyKeywordTupleEventConverter : WampEventValueTupleConverter> + { + } + } +} +#endif \ No newline at end of file diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcProxies/ILongValueTuplesServiceProxy.cs b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcProxies/ILongValueTuplesServiceProxy.cs new file mode 100644 index 000000000..a03905805 --- /dev/null +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcProxies/ILongValueTuplesServiceProxy.cs @@ -0,0 +1,39 @@ +#if !NET40 + +using System; +using System.Runtime.CompilerServices; +using WampSharp.V2.Rpc; + +namespace WampSharp.Tests.Wampv2.Integration.RpcProxies +{ + public interface ILongValueTuplesServiceProxy + { + [WampProcedure("com.myapp.get_long_positional_tuple")] + ValueTuple> GetLongPositionalTuple(string name); + //(string, string, string, string, string, string, string, string, string, string, int) GetLongPositionalTuple(string name); + + [WampProcedure("com.myapp.get_long_keyword_tuple")] + [return: TupleElementNames(new string[] + { + "item1", + "item2", + "item3", + "item4", + "item5", + "item6", + "item7", + "item8", + "length", + "item9", + "item10", + null, + null, + null, + null + })] + ValueTuple> GetLongKeywordTuple(string name); + //(string item1, string item2, string item3, string item4, string item5, string item6, string item7, string item8, int length, string item9, string item10) GetLongKeywordTuple(string name); + } +} + +#endif \ No newline at end of file diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcProxies/INamedTupleComplexResultService.cs b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcProxies/INamedTupleComplexResultService.cs new file mode 100644 index 000000000..e5c5db53f --- /dev/null +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcProxies/INamedTupleComplexResultService.cs @@ -0,0 +1,40 @@ +#if !NET40 +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using WampSharp.V2.Rpc; + +namespace WampSharp.Tests.Wampv2.Integration.RpcProxies +{ + public interface IPositionalTupleComplexResultService + { + [WampProcedure("com.myapp.split_name")] + ValueTuple SplitName(string fullname); + + [WampProcedure("com.myapp.split_name")] + Task> SplitNameAsync(string fullname); + } + + public interface INamedTupleComplexResultService + { + //(int c, int ci) AddComplex(int a, int ai, int b, int bi); + [WampProcedure("com.myapp.add_complex")] + [return: TupleElementNames(new string[] + { + "c", + "ci" + })] + ValueTuple AddComplex(int a, int ai, int b, int bi); + + //Task<(int c, int ci)> AddComplexAsync(int a, int ai, int b, int bi); + [WampProcedure("com.myapp.add_complex")] + [return: TupleElementNames(new string[] + { + "c", + "ci" + })] + Task> AddComplexAsync(int a, int ai, int b, int bi); + } +} + +#endif \ No newline at end of file diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/LongValueTuplesCalleeService.cs b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/LongValueTuplesCalleeService.cs new file mode 100644 index 000000000..8a28c95cc --- /dev/null +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/LongValueTuplesCalleeService.cs @@ -0,0 +1,58 @@ +#if !NET40 + +using System; +using System.Runtime.CompilerServices; +using WampSharp.V2.Rpc; + +namespace WampSharp.Tests.Wampv2.Integration.RpcServices +{ + //public class LongValueTuplesCalleeService : ILongValueTuplesService + //{ + // [WampProcedure("com.myapp.get_long_keyword_tuple")] + // public (string item1, string item2, string item3, string item4, string item5, string item6, string item7, string item8, int length, string item9, string item10) GetLongKeywordTuple(string name) + // { + // return (name + " 1", name + " 2", name + " 3", name + " 4", name + " 5", name + " 6", name + " 7", name + " 8", name.Length, name + " 9", name + " 10"); + // } + + // [WampProcedure("com.myapp.get_long_positional_tuple")] + // public (string, string, string, string, string, string, string, string, string, string, int) GetLongPositionalTuple(string name) + // { + // return (name + " 1", name + " 2", name + " 3", name + " 4", name + " 5", name + " 6", name + " 7", name + " 8", name + " 9", name + " 10", name.Length); + // } + //} + + public class LongValueTuplesCalleeService + { + [WampProcedure("com.myapp.get_long_keyword_tuple")] + [return: TupleElementNames(new string[] + { + "item1", + "item2", + "item3", + "item4", + "item5", + "item6", + "item7", + "item8", + "length", + "item9", + "item10", + null, + null, + null, + null + })] + public ValueTuple> GetLongKeywordTuple(string name) + { + return new ValueTuple>(name + " 1", name + " 2", name + " 3", name + " 4", name + " 5", name + " 6", name + " 7", new ValueTuple(name + " 8", name.Length, name + " 9", name + " 10")); + } + + [WampProcedure("com.myapp.get_long_positional_tuple")] + public ValueTuple> GetLongPositionalTuple(string name) + { + return new ValueTuple>(name + " 1", name + " 2", name + " 3", name + " 4", name + " 5", name + " 6", name + " 7", new ValueTuple(name + " 8", name + " 9", name + " 10", name.Length)); + } + } +} + +#endif \ No newline at end of file diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/LongValueTuplesService.cs b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/LongValueTuplesService.cs new file mode 100644 index 000000000..7bbb231da --- /dev/null +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/LongValueTuplesService.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using System.Linq; +using WampSharp.Core.Serialization; +using WampSharp.V2.Core.Contracts; +using WampSharp.V2.Rpc; + +namespace WampSharp.Tests.Wampv2.Integration.RpcServices +{ + public class LongValueTuplesService + { + [WampProcedure("com.myapp.get_long_positional_tuple")] + [return: WampResult(CollectionResultTreatment.Multivalued)] + public object[] GetLongTuple(string name) + { + object[] result = + Enumerable.Range(0, 10).Select(i => string.Format("{0} {1}", name, i)) + .Concat(new object[] {name.Length}) + .ToArray(); + + return result; + } + + public class KeywordTupleOperation : SyncLocalRpcOperation + { + public KeywordTupleOperation() : base("com.myapp.get_long_keyword_tuple") + { + } + + public override RpcParameter[] Parameters + { + get + { + return new RpcParameter[] {new RpcParameter(typeof(string), 0) }; + } + } + + public override bool HasResult + { + get + { + return false; + } + } + + public override CollectionResultTreatment CollectionResultTreatment + { + get + { + return CollectionResultTreatment.SingleValue; + } + } + + protected override object InvokeSync(IWampRawRpcOperationRouterCallback caller, IWampFormatter formatter, + InvocationDetails details, TMessage[] arguments, IDictionary argumentsKeywords, + out IDictionary outputs) + { + object[] unpacked = + this.UnpackParameters(formatter, arguments, argumentsKeywords); + + string name = (string) unpacked[0]; + + outputs = new Dictionary(); + + outputs["length"] = name.Length; + + for (int i = 0; i < 10; i++) + { + string argumentName = "item" + (i + 1); + outputs[argumentName] = string.Format("{0} {1}", name, i); + } + + return null; + } + } + } +} \ No newline at end of file diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/NamedTupleComplexResultService.cs b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/NamedTupleComplexResultService.cs new file mode 100644 index 000000000..f80eebb72 --- /dev/null +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/NamedTupleComplexResultService.cs @@ -0,0 +1,26 @@ +#if !NET40 +using System; +using System.Runtime.CompilerServices; +using WampSharp.V2.Rpc; + +namespace WampSharp.Tests.Wampv2.Integration.RpcServices +{ + public class NamedTupleComplexResultService + { + [WampProcedure("com.myapp.add_complex")] + [return: TupleElementNames(new string[] + { + "c", + "ci" + })] + public ValueTuple AddComplex(int a, int ai, int b, int bi) + { + return new ValueTuple(a + b, ai + bi); + } + //public (int c, int ci) AddComplex(int a, int ai, int b, int bi) + //{ + // return (a + b, ai + bi); + //} + } +} +#endif \ No newline at end of file diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/PositionalTupleComplexResultService.cs b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/PositionalTupleComplexResultService.cs new file mode 100644 index 000000000..330d8ac40 --- /dev/null +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/Integration/RpcServices/PositionalTupleComplexResultService.cs @@ -0,0 +1,23 @@ +#if !NET40 + +using System; +using System.Runtime.CompilerServices; +using WampSharp.V2.Rpc; + +namespace WampSharp.Tests.Wampv2.Integration.RpcServices +{ + public class PositionalTupleComplexResultService + { + [WampProcedure("com.myapp.add_complex")] + public ValueTuple AddComplex(int a, int ai, int b, int bi) + { + return new ValueTuple(a + b, ai + bi); + } + //public (int, int) AddComplex(int a, int ai, int b, int bi) + //{ + // return (a + b, ai + bi); + //} + } +} + +#endif \ No newline at end of file diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj b/src/net45/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj index ce8430bf0..639aaf7d3 100644 --- a/src/net45/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj @@ -19,15 +19,16 @@ full false bin\Debug\ - TRACE;DEBUG;NET45 + TRACE;DEBUG;NET45 WAMPCRA prompt 4 + false pdbonly true bin\Release\ - TRACE;NET45 + TRACE;NET45 WAMPCRA prompt 4 @@ -63,6 +64,10 @@ True + + ..\..\packages\System.ValueTuple.4.0.0-rc3-24212-01\lib\netstandard1.1\System.ValueTuple.dll + True + @@ -93,13 +98,20 @@ + + + + + + + diff --git a/src/net45/Tests/WampSharp.Tests.Wampv2/packages.config b/src/net45/Tests/WampSharp.Tests.Wampv2/packages.config index 04a84340c..b0657ad3f 100644 --- a/src/net45/Tests/WampSharp.Tests.Wampv2/packages.config +++ b/src/net45/Tests/WampSharp.Tests.Wampv2/packages.config @@ -7,4 +7,5 @@ + \ No newline at end of file diff --git a/src/net45/WampSharp.Default.Client/WampSharp.Default.Client.csproj b/src/net45/WampSharp.Default.Client/WampSharp.Default.Client.csproj index a32d81094..b61b64718 100644 --- a/src/net45/WampSharp.Default.Client/WampSharp.Default.Client.csproj +++ b/src/net45/WampSharp.Default.Client/WampSharp.Default.Client.csproj @@ -51,7 +51,7 @@ - ..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/WampSharp.Default.Client/packages.config b/src/net45/WampSharp.Default.Client/packages.config index e1e00513d..a5c0aaf7d 100644 --- a/src/net45/WampSharp.Default.Client/packages.config +++ b/src/net45/WampSharp.Default.Client/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/src/net45/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj b/src/net45/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj index b6f82a2e5..0bd408b2f 100644 --- a/src/net45/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj +++ b/src/net45/WampSharp.WAMP1.Default/WampSharp.WAMP1.Default.csproj @@ -54,7 +54,7 @@ - ..\packages\WebSocket4Net.0.15.0-beta4\lib\net45\WebSocket4Net.dll + ..\packages\WebSocket4Net.0.15.0-beta5\lib\net45\WebSocket4Net.dll True diff --git a/src/net45/WampSharp.WAMP1.Default/packages.config b/src/net45/WampSharp.WAMP1.Default/packages.config index ff2f6eb3e..144c5e1de 100644 --- a/src/net45/WampSharp.WAMP1.Default/packages.config +++ b/src/net45/WampSharp.WAMP1.Default/packages.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/src/net45/WampSharp.WAMP1/WAMP1/V1/Core/Listener/WampListener.cs b/src/net45/WampSharp.WAMP1/WAMP1/V1/Core/Listener/WampListener.cs index ae23e39f0..3793cf3bc 100644 --- a/src/net45/WampSharp.WAMP1/WAMP1/V1/Core/Listener/WampListener.cs +++ b/src/net45/WampSharp.WAMP1/WAMP1/V1/Core/Listener/WampListener.cs @@ -50,7 +50,7 @@ protected override void OnConnectionOpen(IWampConnection connection) IWampClient client = ClientContainer.GetClient(connection); - mLogger.DebugFormat("Client connected, session id: {0}", client.SessionId); + mLogger.DebugFormat("Client connected, session id: {SessionId}", client.SessionId); client.Welcome(client.SessionId, 1, "WampSharp"); @@ -74,7 +74,7 @@ protected override void OnCloseConnection(IWampConnection connection) if (mLogger.IsDebugEnabled()) { IWampClient client = ClientContainer.GetClient(connection); - mLogger.DebugFormat("Client disconnected, session id: {0}", client.SessionId); + mLogger.DebugFormat("Client disconnected, session id: {SessionId}", client.SessionId); } base.OnCloseConnection(connection); diff --git a/src/net45/WampSharp/Core/Dispatch/Handler/WampMethodBuilder.cs b/src/net45/WampSharp/Core/Dispatch/Handler/WampMethodBuilder.cs index c91703887..cfa4bec8c 100644 --- a/src/net45/WampSharp/Core/Dispatch/Handler/WampMethodBuilder.cs +++ b/src/net45/WampSharp/Core/Dispatch/Handler/WampMethodBuilder.cs @@ -143,7 +143,7 @@ private object DeserializeArgument(ParameterInfo parameter, TMessage argument) } catch (Exception ex) { - mLogger.ErrorFormat(ex, "Failed deserializing {0}", parameter.Name); + mLogger.ErrorFormat(ex, "Failed deserializing {ParameterName}", parameter.Name); throw; } } diff --git a/src/net45/WampSharp/Core/Dispatch/WampIncomingMessageHandler.cs b/src/net45/WampSharp/Core/Dispatch/WampIncomingMessageHandler.cs index 49ce41bea..05931e6a6 100644 --- a/src/net45/WampSharp/Core/Dispatch/WampIncomingMessageHandler.cs +++ b/src/net45/WampSharp/Core/Dispatch/WampIncomingMessageHandler.cs @@ -44,7 +44,7 @@ public void HandleMessage(TClient client, WampMessage message) if (method != null) { - mLogger.DebugFormat("Mapped message to method: {0}", method.Method); + mLogger.DebugFormat("Mapped message to method: {Method}", method.Method); Action> action = mDelegateCache.Get(method); action(client, message); } diff --git a/src/net45/WampSharp/Core/Proxy/WampOutgoingRequestSerializer.cs b/src/net45/WampSharp/Core/Proxy/WampOutgoingRequestSerializer.cs index a982e44b1..38df64c00 100644 --- a/src/net45/WampSharp/Core/Proxy/WampOutgoingRequestSerializer.cs +++ b/src/net45/WampSharp/Core/Proxy/WampOutgoingRequestSerializer.cs @@ -34,7 +34,7 @@ public WampOutgoingRequestSerializer(IWampFormatter formatter) public WampMessage SerializeRequest(MethodInfo method, object[] arguments) { - mLogger.DebugFormat("Calling remote peer proxy method: {0}", method); + mLogger.DebugFormat("Calling remote peer proxy method: {Method}", method); WampMethodInfo wampMethod = GetWampMethod(method); diff --git a/src/net45/WampSharp/Core/Utilities/CustomAttributeExtensions.cs b/src/net45/WampSharp/Core/Utilities/CustomAttributeExtensions.cs index 0a7bbfb4f..a2c80588b 100644 --- a/src/net45/WampSharp/Core/Utilities/CustomAttributeExtensions.cs +++ b/src/net45/WampSharp/Core/Utilities/CustomAttributeExtensions.cs @@ -18,6 +18,11 @@ public static bool IsDefined(this MemberInfo element, Type attributeType, bool i { return Attribute.IsDefined(element, attributeType, inherit); } + + public static bool IsDefined(this ParameterInfo parameter, Type attributeType, bool inherit = true) + { + return Attribute.IsDefined(parameter, attributeType, inherit); + } } #endif } \ No newline at end of file diff --git a/src/net45/WampSharp/Core/Utilities/TypeExtensions.cs b/src/net45/WampSharp/Core/Utilities/TypeExtensions.cs index 4636698cc..2ae5aabef 100644 --- a/src/net45/WampSharp/Core/Utilities/TypeExtensions.cs +++ b/src/net45/WampSharp/Core/Utilities/TypeExtensions.cs @@ -98,6 +98,19 @@ public static GenericParameterAttributes GenericParameterAttributes(this Type ty #endif } +#if PCL + public static bool IsDefined(this Type type, Type attributeType, bool inherit) + { + return type.GetTypeInfo().IsDefined(attributeType, inherit); + } + + public static T GetCustomAttribute(this Type type, bool inherit = true) + where T : Attribute + { + return type.GetTypeInfo().GetCustomAttribute(inherit); + } +#endif + #if NET40 public static Type AsType(this Type type) { @@ -123,7 +136,14 @@ public static bool IsAssignableFrom(this Type interfaceType, Type type) public static Type[] GetGenericArguments(this Type type) { - return type.GenericTypeArguments; + TypeInfo typeInfo = type.GetTypeInfo(); + + if (typeInfo.IsGenericTypeDefinition) + { + return typeInfo.GenericTypeParameters; + } + + return typeInfo.GenericTypeArguments; } public static MethodInfo GetMethod(this Type type, string methodName) @@ -145,6 +165,21 @@ public static bool IsInstanceOfType(this Type type, object instance) { return type.IsAssignableFrom(instance.GetType()); } + + public static IEnumerable GetProperties(this Type type) + { + return type.GetTypeInfo().DeclaredProperties; + } + + public static IEnumerable GetFields(this Type type) + { + return type.GetTypeInfo().DeclaredFields; + } + + public static FieldInfo GetField(this Type type, string name) + { + return type.GetTypeInfo().GetDeclaredField(name); + } #endif } } \ No newline at end of file diff --git a/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTuple.cs b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTuple.cs new file mode 100644 index 000000000..38a45b060 --- /dev/null +++ b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTuple.cs @@ -0,0 +1,55 @@ +#if NET40 + +using System; +using System.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.ReturnValue)] + internal sealed class TupleElementNamesAttribute : Attribute + { + public IList TransformNames { get; private set; } + + public TupleElementNamesAttribute(string[] transformNames) + { + TransformNames = transformNames; + } + } +} + +namespace System +{ + internal class ValueTuple + { + } + + internal class ValueTuple + { + } + + internal class ValueTuple + { + } + + internal class ValueTuple + { + } + + internal class ValueTuple + { + } + + internal class ValueTuple + { + } + + internal class ValueTuple + { + } + + internal class ValueTuple + { + } +} + +#endif \ No newline at end of file diff --git a/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleArrayConverter.cs b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleArrayConverter.cs new file mode 100644 index 000000000..0bc113821 --- /dev/null +++ b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleArrayConverter.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace WampSharp.Core.Utilities.ValueTuple +{ + internal static class ValueTupleArrayConverter + { + public static readonly ValueTupleArrayConverter Value = new ValueTupleArrayConverter(typeof(TValueTuple)); + } + + internal class ValueTupleArrayConverter : ValueTupleConverter + { + private readonly Type mTupleType; + + private static readonly MethodInfo mGetMethod = + Method.Get(() => Get()) + .GetGenericMethodDefinition(); + + private readonly Func mToArrayDelegate; + + private readonly Func mToTupleDelegate; + private readonly int mTupleLegnth; + + public ValueTupleArrayConverter(Type tupleType) : base(tupleType) + { + mTupleType = tupleType; + mTupleLegnth = tupleType.GetValueTupleLength(); + mToArrayDelegate = BuildToArray(); + mToTupleDelegate = BuildToTuple(); + } + + public object ToTuple(object[] array) + { + if (array.Length != mTupleLegnth) + { + throw new ArgumentException("Expected an array of size " + mTupleLegnth, "array"); + } + + return mToTupleDelegate(array); + } + + public object[] ToArray(object valueTuple) + { + return mToArrayDelegate(valueTuple); + } + + private Func BuildToTuple() + { + ParameterExpression array = + Expression.Parameter(typeof(object[]), "array"); + + int tupleLength = mTupleType.GetValueTupleLength(); + + IEnumerable tupleItemValues = + Enumerable.Range(0, tupleLength) + .Select(index => Expression.ArrayIndex(array, Expression.Constant(index))); + + // new ValueTuple((T1)array[0],(T2)array[1], ...) + + Func result = + BuildToTuple + (array, tupleItemValues); + + return result; + } + + private Func BuildToArray() + { + ParameterExpression tupleResult = + Expression.Parameter(typeof(object), "tupleResult"); + + ParameterExpression casted = + Expression.Variable(mTupleType, "casted"); + + BinaryExpression assignment = + Expression.Assign(casted, Expression.Convert(tupleResult, mTupleType)); + + IEnumerable parameters = + GetTupleItemsExpressions(casted, mTupleType); + + NewArrayExpression arrayInit = + Expression.NewArrayInit(typeof(object), parameters); + + BlockExpression body = + Expression.Block(variables: new[] { casted }, + expressions: new Expression[] + { + assignment, + arrayInit + }); + + Expression> lambda = + Expression.Lambda> + (body: body, + parameters: tupleResult); + + Func result = lambda.Compile(); + + return result; + } + + public static ValueTupleArrayConverter Get(Type type) + { + object result = + mGetMethod.MakeGenericMethod(type).Invoke(null, new object[]{}); + + return (ValueTupleArrayConverter) result; + } + + public static ValueTupleArrayConverter Get() + { + return ValueTupleArrayConverter.Value; + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleConverter.cs b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleConverter.cs new file mode 100644 index 000000000..68dd09f43 --- /dev/null +++ b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleConverter.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace WampSharp.Core.Utilities.ValueTuple +{ + internal abstract class ValueTupleConverter + { + private const int MaxTupleSize = 7; + private readonly Type mTupleType; + + protected ValueTupleConverter(Type tupleType) + { + ThrowHelper.ValidateSimpleTuple(tupleType); + mTupleType = tupleType; + } + + protected Func BuildToTuple(ParameterExpression sourceParameter, IEnumerable tupleItemValuesExpressions) + { + NewExpression tupleCreation = + GetTupleNewExpression(tupleItemValuesExpressions, mTupleType); + + // new ValueTuple((T1)dictionary["$argument1Name"],(T2)dictionary["$argument2Name"], ...) + + UnaryExpression boxed = + Expression.Convert(tupleCreation, typeof(object)); + + var lambda = Expression.Lambda> + (boxed, sourceParameter); + + var compiled = lambda.Compile(); + + return compiled; + } + + public static NewExpression GetTupleNewExpression(IEnumerable tupleItemValuesExpressions, Type tupleType) + { + Type[] genericArguments = tupleType.GetGenericArguments(); + + IEnumerable tupleSimpleArguments = tupleItemValuesExpressions.Zip + (genericArguments.Take(MaxTupleSize), + (expression, type) => + Expression.Convert(expression, + type)); + + IEnumerable tupleConstructorArguments = tupleSimpleArguments; + + if (genericArguments.Length > MaxTupleSize) + { + IEnumerable nestedItemValueExpressions = + tupleItemValuesExpressions.Skip(MaxTupleSize); + + Type nestedTupleType = genericArguments.Last(); + + NewExpression newExpression = + GetTupleNewExpression(nestedItemValueExpressions, nestedTupleType); + + tupleConstructorArguments = tupleConstructorArguments.Concat(new[] {newExpression}); + } + + NewExpression tupleCreation = + Expression.New(tupleType.GetConstructors().FirstOrDefault(), + tupleConstructorArguments); + + return tupleCreation; + } + + public static IEnumerable GetTupleItemsExpressions + (Expression tupleInstance, + Type tupleType) + { + IEnumerable result = + InnerGetTupleItemsExpressions(tupleInstance, tupleType); + + return result.Select(x => Expression.Convert(x, typeof(object))); + } + + protected static IEnumerable InnerGetTupleItemsExpressions + (Expression tupleInstance, + Type tupleType) + { + IEnumerable simpleFields = + tupleType.GetFields() + .Where(x => x.Name.StartsWith("Item")) + .OrderBy(x => x.Name) + .Select(field => Expression.Field(tupleInstance, field)); + + IEnumerable result = simpleFields; + + Type[] genericArguments = tupleType.GetGenericArguments(); + + if (genericArguments.Length > MaxTupleSize) + { + FieldInfo restField = tupleType.GetField("Rest"); + + MemberExpression nestedTupleInstance = + Expression.Field(tupleInstance, restField); + + Type nestedTupleType = genericArguments.Last(); + + IEnumerable nestedFields = + InnerGetTupleItemsExpressions(nestedTupleInstance, nestedTupleType); + + result = result.Concat(nestedFields); + } + + return result; + } + + protected static class ThrowHelper + { + public static void ValidateSimpleTuple(Type tupleType) + { + if (!tupleType.IsValueTuple()) + { + throw new ArgumentException("Expected a ValueTuple type", "tupleType"); + } + } + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleDictionaryConverter.cs b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleDictionaryConverter.cs new file mode 100644 index 000000000..4823e36d1 --- /dev/null +++ b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleDictionaryConverter.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; + +namespace WampSharp.Core.Utilities.ValueTuple +{ + internal class ValueTupleDictionaryConverter : ValueTupleConverter + { + private readonly Func> mToDictionaryDelegate; + + private readonly Func, object> mToTupleDelegate; + + public ValueTupleDictionaryConverter(Type tupleType, Func> toDictionaryDelegate, Func, object> toTupleDelegate) : + base(tupleType) + { + Validate(tupleType); + mToDictionaryDelegate = toDictionaryDelegate; + mToTupleDelegate = toTupleDelegate; + } + + private void Validate(Type tupleType) + { + ThrowHelper.ValidateSimpleTuple(tupleType); + } + + public object ToTuple(IDictionary dictionary) + { + return mToTupleDelegate(dictionary); + } + + public IDictionary ToDictionary(object valueTuple) + { + return mToDictionaryDelegate(valueTuple); + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleDictionaryConverterBuilder.cs b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleDictionaryConverterBuilder.cs new file mode 100644 index 000000000..10078c051 --- /dev/null +++ b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleDictionaryConverterBuilder.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace WampSharp.Core.Utilities.ValueTuple +{ + internal static class ValueTupleDictionaryConverterBuilder + { + private static readonly MethodInfo mBuildMethod = Method.Get(() => Build(default(IList))) + .GetGenericMethodDefinition(); + + public static ValueTupleDictionaryConverter Build(Type tupleType, IList transformNames) + { + MethodInfo methodToInvoke = + mBuildMethod.MakeGenericMethod(tupleType); + + object result = + methodToInvoke.Invoke(null, new object[] {transformNames}); + + return (ValueTupleDictionaryConverter) result; + } + + public static ValueTupleDictionaryConverter Build(IList transformNames) + { + return ValueTupleDictionaryConverterBuilder.Get(transformNames); + } + } + + internal class ValueTupleDictionaryConverterBuilder + { + private static readonly MethodInfo mDictionaryAddMethod = + Method.Get((IDictionary dictionary) => + dictionary.Add(default(string), default(object))); + + private static readonly PropertyInfo mDictionaryIndexer = + typeof(IDictionary).GetProperties(). + FirstOrDefault(x => x.GetIndexParameters().Any()); + + private static readonly PropertyInfo mListIndexer = + typeof(IList).GetProperties(). + FirstOrDefault(x => x.GetIndexParameters().Any()); + + private static Func, IDictionary> mToDictionary = GetToDictionaryBuilder(); + private static Func, IList, object> mToTuple = GetToTupleBuilder(); + + public static ValueTupleDictionaryConverter Get(IList transformNames) + { + Func> toDictionaryDelegate = + tuple => mToDictionary(tuple, transformNames); + + Func, object> toTupleDelegate = + dictionary => mToTuple(dictionary, transformNames); + + return new ValueTupleDictionaryConverter(typeof(TTuple), toDictionaryDelegate, toTupleDelegate); + } + + private static Func, IDictionary> GetToDictionaryBuilder() + { + Type tupleType = typeof(TTuple); + + ParameterExpression transformNamesParameter = + Expression.Parameter(typeof(IList), "transformNamesParameter"); + + ParameterExpression tupleParameter = + Expression.Parameter(typeof(object), "tupleParameter"); + + ParameterExpression casted = + Expression.Variable(tupleType, "casted"); + + BinaryExpression assignment = + Expression.Assign(casted, Expression.Convert(tupleParameter, tupleType)); + + IEnumerable tupleItemsExpressions = + ValueTupleConverter.GetTupleItemsExpressions(casted, tupleType); + + ListInitExpression dictionaryInit = + Expression.ListInit + (Expression.New(typeof(Dictionary)), + tupleItemsExpressions.Select((parameter, i) => Expression.ElementInit + (mDictionaryAddMethod, + Expression.Property(transformNamesParameter, mListIndexer, Expression.Constant(i)), + parameter))); + + BlockExpression body = + Expression.Block(variables: new[] { casted }, + expressions: new Expression[] + { + assignment, + dictionaryInit + }); + + Expression, IDictionary>> lambda = + Expression.Lambda, IDictionary>> + (body, + tupleParameter, + transformNamesParameter); + + Func, IDictionary> result = lambda.Compile(); + + return result; + } + + private static Func, IList, object> GetToTupleBuilder() + { + ParameterExpression dictionary = + Expression.Parameter(typeof(IDictionary), "dictionary"); + + ParameterExpression transformNames = + Expression.Parameter(typeof(IList), "transformNames"); + + int valueTupleLength = typeof(TTuple).GetValueTupleLength(); + + var tupleElements = + Enumerable.Range(0, valueTupleLength); + + IEnumerable itemsValues = + tupleElements.Select + (index => + Expression.MakeIndex(dictionary, mDictionaryIndexer, + new Expression[] + { + Expression.Property(transformNames, + mListIndexer, + Expression.Constant(index)) + })); + + // new ValueTuple((T1)dictionary[transformNames[0]],(T2)dictionary[transformNames[1]], ...) + Func, IList, object> result = + GetToTupleBuilder(dictionary, itemsValues, transformNames); + + return result; + } + + private static Func, IList, object> GetToTupleBuilder(ParameterExpression dictionary, IEnumerable itemsValues, ParameterExpression transformNames) + { + // new ValueTuple((T1)dictionary[transformNames[0]],(T2)dictionary[transformNames[1]], ...) + NewExpression tupleCreation = + ValueTupleConverter.GetTupleNewExpression(itemsValues, typeof(TTuple)); + + UnaryExpression boxed = + Expression.Convert(tupleCreation, typeof(object)); + + var lambda = + Expression.Lambda, IList, object>> + (boxed, dictionary, transformNames); + + var result = lambda.Compile(); + + return result; + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleTypeExtensions.cs b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleTypeExtensions.cs new file mode 100644 index 000000000..aa9eeaca3 --- /dev/null +++ b/src/net45/WampSharp/Core/Utilities/ValueTuple/ValueTupleTypeExtensions.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace WampSharp.Core.Utilities.ValueTuple +{ + internal static class ValueTupleTypeExtensions + { + public static bool IsValueTuple(this Type type) + { + if (!type.IsGenericType()) + { + return false; + } + + Type genericTypeDefinition = type.GetGenericTypeDefinition(); + + if ((genericTypeDefinition == typeof(ValueTuple<>)) || + (genericTypeDefinition == typeof(ValueTuple<,>)) || + (genericTypeDefinition == typeof(ValueTuple<,,>)) || + (genericTypeDefinition == typeof(ValueTuple<,,,>)) || + (genericTypeDefinition == typeof(ValueTuple<,,,,>)) || + (genericTypeDefinition == typeof(ValueTuple<,,,,,>)) || + (genericTypeDefinition == typeof(ValueTuple<,,,,,,>)) || + (genericTypeDefinition == typeof(ValueTuple<,,,,,,,>))) + { + return true; + } + + return false; + } + + public static int GetValueTupleLength(this Type type) + { + if (!type.IsValueTuple()) + { + throw new ArgumentException("Expected a ValueTuple type", "type"); + } + + Type genericTypeDefinition = type.GetGenericTypeDefinition(); + + Type[] genericArguments = genericTypeDefinition.GetGenericArguments(); + + int tupleLength = genericArguments.Length; + if (!genericTypeDefinition.IsLongTuple()) + { + return tupleLength; + } + else + { + Type last = type.GetGenericArguments().Last(); + + return (tupleLength - 1) + + last.GetValueTupleLength(); + } + } + + public static bool IsLongTuple(this Type tupleType) + { + return tupleType.IsGenericType() && + tupleType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,,,,>); + } + + public static bool IsValidTupleType(this Type tupleType) + { + if (tupleType.IsValueTuple()) + { + if (tupleType.IsLongTuple()) + { + Type rest = tupleType.GetGenericArguments().Last(); + + if (!rest.IsValidTupleType()) + { + return false; + } + } + + return true; + } + + return false; + } + + public static IEnumerable GetValueTupleElementTypes(this Type tupleType) + { + Type[] genericArguments = tupleType.GetGenericArguments(); + + if (!tupleType.IsLongTuple()) + { + return genericArguments; + } + else + { + IEnumerable firstElements = + genericArguments.Take(genericArguments.Length - 1); + + Type nestedTupleType = genericArguments.Last(); + + IEnumerable rest = nestedTupleType.GetValueTupleElementTypes(); + + return firstElements.Concat(rest); + } + } + + public static bool ReturnsTuple(this MethodInfo method) + { + Type unwrappedReturnType = TaskExtensions.UnwrapReturnType(method.ReturnType); + + return unwrappedReturnType.IsValueTuple(); + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/AsyncOperationCallback.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/AsyncOperationCallback.cs index f6a6598ae..5ddddc68c 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/AsyncOperationCallback.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/AsyncOperationCallback.cs @@ -28,9 +28,9 @@ protected virtual void SetResult(ResultDetails details, TResult result) mTask.SetResult(result); } - protected virtual TResult GetResult(IWampFormatter formatter, TMessage[] arguments) + protected virtual TResult GetResult(IWampFormatter formatter, TMessage[] arguments, IDictionary argumentsKeywords) { - return mExtractor.GetResult(formatter, arguments); + return mExtractor.GetResult(formatter, arguments, argumentsKeywords); } public void Result(IWampFormatter formatter, ResultDetails details) @@ -46,13 +46,20 @@ public void Result(IWampFormatter formatter, ResultDetails d public void Result(IWampFormatter formatter, ResultDetails details, TMessage[] arguments, IDictionary argumentsKeywords) { - SetResult(details, formatter, arguments); + SetResult(details, formatter, arguments, argumentsKeywords); } - private void SetResult(ResultDetails details, IWampFormatter formatter, TMessage[] arguments) + private void SetResult(ResultDetails details, IWampFormatter formatter, TMessage[] arguments, IDictionary argumentsKeywords = null) { - TResult result = GetResult(formatter, arguments); - SetResult(details, result); + try + { + TResult result = GetResult(formatter, arguments, argumentsKeywords); + SetResult(details, result); + } + catch (Exception ex) + { + SetException(ex); + } } public void Error(IWampFormatter formatter, TMessage details, string error) diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/IOperationResultExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/IOperationResultExtractor.cs index cdc7352ad..4369d0a22 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/IOperationResultExtractor.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/IOperationResultExtractor.cs @@ -1,9 +1,10 @@ +using System.Collections.Generic; using WampSharp.Core.Serialization; namespace WampSharp.V2.CalleeProxy { internal interface IOperationResultExtractor { - TResult GetResult(IWampFormatter formatter, TMessage[] arguments); + TResult GetResult(IWampFormatter formatter, TMessage[] arguments, IDictionary argumentsKeywords); } } \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/MultiValueExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/MultiValueExtractor.cs index 379a07fee..a0df45237 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/MultiValueExtractor.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/MultiValueExtractor.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using WampSharp.Core.Serialization; @@ -9,7 +10,7 @@ internal class MultiValueExtractor : IOperationResultExtractor(IWampFormatter formatter, TMessage[] arguments) + public TResult[] GetResult(IWampFormatter formatter, TMessage[] arguments, IDictionary argumentsKeywords) { if (!arguments.Any()) { diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/OperationResultExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/OperationResultExtractor.cs new file mode 100644 index 000000000..e3ff1b00d --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/OperationResultExtractor.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using WampSharp.Core.Utilities; +using WampSharp.Core.Utilities.ValueTuple; +using WampSharp.V2.Core; +using WampSharp.V2.Rpc; + +namespace WampSharp.V2.CalleeProxy +{ + internal class OperationResultExtractor + { + public static IOperationResultExtractor Get(MethodInfo method) + { + IOperationResultExtractor extractor; + + if (typeof(T).IsValueTuple()) + { + extractor = GetValueTupleOperationResultExtractor(method); + } + else if (!method.HasMultivaluedResult()) + { + bool hasReturnValue = method.HasReturnValue(); + extractor = new SingleValueExtractor(hasReturnValue); + } + else + { + Type elementType = typeof(T).GetElementType(); + + Type extractorType = + typeof(MultiValueExtractor<>).MakeGenericType(elementType); + + extractor = + (IOperationResultExtractor)Activator.CreateInstance(extractorType); + } + + return extractor; + } + + private static IOperationResultExtractor GetValueTupleOperationResultExtractor(MethodInfo method) + { + ArgumentUnpacker unpacker = GetTupleArgumentUnpacker(method); + + return new ValueTupleValueExtractor(unpacker); + } + + private static ArgumentUnpacker GetTupleArgumentUnpacker(MethodInfo method) + { + Type tupleType = TaskExtensions.UnwrapReturnType(method.ReturnType); + + IEnumerable transformNames = null; + + if (method.ReturnParameter.IsDefined(typeof(TupleElementNamesAttribute))) + { + TupleElementNamesAttribute attribute = + method.ReturnParameter.GetCustomAttribute(); + + transformNames = attribute.TransformNames; + } + + return ArgumentUnpackerHelper.GetValueTupleArgumentUnpacker + (tupleType, transformNames); + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/SingleValueExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/SingleValueExtractor.cs index c027f8986..776498acb 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/SingleValueExtractor.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/SingleValueExtractor.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using WampSharp.Core.Serialization; @@ -14,7 +15,7 @@ public SingleValueExtractor(bool hasReturnValue) mHasReturnValue = hasReturnValue; } - public TResult GetResult(IWampFormatter formatter, TMessage[] arguments) + public TResult GetResult(IWampFormatter formatter, TMessage[] arguments, IDictionary argumentsKeywords) { if (!mHasReturnValue || !arguments.Any()) { diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/ValueTupleValueExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/ValueTupleValueExtractor.cs new file mode 100644 index 000000000..74f883657 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Async/ValueTupleValueExtractor.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using WampSharp.Core.Serialization; +using WampSharp.Core.Utilities.ValueTuple; +using WampSharp.V2.Core; + +namespace WampSharp.V2.CalleeProxy +{ + internal class ValueTupleValueExtractor : IOperationResultExtractor + { + private readonly ArgumentUnpacker mUnpacker; + private readonly ValueTupleArrayConverter mConverter; + + public ValueTupleValueExtractor(ArgumentUnpacker unpacker) + { + mUnpacker = unpacker; + mConverter = ValueTupleArrayConverter.Value; + } + + public T GetResult(IWampFormatter formatter, TMessage[] arguments, IDictionary argumentsKeywords) + { + object[] array = + mUnpacker.UnpackParameters(formatter, arguments, argumentsKeywords); + + T result = (T) mConverter.ToTuple(array); + + return result; + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Sync/SyncCallback.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Sync/SyncCallback.cs index 3e4ba4073..ddc65b40b 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Sync/SyncCallback.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/Callbacks/Sync/SyncCallback.cs @@ -50,7 +50,7 @@ public override void Result(IWampFormatter formatter, Result mArguments, outOrRefParameters); - SetResult(formatter, arguments); + SetResult(formatter, arguments, argumentsKeywords); } catch (Exception ex) { @@ -59,10 +59,17 @@ public override void Result(IWampFormatter formatter, Result } } - private void SetResult(IWampFormatter formatter, TMessage[] arguments) + private void SetResult(IWampFormatter formatter, TMessage[] arguments, IDictionary argumentKeywords = null) { - TResult result = mExtractor.GetResult(formatter, arguments); - SetResult(result); + try + { + TResult result = mExtractor.GetResult(formatter, arguments, argumentKeywords); + SetResult(result); + } + catch (Exception ex) + { + SetException(ex); + } } protected void SetResult(TResult result) diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyBase.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyBase.cs index 0fa3610ef..cff614c88 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyBase.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyBase.cs @@ -9,6 +9,10 @@ namespace WampSharp.V2.CalleeProxy { public class CalleeProxyBase { + protected delegate T InvokeSyncDelegate(CalleeProxyBase proxy, params object[] arguments); + protected delegate Task InvokeAsyncDelegate(CalleeProxyBase proxy, params object[] arguments); + protected delegate Task InvokeProgressiveAsyncDelegate(CalleeProxyBase proxy, IProgress progress, params object[] arguments); + private readonly WampCalleeProxyInvocationHandler mHandler; private readonly ICalleeProxyInterceptor mInterceptor; @@ -19,6 +23,59 @@ public CalleeProxyBase(IWampRealmProxy realmProxy, mHandler = new ClientInvocationHandler(realmProxy); } + protected static InvokeSyncDelegate GetInvokeSync(MethodInfo method) + { + IOperationResultExtractor extractor = GetExtractor(method); + return GetInvokeSync(method, extractor); + } + + protected static InvokeAsyncDelegate GetInvokeAsync(MethodInfo method) + { + IOperationResultExtractor extractor = GetExtractor(method); + return GetInvokeAsync(method, extractor); + } + + protected static InvokeProgressiveAsyncDelegate GetInvokeProgressiveAsync(MethodInfo method) + { + IOperationResultExtractor extractor = GetExtractor(method); + return GetInvokeProgressiveAsync(method, extractor); + } + + private static IOperationResultExtractor GetExtractor(MethodInfo method) + { + return OperationResultExtractor.Get(method); + } + + + private static InvokeSyncDelegate GetInvokeSync(MethodBase method, IOperationResultExtractor extractor) + { + InvokeSyncDelegate result = + (proxy, arguments) => + proxy.InvokeSync(method, extractor, arguments); + + return result; + } + + private static InvokeAsyncDelegate GetInvokeAsync(MethodBase method, IOperationResultExtractor extractor) + { + InvokeAsyncDelegate result = + (proxy, arguments) => + proxy.InvokeAsync(method, extractor, arguments); + + return result; + } + + private static InvokeProgressiveAsyncDelegate + GetInvokeProgressiveAsync(MethodBase method, + IOperationResultExtractor extractor) + { + InvokeProgressiveAsyncDelegate result = + (proxy, progress, arguments) => + proxy.InvokeProgressiveAsync(method, progress, extractor, arguments); + + return result; + } + protected T SingleInvokeSync(MethodBase method, params object[] arguments) { return InvokeSync(method, new SingleValueExtractor(true), arguments); @@ -103,21 +160,11 @@ private Task InvokeProgressiveAsync progress); } - protected static MethodInfo GetMethodInfo(Expression expression) - { - return Method.Get(expression); - } - protected static MethodInfo GetMethodInfo(Expression> expression) { return Method.Get(expression); } - protected static MethodInfo GetMethodInfo(Func> expressionFactory) - { - return Method.Get(expressionFactory()); - } - protected static MethodInfo GetMethodInfo(Func>> expressionFactory) { return Method.Get(expressionFactory()); diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyInterceptorBase.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyInterceptorBase.cs index c7708591d..367be0993 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyInterceptorBase.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyInterceptorBase.cs @@ -1,8 +1,13 @@ #if CASTLE || DISPATCH_PROXY using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using Castle.DynamicProxy; using WampSharp.Core.Utilities; +using WampSharp.Core.Utilities.ValueTuple; +using WampSharp.V2.Core; using WampSharp.V2.Rpc; namespace WampSharp.V2.CalleeProxy @@ -65,7 +70,7 @@ public CalleeProxyInterceptorBase(MethodInfo method, IWampCalleeProxyInvocationH ICalleeProxyInterceptor interceptor) : base(method, handler, interceptor) { - mExtractor = GetOperationResultExtractor(method); + mExtractor = OperationResultExtractor.Get(method); } public IOperationResultExtractor Extractor @@ -75,29 +80,6 @@ public IOperationResultExtractor Extractor return mExtractor; } } - - private static IOperationResultExtractor GetOperationResultExtractor(MethodInfo method) - { - IOperationResultExtractor extractor; - - if (!method.HasMultivaluedResult()) - { - bool hasReturnValue = method.HasReturnValue(); - extractor = new SingleValueExtractor(hasReturnValue); - } - else - { - Type elementType = typeof(T).GetElementType(); - - Type extractorType = - typeof(MultiValueExtractor<>).MakeGenericType(elementType); - - extractor = - (IOperationResultExtractor)Activator.CreateInstance(extractorType); - } - - return extractor; - } } } #endif \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyInterceptorFactory.cs b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyInterceptorFactory.cs index 9d483692b..5f422f0ac 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyInterceptorFactory.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/CalleeProxy/CalleeProxyInterceptorFactory.cs @@ -33,6 +33,8 @@ private static Type GetRelevantInterceptorType(MethodInfo method) if (!typeof(Task).IsAssignableFrom(returnType)) { + MethodInfoValidation.ValidateTupleReturnType(method); + genericArgument = returnType == typeof(void) ? typeof(object) : returnType; interceptorType = typeof(SyncCalleeProxyInterceptor<>); } diff --git a/src/net45/WampSharp/WAMP2/V2/Api/Client/WampRealmProxyServiceProvider.cs b/src/net45/WampSharp/WAMP2/V2/Api/Client/WampRealmProxyServiceProvider.cs index c6ef80611..5a8013ab9 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/Client/WampRealmProxyServiceProvider.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/Client/WampRealmProxyServiceProvider.cs @@ -35,16 +35,41 @@ public Task RegisterCallee(object instance) } public Task RegisterCallee(object instance, ICalleeRegistrationInterceptor interceptor) + { + return RegisterCallee(instance.GetType(), () => instance, interceptor); + } + + public Task RegisterCallee(Type type, Func instanceProvider) + { + return RegisterCallee(type, instanceProvider, CalleeRegistrationInterceptor.Default); + } + + + public Task RegisterCallee(Func instanceProvider, + ICalleeRegistrationInterceptor interceptor) + where TService : class + { + return RegisterCallee(typeof(TService), instanceProvider, interceptor); + } + + + public Task RegisterCallee(Func instanceProvider) + where TService : class + { + return RegisterCallee(typeof(TService), instanceProvider); + } + + public Task RegisterCallee(Type type, Func instanceProvider, ICalleeRegistrationInterceptor interceptor) { IEnumerable operationsToRegister = - mExtractor.ExtractOperations(instance, interceptor); + mExtractor.ExtractOperations(type, instanceProvider, interceptor); - List> registrations = + List> registrations = new List>(); foreach (OperationToRegister operationToRegister in operationsToRegister) { - Task task = + Task task = mProxy.RpcCatalog.Register(operationToRegister.Operation, operationToRegister.Options); registrations.Add(task); @@ -81,6 +106,15 @@ public IWampSubject GetSubject(string topicUri) return result; } + public ISubject GetSubject(string topicUri, IWampEventValueTupleConverter converter) + { + IWampSubject subject = GetSubject(topicUri); + + WampTupleTopicSubject result = new WampTupleTopicSubject(subject, converter); + + return result; + } + public IDisposable RegisterPublisher(object instance) { return RegisterPublisher(instance, new PublisherRegistrationInterceptor()); diff --git a/src/net45/WampSharp/WAMP2/V2/Api/IWampRealmServiceProvider.cs b/src/net45/WampSharp/WAMP2/V2/Api/IWampRealmServiceProvider.cs index 584cfeed3..d1c3df367 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/IWampRealmServiceProvider.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/IWampRealmServiceProvider.cs @@ -30,7 +30,47 @@ public interface IWampRealmServiceProvider /// A task that is completed when all methods are registered - its result is a /// - disposing it will unregister the instance. Task RegisterCallee(object instance, ICalleeRegistrationInterceptor interceptor); - + + /// + /// Registers an instance of a type having methods decorated with + /// to the realm. + /// + /// The type of the service to register. + /// A delegate that creates an instance of the service type per call. + /// A task that is completed when all methods are registered - its result is a + /// - disposing it will unregister the instance. + Task RegisterCallee(Type serviceType, Func instanceProvider); + + /// + /// Registers an instance of a type having methods decorated with + /// to the realm. + /// + /// The type of the service to register. + /// A delegate that creates an instance of the service type per call. + /// An object which allows registration customization. + /// A task that is completed when all methods are registered - its result is a + /// - disposing it will unregister the instance. + Task RegisterCallee(Type serviceType, Func instanceProvider, ICalleeRegistrationInterceptor interceptor); + + /// + /// Registers an instance of a type having methods decorated with + /// to the realm. + /// + /// A delegate that creates an instance per call. + /// A task that is completed when all methods are registered - its result is a + /// - disposing it will unregister the instance. + Task RegisterCallee(Func instanceProvider) where TService : class; + + /// + /// Registers an instance of a type having methods decorated with + /// to the realm. + /// + /// A delegate that creates an instance per call. + /// An object which allows registration customization. + /// A task that is completed when all methods are registered - its result is a + /// - disposing it will unregister the instance. + Task RegisterCallee(Func instanceProvider, ICalleeRegistrationInterceptor interceptor) where TService : class; + /// /// Gets a proxy of a callee registered in the realm. /// @@ -98,5 +138,20 @@ public interface IWampRealmServiceProvider /// A Task that is finished when SUBSCRIBE is complete - its result is a /// - disposing it will unsubscribe from the topic. Task RegisterSubscriber(object instance, ISubscriberRegistrationInterceptor interceptor); + +#if !NET40 + + /// + /// Gets a representing a + /// WAMP topic in the realm. + /// + /// The WAMP topic uri. + /// An interface responsible for converting s into s + /// and vice versa + /// The requested subject. + ISubject GetSubject(string topicUri, IWampEventValueTupleConverter tupleConverter); + +#endif + } } \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/Rx/IWampEventValueTupleConverter.cs b/src/net45/WampSharp/WAMP2/V2/Api/Rx/IWampEventValueTupleConverter.cs new file mode 100644 index 000000000..922096ae9 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Api/Rx/IWampEventValueTupleConverter.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using WampSharp.Core.Serialization; + +namespace WampSharp.V2 +{ + public interface IWampEventValueTupleConverter + { + TTuple ToTuple(IWampSerializedEvent @event); + + TTuple ToTuple(IWampFormatter formatter, + TMessage[] argumentsArray, + IDictionary argumentKeywords); + + IWampEvent ToEvent(TTuple tuple); + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/Rx/SerializedValueFormatter.cs b/src/net45/WampSharp/WAMP2/V2/Api/Rx/SerializedValueFormatter.cs new file mode 100644 index 000000000..4033261bd --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Api/Rx/SerializedValueFormatter.cs @@ -0,0 +1,35 @@ +using System; +using WampSharp.Core.Serialization; +using WampSharp.V2.Core; + +namespace WampSharp.V2 +{ + internal class SerializedValueFormatter : IWampFormatter + { + public static readonly IWampFormatter Value = new SerializedValueFormatter(); + + private SerializedValueFormatter() + { + } + + public bool CanConvert(ISerializedValue argument, Type type) + { + return true; + } + + public TTarget Deserialize(ISerializedValue message) + { + return message.Deserialize(); + } + + public object Deserialize(Type type, ISerializedValue message) + { + return message.Deserialize(type); + } + + public ISerializedValue Serialize(object value) + { + return new SerializedValue(WampObjectFormatter.Value, value); + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampClientSubject.cs b/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampClientSubject.cs index 64fd79916..296b202e7 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampClientSubject.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampClientSubject.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using SystemEx; using WampSharp.Core.Listener; -using WampSharp.V2.CalleeProxy; using WampSharp.V2.Client; using WampSharp.V2.Core.Contracts; using WampSharp.V2.Realm; diff --git a/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampEventValueTupleConverter.cs b/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampEventValueTupleConverter.cs new file mode 100644 index 000000000..c6ed63fc5 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampEventValueTupleConverter.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using WampSharp.Core.Serialization; +using WampSharp.Core.Utilities.ValueTuple; +using WampSharp.V2.Core; + +namespace WampSharp.V2 +{ + /// + /// A default implementation of . + /// + /// + /// + /// Derive from this class and specify your desired tuple type. + /// + /// + /// public class MyEventValueTupleConverter : WampEventValueTupleConverter{(int x, int y)} + /// { + /// } + /// + public abstract class WampEventValueTupleConverter : IWampEventValueTupleConverter + { + private readonly ArgumentUnpacker mArgumentUnpacker; + private readonly ValueTupleArrayConverter mArrayConverter; + private readonly ValueTupleDictionaryConverter mDictionaryConverter; + private static readonly object[] mEmptyArguments = new object[0]; + + protected WampEventValueTupleConverter() + { + Type tupleType = typeof(TTuple); + + if (!tupleType.IsValueTuple()) + { + throw new ArgumentException("Expected TTuple to be a ValueTuple"); + } + + if (!tupleType.IsValidTupleType()) + { + throw new ArgumentException("TTuple is an invalid ValueTuple. Expected TRest to be a ValueTuple."); + } + + mArrayConverter = ValueTupleArrayConverter.Value; + + Type converterType = GetConverterType(); + + ValidateConverterType(converterType); + + IList transformNames = GetTransformNames(converterType); + + int tupleLength = tupleType.GetValueTupleLength(); + + ValidateTransformNames(transformNames, tupleLength); + + if (transformNames != null) + { + if (transformNames.Take(tupleLength).All(x => x != null)) + { + mDictionaryConverter = + ValueTupleDictionaryConverterBuilder.Build(tupleType, transformNames); + } + } + + mArgumentUnpacker = + ArgumentUnpackerHelper.GetValueTupleArgumentUnpacker + (tupleType, transformNames); + } + + private void ValidateConverterType(Type converterType) + { + if (converterType.IsGenericType()) + { + Type genericTypeDefinition = + converterType.GetGenericTypeDefinition(); + + Type genericTypeDefinitionBase = + genericTypeDefinition.BaseType(); + + Type genericTypeDefinitionBaseTupleType = + genericTypeDefinitionBase.GetGenericArguments()[0]; + + if (!genericTypeDefinitionBaseTupleType.IsValueTuple()) + { + throw new ArgumentException( + string.Format( + "Expected a class deriving directly from {0} to specify a ValueTuple as the generic parameter TTuple", + typeof(WampEventValueTupleConverter<>).Name)); + } + } + } + + private void ValidateTransformNames(IList transformNames, int tupleLength) + { + if (transformNames != null) + { + IEnumerable relevantNames = + transformNames.Take(tupleLength).ToList(); + + if (!(relevantNames.All(x => x == null) || + relevantNames.All(x => x != null))) + { + throw new ArgumentException( + "Expected all TTuple elements to have a name or non of them to have a name"); + } + } + } + + private IList GetTransformNames(Type converterType) + { + IList transformNames = null; + + if (converterType.IsDefined(typeof(TupleElementNamesAttribute), true)) + { + TupleElementNamesAttribute attribute = + converterType.GetCustomAttribute(); + + transformNames = attribute.TransformNames; + } + + return transformNames; + } + + private Type GetConverterType() + { + Type currentType = this.GetType(); + + Type baseType = typeof(WampEventValueTupleConverter); + + while (currentType.BaseType() != baseType) + { + currentType = currentType.BaseType(); + } + + return currentType; + } + + public virtual TTuple ToTuple(IWampSerializedEvent @event) + { + return ToTuple(SerializedValueFormatter.Value, @event.Arguments, @event.ArgumentsKeywords); + } + + public virtual TTuple ToTuple(IWampFormatter formatter, + TMessage[] argumentsArray, + IDictionary argumentKeywords) + { + object[] unpacked = + mArgumentUnpacker.UnpackParameters(formatter, + argumentsArray, + argumentKeywords); + + return (TTuple) mArrayConverter.ToTuple(unpacked); + } + + public virtual IWampEvent ToEvent(TTuple tuple) + { + IDictionary argumentsKeywords = null; + + object[] arguments = mEmptyArguments; + + if (mDictionaryConverter != null) + { + argumentsKeywords = mDictionaryConverter.ToDictionary(tuple); + } + else + { + arguments = mArrayConverter.ToArray(tuple); + } + + WampEvent result = + new WampEvent + { + Arguments = arguments, + ArgumentsKeywords = argumentsKeywords + }; + + return result; + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampSubject.cs b/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampSubject.cs index fe5d36882..1fcd0d974 100644 --- a/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampSubject.cs +++ b/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampSubject.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using WampSharp.V2.Core.Contracts; namespace WampSharp.V2 diff --git a/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampTupleTopicSubject.cs b/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampTupleTopicSubject.cs new file mode 100644 index 000000000..882aa5c9c --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Api/Rx/WampTupleTopicSubject.cs @@ -0,0 +1,43 @@ +using System; +using System.Reactive.Linq; +using System.Reactive.Subjects; + +namespace WampSharp.V2 +{ + internal class WampTupleTopicSubject : ISubject + { + private readonly IWampSubject mSubject; + private readonly IWampEventValueTupleConverter mConverter; + private readonly IObservable mObservable; + + public WampTupleTopicSubject(IWampSubject subject, IWampEventValueTupleConverter converter) + { + mSubject = subject; + mConverter = converter; + + mObservable = + mSubject.Select(x => mConverter.ToTuple(x)); + } + + public void OnNext(TTuple value) + { + IWampEvent wampEvent = mConverter.ToEvent(value); + mSubject.OnNext(wampEvent); + } + + public void OnError(Exception error) + { + mSubject.OnError(error); + } + + public void OnCompleted() + { + mSubject.OnCompleted(); + } + + public IDisposable Subscribe(IObserver observer) + { + return mObservable.Subscribe(observer); + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Core/ArgumentUnpacker.cs b/src/net45/WampSharp/WAMP2/V2/Core/ArgumentUnpacker.cs index df3467f1b..19f832ef9 100644 --- a/src/net45/WampSharp/WAMP2/V2/Core/ArgumentUnpacker.cs +++ b/src/net45/WampSharp/WAMP2/V2/Core/ArgumentUnpacker.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using WampSharp.Core.Serialization; using WampSharp.V2.Core.Contracts; @@ -31,7 +32,7 @@ public object[] UnpackParameters(IWampFormatter formatter, int positionalArguments = 0; - if (arguments != null) + if (!SkipPositionalArguments && (arguments != null)) { positionalArguments = arguments.Length; @@ -49,6 +50,8 @@ public object[] UnpackParameters(IWampFormatter formatter, return result; } + public bool SkipPositionalArguments { get; set; } + private object ConvertParameter(IWampFormatter formatter, LocalParameter parameter, TMessage value) { return formatter.Deserialize(parameter.Type, value); @@ -90,7 +93,7 @@ private object ConvertNamedParameter(IWampFormatter formatte } catch (Exception ex) { - throw NameError(parameter.Name); + throw NameError(parameter.Name, ex); } } @@ -104,18 +107,18 @@ private object GetPositionalParameterValue(IWampFormatter fo } catch (Exception ex) { - throw PositionError(parameter.Position); + throw PositionError(parameter.Position, ex); } } - protected virtual Exception NameError(string name) + protected virtual Exception NameError(string name, Exception exception = null) { - return new WampException(WampErrors.InvalidArgument, "argument name: " + name); + return new WampInvalidArgumentException("argument name: " + name, exception); } - protected virtual Exception PositionError(int position) + protected virtual Exception PositionError(int position, Exception exception = null) { - return new WampException(WampErrors.InvalidArgument, "argument position: " + position); + return new WampInvalidArgumentException("argument position: " + position, exception); } } } \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Core/ArgumentUnpackerHelper.cs b/src/net45/WampSharp/WAMP2/V2/Core/ArgumentUnpackerHelper.cs new file mode 100644 index 000000000..7cae2efd3 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Core/ArgumentUnpackerHelper.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using WampSharp.Core.Utilities.ValueTuple; + +namespace WampSharp.V2.Core +{ + internal static class ArgumentUnpackerHelper + { + public static ArgumentUnpacker GetValueTupleArgumentUnpacker(Type tupleType, IEnumerable tupleElementNames = null) + { + bool skipPositionalArguments; + + if (tupleElementNames != null) + { + skipPositionalArguments = true; + } + else + { + tupleElementNames = Enumerable.Repeat(default(string), tupleType.GetValueTupleLength()); + skipPositionalArguments = false; + } + + var argumentTypes = + tupleType.GetValueTupleElementTypes() + .Select((type, index) => new { type, index }); + + IEnumerable localParameters = + tupleElementNames. + Zip(argumentTypes, + (name, typeToIndex) => + new LocalParameter(name, + typeToIndex.type, + typeToIndex.index)); + + ArgumentUnpacker result = new ArgumentUnpacker(localParameters.ToArray()); + + result.SkipPositionalArguments = skipPositionalArguments; + + return result; + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Core/Contracts/WampInvalidArgumentException.cs b/src/net45/WampSharp/WAMP2/V2/Core/Contracts/WampInvalidArgumentException.cs new file mode 100644 index 000000000..16e8654db --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Core/Contracts/WampInvalidArgumentException.cs @@ -0,0 +1,19 @@ +using System; +using System.Runtime.Serialization; + +namespace WampSharp.V2.Core.Contracts +{ + [Serializable] + public class WampInvalidArgumentException : WampException + { + public WampInvalidArgumentException(string details, Exception innerException) : + base(null, + WampErrors.InvalidArgument, + new object[] {details}, + null, + "Unable to deserialize a given argument. " + details, + innerException) + { + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Core/Listener/WampListener.cs b/src/net45/WampSharp/WAMP2/V2/Core/Listener/WampListener.cs index 0b1cdc565..0a5e9b06e 100644 --- a/src/net45/WampSharp/WAMP2/V2/Core/Listener/WampListener.cs +++ b/src/net45/WampSharp/WAMP2/V2/Core/Listener/WampListener.cs @@ -44,7 +44,7 @@ protected override void OnNewConnection(IWampConnection connection) IWampClientProxy client = ClientContainer.GetClient(connection); - mLogger.DebugFormat("Client connected, session id: " + client.Session); + mLogger.DebugFormat("Client connected, session id: {SessionId}", client.Session); mSessionHandler.OnNewClient(client); } @@ -55,7 +55,7 @@ protected override void OnCloseConnection(IWampConnection connection) if (ClientContainer.TryGetClient(connection, out client)) { - mLogger.DebugFormat("Client disconnected, session id: " + client.Session); + mLogger.DebugFormat("Client disconnected, session id: {SessionId}", client.Session); mSessionHandler.OnClientDisconnect(client); } diff --git a/src/net45/WampSharp/WAMP2/V2/PCL/CodeGeneration/OutRefProxyMethodWriter.cs b/src/net45/WampSharp/WAMP2/V2/PCL/CodeGeneration/OutRefProxyMethodWriter.cs index f0b10f8fb..869fad92c 100644 --- a/src/net45/WampSharp/WAMP2/V2/PCL/CodeGeneration/OutRefProxyMethodWriter.cs +++ b/src/net45/WampSharp/WAMP2/V2/PCL/CodeGeneration/OutRefProxyMethodWriter.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using WampSharp.V2.Rpc; +using WampSharp.Core.Utilities; namespace WampSharp.CodeGeneration { @@ -11,17 +11,19 @@ internal class OutRefProxyMethodWriter : IProxyMethodWriter { private readonly string mFieldDeclaration = @" -private static readonly MethodInfo mMethod{$methodIndex} = - GetMethodInfo(() => - { +private static readonly InvokeSyncDelegate<{$genericType}> mMethodHandler{$methodIndex} = + GetInvokeSync<{$genericType}>( + GetMethodInfo(() => + { {$variableDefaultAssignments} - return (Expression>) - (x => x.{$methodName}({$qualifiedVariableList})); - });"; + return (Expression>) + (x => x.{$methodName}({$qualifiedVariableList})); + }) +);"; private readonly string mDefaultAssignment = -" {$parameterType} {$parameterName} = default({$parameterType});"; +" {$parameterType} {$parameterName} = default({$parameterType});"; public string WriteField(int methodIndex, MethodInfo method) { @@ -31,6 +33,8 @@ public string WriteField(int methodIndex, MethodInfo method) dictionary["methodIndex"] = methodIndex.ToString(); dictionary["interfaceType"] = FormatTypeExtensions.FormatType(type); + Type returnType = TaskExtensions.UnwrapReturnType(method.ReturnType); + dictionary["genericType"] = FormatTypeExtensions.FormatType(returnType); dictionary["methodName"] = method.Name; dictionary["qualifiedVariableList"] = string.Join(", ", @@ -80,14 +84,14 @@ private string GetQualifiedName(ParameterInfo parameterInfo, public {$returnType} {$methodName}({$parametersDeclaration}) { object[] ___array = new object[] { {$array} }; - {$varResult}{$invokeMethod}{$genericType}({$parameterList}); + {$varResult}{$methodHandler}({$parameterList}); {$unpack} {$return} }"; public string WriteMethod(int methodIndex, MethodInfo method) { - string methodField = "mMethod" + methodIndex; + string methodHandler = "mMethodHandler" + methodIndex; IDictionary dictionary = new Dictionary(); @@ -103,40 +107,22 @@ public string WriteMethod(int methodIndex, MethodInfo method) dictionary["parameterList"] = string.Join(", ", - new[] {methodField, "___array"}); + new[] {"this", "___array"}); Type returnType = method.ReturnType; dictionary["returnType"] = FormatTypeExtensions.FormatType(returnType); - string invokeMethod; - - invokeMethod = "InvokeSync"; - if (returnType != typeof(void)) { dictionary["varResult"] = "var ___result = "; dictionary["return"] = "return ___result;"; - dictionary["genericType"] = CodeGenerationHelper.GetGenericType(returnType); } else { dictionary["varResult"] = string.Empty; dictionary["return"] = "return;"; - dictionary["genericType"] = string.Empty; } - if (!method.HasMultivaluedResult()) - { - invokeMethod = "Single" + invokeMethod; - } - else - { - invokeMethod = "Multi" + invokeMethod; - dictionary["genericType"] = CodeGenerationHelper.GetGenericType(returnType.GetElementType()); - } - - dictionary["invokeMethod"] = invokeMethod; - dictionary["parametersDeclaration"] = string.Join(", ", parameters.Select @@ -148,6 +134,8 @@ public string WriteMethod(int methodIndex, MethodInfo method) parameters.Where(x => x.IsOut || x.ParameterType.IsByRef) .Select(x => GetUnpackStatement(x))); + dictionary["methodHandler"] = methodHandler; + return CodeGenerationHelper.ProcessTemplate(mMethodTemplate, dictionary); } diff --git a/src/net45/WampSharp/WAMP2/V2/PCL/CodeGeneration/SimpleProxyMethodWriter.cs b/src/net45/WampSharp/WAMP2/V2/PCL/CodeGeneration/SimpleProxyMethodWriter.cs index f380e7087..bbb60b471 100644 --- a/src/net45/WampSharp/WAMP2/V2/PCL/CodeGeneration/SimpleProxyMethodWriter.cs +++ b/src/net45/WampSharp/WAMP2/V2/PCL/CodeGeneration/SimpleProxyMethodWriter.cs @@ -15,12 +15,45 @@ internal class SimpleProxyMethodWriter : IProxyMethodWriter @" public {$returnType} {$methodName}({$parametersDeclaration}) { - {$return}{$invokeMethod}{$genericType}({$parameterList}); + {$return}{$methodHandler}({$parameterList}); }"; + private string GetDelegateType(MethodInfo method) + { + string prefix = GetDelegateNamePrefix(method); + + Type returnType = TaskExtensions.UnwrapReturnType(method.ReturnType); + + string returnTypeAlias = FormatTypeExtensions.FormatType(returnType); + + string result = string.Format("{0}Delegate<{1}>", prefix, returnTypeAlias); + + return result; + } + + private static string GetDelegateNamePrefix(MethodInfo method) + { + string result; + + if (method.GetCustomAttribute() != null) + { + result = "InvokeProgressiveAsync"; + } + else if (typeof(Task).IsAssignableFrom(method.ReturnType)) + { + result = "InvokeAsync"; + } + else + { + result = "InvokeSync"; + } + + return result; + } + public string WriteMethod(int methodIndex, MethodInfo method) { - string methodField = "mMethod" + methodIndex; + string methodHandler = "mMethodHandler" + methodIndex; IDictionary dictionary = new Dictionary(); @@ -29,61 +62,28 @@ public string WriteMethod(int methodIndex, MethodInfo method) dictionary["methodName"] = method.Name; dictionary["parameterList"] = - string.Join(", ", - new[] {methodField}.Concat(parameters.Select(x => x.Name))); + string.Join(", ", new [] {"this"}.Concat(parameters.Select(x => x.Name))); dictionary["returnType"] = FormatTypeExtensions.FormatType(method.ReturnType); - string invokeMethod; - if (method.GetCustomAttribute() != null) { - invokeMethod = "InvokeProgressiveAsync"; - dictionary["parameterList"] = string.Join(", ", - new[] {methodField}.Concat - (new[] {parameters.Last()}.Concat(parameters.Take(parameters.Length - 1)) - .Select(x => x.Name))); - } - else if (typeof (Task).IsAssignableFrom(method.ReturnType)) - { - invokeMethod = "InvokeAsync"; + new [] {"this"}.Concat(new[] { parameters.Last() }.Concat(parameters.Take(parameters.Length - 1)) + .Select(x => x.Name))); } - else - { - invokeMethod = "InvokeSync"; - } - - Type returnType = TaskExtensions.UnwrapReturnType(method.ReturnType); if (method.ReturnType != typeof(void)) { dictionary["return"] = "return "; - dictionary["genericType"] = CodeGenerationHelper.GetGenericType(returnType); } else { dictionary["return"] = string.Empty; - dictionary["genericType"] = string.Empty; - } - - if (method.ReturnType == typeof (Task)) - { - dictionary["genericType"] = string.Empty; - } - - if (!method.HasMultivaluedResult()) - { - invokeMethod = "Single" + invokeMethod; - } - else - { - invokeMethod = "Multi" + invokeMethod; - dictionary["genericType"] = CodeGenerationHelper.GetGenericType(returnType.GetElementType()); } - dictionary["invokeMethod"] = invokeMethod; + dictionary["methodHandler"] = methodHandler; dictionary["parametersDeclaration"] = string.Join(", ", @@ -94,7 +94,9 @@ public string WriteMethod(int methodIndex, MethodInfo method) } private string mFieldTemplate = - @"private static readonly MethodInfo mMethod{$methodIndex} = GetMethodInfo(({$interfaceType} instance) => instance.{$methodName}({$defaults}));"; + @"private static readonly {$delegateType} mMethodHandler{$methodIndex} = Get{$delegatePrefix}<{$genericType}>( + GetMethodInfo(({$interfaceType} instance) => instance.{$methodName}({$defaults})) +);"; public string WriteField(int methodIndex, MethodInfo method) { @@ -103,7 +105,11 @@ public string WriteField(int methodIndex, MethodInfo method) Type type = method.DeclaringType; dictionary["methodIndex"] = methodIndex.ToString(); + dictionary["delegateType"] = GetDelegateType(method); + dictionary["delegatePrefix"] = GetDelegateNamePrefix(method); dictionary["interfaceType"] = FormatTypeExtensions.FormatType(type); + Type genericType = TaskExtensions.UnwrapReturnType(method.ReturnType); + dictionary["genericType"] = FormatTypeExtensions.FormatType(genericType); dictionary["methodName"] = method.Name; dictionary["defaults"] = string.Join(", ", diff --git a/src/net45/WampSharp/WAMP2/V2/PubSub/Subscriber/MethodInfoSubscriber.cs b/src/net45/WampSharp/WAMP2/V2/PubSub/Subscriber/MethodInfoSubscriber.cs index 7c2f4d142..e9603d82d 100644 --- a/src/net45/WampSharp/WAMP2/V2/PubSub/Subscriber/MethodInfoSubscriber.cs +++ b/src/net45/WampSharp/WAMP2/V2/PubSub/Subscriber/MethodInfoSubscriber.cs @@ -76,7 +76,7 @@ protected override void InnerEvent } catch (Exception ex) { - mLogger.ErrorFormat(ex, "An error occured while calling " + mMethod); + mLogger.ErrorFormat(ex, "An error occured while calling {Method}", mMethod); } finally { diff --git a/src/net45/WampSharp/WAMP2/V2/PubSub/WampPubSubServer.cs b/src/net45/WampSharp/WAMP2/V2/PubSub/WampPubSubServer.cs index 93421c9eb..b90c5fe13 100644 --- a/src/net45/WampSharp/WAMP2/V2/PubSub/WampPubSubServer.cs +++ b/src/net45/WampSharp/WAMP2/V2/PubSub/WampPubSubServer.cs @@ -69,7 +69,7 @@ private void InnerPublish(IWampPublisher publisher, string topicUri, long reques catch (WampException ex) { mLogger.ErrorFormat(ex, - "Failed publishing to topic '{0}'. Publication request id: {1}", + "Failed publishing to topic '{TopicUri}'. Publication request id: {RequestId}", topicUri, requestId); PublishErrorIfNeeded(publisher, requestId, acknowledge, ex); @@ -111,7 +111,7 @@ public void Subscribe(IWampSubscriber subscriber, long requestId, SubscribeOptio catch (WampException ex) { mLogger.ErrorFormat(ex, - "Failed subscribing to topic '{0}'. Subscription request id: {1}", + "Failed subscribing to topic '{TopicUri}'. Subscription request id: {RequestId}", topicUri, requestId); subscriber.SubscribeError(requestId, ex); diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/AsyncLocalRpcOperation.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/AsyncLocalRpcOperation.cs index ad32f1fdc..45d11c949 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/AsyncLocalRpcOperation.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/AsyncLocalRpcOperation.cs @@ -36,11 +36,11 @@ protected override async void InnerInvoke(IWampRawRpcOperationRouterCa object result = await task; - CallResult(caller, result, null); + CallResult(caller, result); } catch (Exception ex) { - mLogger.ErrorFormat(ex, "An error occured while calling {0}", this.Procedure); + mLogger.ErrorFormat(ex, "An error occured while calling {ProcedureUri}", this.Procedure); WampException wampException = ex as WampException; @@ -83,7 +83,7 @@ private void TaskCallback(Task task, IWampRawRpcOperationRouterCallback if (task.Exception == null) { object result = task.Result; - CallResult(caller, result, null); + CallResult(caller, result); } else { @@ -105,5 +105,26 @@ private void TaskCallback(Task task, IWampRawRpcOperationRouterCallback } #endif + + + protected void CallResult(IWampRawRpcOperationRouterCallback caller, object result, YieldOptions yieldOptions = null) + { + yieldOptions = yieldOptions ?? new YieldOptions(); + + object[] resultArguments = GetResultArguments(result); + + IDictionary resultArgumentKeywords = + GetResultArgumentKeywords(result); + + CallResult(caller, + yieldOptions, + resultArguments, + resultArgumentKeywords); + } + + protected virtual IDictionary GetResultArgumentKeywords(object result) + { + return null; + } } } \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/LocalRpcOperation.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/LocalRpcOperation.cs index 749e09df1..db546e48d 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/LocalRpcOperation.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/LocalRpcOperation.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using WampSharp.Logging; - using WampSharp.Core.Serialization; using WampSharp.V2.Core; using WampSharp.V2.Core.Contracts; @@ -12,8 +12,6 @@ namespace WampSharp.V2.Rpc { public abstract class LocalRpcOperation : IWampRpcOperation { - private static readonly object[] mEmptyResult = new object[0]; - private readonly string mProcedure; protected readonly ILog mLogger; @@ -70,27 +68,18 @@ public void Invoke(IWampRawRpcOperationRouterCallback caller, IWampFor InnerInvoke(caller, formatter, details, arguments, argumentsKeywords); } - protected void CallResult(IWampRawRpcOperationRouterCallback caller, object result, IDictionary outputs) + protected virtual object[] GetResultArguments(object result) { - YieldOptions options = new YieldOptions(); - - object[] resultArguments = mEmptyResult; + IWampResultExtractor extractor = WampResultExtractor.GetResultExtractor(this); - if (this.HasResult) - { - if (this.CollectionResultTreatment == CollectionResultTreatment.Multivalued) - { - resultArguments = GetFlattenResult((dynamic) result); - } - else - { - resultArguments = new object[] {result}; - } - } + return extractor.GetArguments(result); + } - if (outputs != null) + protected void CallResult(IWampRawRpcOperationRouterCallback caller, YieldOptions options, object[] arguments, IDictionary argumentKeywords) + { + if (argumentKeywords != null) { - caller.Result(ObjectFormatter, options, resultArguments, outputs); + caller.Result(ObjectFormatter, options, arguments, argumentKeywords); } else if (!this.HasResult) { @@ -98,20 +87,10 @@ protected void CallResult(IWampRawRpcOperationRouterCallback caller, object resu } else { - caller.Result(ObjectFormatter, options, resultArguments); + caller.Result(ObjectFormatter, options, arguments); } } - private object[] GetFlattenResult(ICollection result) - { - return result.Cast().ToArray(); - } - - private object[] GetFlattenResult(object result) - { - return new object[] {result}; - } - protected object[] UnpackParameters(IWampFormatter formatter, TMessage[] arguments, IDictionary argumentsKeywords) @@ -131,6 +110,17 @@ protected abstract void InnerInvoke TMessage[] arguments, IDictionary argumentsKeywords); + + protected void ValidateInstanceType(object instance, MethodInfo method) + { + Type declaringType = method.DeclaringType; + + if (!declaringType.IsInstanceOfType(instance)) + { + throw new ArgumentException("Expected an instance of type " + declaringType); + } + } + protected class WampRpcErrorCallback : IWampErrorCallback { private readonly IWampRawRpcOperationRouterCallback mCallback; diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/AsyncMethodInfoRpcOperation.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/AsyncMethodInfoRpcOperation.cs index ac32d316b..e82ea1bf7 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/AsyncMethodInfoRpcOperation.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/AsyncMethodInfoRpcOperation.cs @@ -5,23 +5,26 @@ using System.Threading.Tasks; using WampSharp.Core.Serialization; using WampSharp.Core.Utilities; +using WampSharp.Core.Utilities.ValueTuple; using WampSharp.V2.Core.Contracts; +using TaskExtensions = WampSharp.Core.Utilities.TaskExtensions; namespace WampSharp.V2.Rpc { public class AsyncMethodInfoRpcOperation : AsyncLocalRpcOperation { - private readonly object mInstance; + private readonly Func mInstanceProvider; private readonly MethodInfo mMethod; private readonly Func mMethodInvoker; private readonly RpcParameter[] mParameters; private readonly bool mHasResult; private readonly CollectionResultTreatment mCollectionResultTreatment; + private IWampResultExtractor mResultExtractor; - public AsyncMethodInfoRpcOperation(object instance, MethodInfo method, string procedureName) : + public AsyncMethodInfoRpcOperation(Func instanceProvider, MethodInfo method, string procedureName) : base(procedureName) { - mInstance = instance; + mInstanceProvider = instanceProvider; mMethod = method; mMethodInvoker = MethodInvokeGenerator.CreateTaskInvokeMethod(method); @@ -41,8 +44,14 @@ public AsyncMethodInfoRpcOperation(object instance, MethodInfo method, string pr method.GetParameters() .Select(parameter => new RpcParameter(parameter)) .ToArray(); - } + mResultExtractor = WampResultExtractor.GetResultExtractor(this); + + if (method.ReturnsTuple()) + { + mResultExtractor = WampResultExtractor.GetValueTupleResultExtractor(method); + } + } public override RpcParameter[] Parameters { @@ -75,8 +84,12 @@ protected override Task InvokeAsync(IWampRawRpcOperationRouter object[] unpacked = GetMethodParameters(caller, formatter, arguments, argumentsKeywords); + object instance = mInstanceProvider(); + + ValidateInstanceType(instance, mMethod); + Task result = - mMethodInvoker(mInstance, unpacked); + mMethodInvoker(instance, unpacked); Task casted = result as Task; @@ -88,9 +101,19 @@ protected override Task InvokeAsync(IWampRawRpcOperationRouter } } + protected override object[] GetResultArguments(object result) + { + return mResultExtractor.GetArguments(result); + } + + protected override IDictionary GetResultArgumentKeywords(object result) + { + return mResultExtractor.GetArgumentKeywords(result); + } + protected bool Equals(AsyncMethodInfoRpcOperation other) { - return Equals(mInstance, other.mInstance) && Equals(mMethod, other.mMethod) && string.Equals(Procedure, other.Procedure); + return Equals(mInstanceProvider, other.mInstanceProvider) && Equals(mMethod, other.mMethod) && string.Equals(Procedure, other.Procedure); } public override bool Equals(object obj) @@ -105,7 +128,7 @@ public override int GetHashCode() { unchecked { - var hashCode = (mInstance != null ? mInstance.GetHashCode() : 0); + var hashCode = (mInstanceProvider != null ? mInstanceProvider.GetHashCode() : 0); hashCode = (hashCode*397) ^ (mMethod != null ? mMethod.GetHashCode() : 0); hashCode = (hashCode*397) ^ (Procedure != null ? Procedure.GetHashCode() : 0); return hashCode; diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/CallerProgress.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/CallerProgress.cs deleted file mode 100644 index 8a76496ba..000000000 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/CallerProgress.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using WampSharp.V2.Core; -using WampSharp.V2.Core.Contracts; - -namespace WampSharp.V2.Rpc -{ - internal class CallerProgress : IProgress - { - private readonly IWampRawRpcOperationRouterCallback mCaller; - - public CallerProgress(IWampRawRpcOperationRouterCallback caller) - { - mCaller = caller; - } - - public void Report(T value) - { - mCaller.Result(WampObjectFormatter.Value, - new YieldOptions {Progress = true}, - new object[] {value}); - } - } -} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/IOperationExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/IOperationExtractor.cs index 92f9a8a7b..7c31d82b3 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/IOperationExtractor.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/IOperationExtractor.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using WampSharp.V2.Core.Contracts; namespace WampSharp.V2.Rpc { internal interface IOperationExtractor { - IEnumerable ExtractOperations(object instance, ICalleeRegistrationInterceptor interceptor); + IEnumerable ExtractOperations(Type serviceType, Func instance, ICalleeRegistrationInterceptor interceptor); } internal class OperationToRegister diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/MethodInfoValidation.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/MethodInfoValidation.cs index 4d716a856..6d74337e4 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/MethodInfoValidation.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/MethodInfoValidation.cs @@ -1,18 +1,76 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using WampSharp.Core.Utilities; +using WampSharp.Core.Utilities.ValueTuple; namespace WampSharp.V2.Rpc { internal class MethodInfoValidation { + public static void ValidateTupleReturnType(MethodInfo method) + { + if (method.ReturnsTuple()) + { + Type returnType = method.ReturnType; + Type tupleType = TaskExtensions.UnwrapReturnType(returnType); + + if (!tupleType.IsValidTupleType()) + { + ThrowHelper.MethodReturnsInvalidValueTuple(method); + } + + if (method.ReturnParameter.IsDefined(typeof(TupleElementNamesAttribute))) + { + int tupleLength = tupleType.GetValueTupleLength(); + + TupleElementNamesAttribute attribute = + method.ReturnParameter.GetCustomAttribute(); + + IList transformNames = attribute.TransformNames; + + List tupleNames = + transformNames.Take(tupleLength).ToList(); + + ValidateTupleReturnType(method, tupleNames); + ValidateTupleReturnTypeWithOutRefParameters(method, tupleNames); + } + } + } + + private static void ValidateTupleReturnTypeWithOutRefParameters(MethodInfo method, IEnumerable tupleNames) + { + IEnumerable outOrRefNames = + method.GetParameters().Where(x => x.IsOut || x.ParameterType.IsByRef) + .Select(x => x.Name); + + ICollection intersection = + tupleNames.Intersect(outOrRefNames).ToList(); + + if (intersection.Count > 0) + { + ThrowHelper.TupleReturnTypeAndOutRefParametersHaveCommonNames(method, intersection); + } + } + + private static void ValidateTupleReturnType(MethodInfo method, IList tupleNames) + { + if (tupleNames.Any(x => x == null) && tupleNames.Any(x => x != null)) + { + ThrowHelper.InvalidTupleReturnType(method); + } + } + public static void ValidateAsyncMethod(MethodInfo method) { if (method.GetParameters().Any(x => x.IsOut || x.ParameterType.IsByRef)) { ThrowHelper.AsyncOutRefMethod(method); } + + ValidateTupleReturnType(method); } public static void ValidateProgressiveMethod(MethodInfo method) @@ -31,6 +89,35 @@ public static void ValidateProgressiveMethod(MethodInfo method) { ThrowHelper.ProgressiveParameterTypeMismatch(method, returnType); } + + ValidateTupleReturnTypeOfProgressiveMethod(method, lastParameter); + } + + private static void ValidateTupleReturnTypeOfProgressiveMethod(MethodInfo method, ParameterInfo lastParameter) + { + bool methodHasAttribute = method.ReturnParameter.IsDefined(typeof(TupleElementNamesAttribute)); + bool parameterHasAttributte = lastParameter.IsDefined(typeof(TupleElementNamesAttribute)); + + bool attributesMatch = methodHasAttribute == parameterHasAttributte; + + if (methodHasAttribute && parameterHasAttributte) + { + TupleElementNamesAttribute methodAttribute = + method.ReturnParameter.GetCustomAttribute(); + + TupleElementNamesAttribute parameterAttribute = + lastParameter.GetCustomAttribute(); + + IList methodTransformNames = methodAttribute.TransformNames; + IList parameterTransformNames = parameterAttribute.TransformNames; + + attributesMatch = methodTransformNames.SequenceEqual(parameterTransformNames); + } + + if (!attributesMatch) + { + ThrowHelper.ProgressiveParameterTupleMismatch(method); + } } private static class ThrowHelper @@ -50,6 +137,39 @@ public static void ProgressiveParameterTypeMismatch(MethodInfo method, Type retu "Method {0} of type {1} is declared as a progressive WAMP procedure, but its last parameter is not a IProgress of its return type. Expected: IProgress<{2}>", method.Name, method.DeclaringType.FullName, returnType.FullName)); } + + public static void ProgressiveParameterTupleMismatch(MethodInfo method) + { + throw new ArgumentException + (String.Format( + "Method {0} of type {1} is declared as a progressive WAMP procedure that returns a tuple, but its last parameter tuple definition does not match its return type tuple definition.", + method.Name, method.DeclaringType.FullName)); + } + + public static void InvalidTupleReturnType(MethodInfo method) + { + throw new ArgumentException + (String.Format( + "Method {0} of type {1} is declared as a WAMP procedure that returns a tuple which some of its elements have names and some don't. Expected all tuple elements have names or none of them have names.", + method.Name, method.DeclaringType.FullName)); + } + + public static void TupleReturnTypeAndOutRefParametersHaveCommonNames(MethodInfo method, ICollection intersection) + { + throw new ArgumentException + (String.Format( + "Method {0} of type {1} is declared as a WAMP procedure that returns a tuple and also has out/ref parameters. There exists some tuple elements with the same names as some of the out/ref parameters. Expected out/ref and element names of returned tuple to be distinct. Details: conflicted names {2}", + method.Name, method.DeclaringType.FullName, + string.Join(", ", intersection))); + } + + public static void MethodReturnsInvalidValueTuple(MethodInfo method) + { + throw new ArgumentException + (String.Format( + "Method {0} of type {1} returns an invalid ValueTuple. Expected TRest to be a ValueTuple.", + method.Name, method.DeclaringType.FullName)); + } } } } \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/OperationExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/OperationExtractor.cs index 9505154a4..52c9150ab 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/OperationExtractor.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/OperationExtractor.cs @@ -10,10 +10,9 @@ namespace WampSharp.V2.Rpc { internal class OperationExtractor : IOperationExtractor { - public IEnumerable ExtractOperations(object instance, ICalleeRegistrationInterceptor interceptor) + public IEnumerable ExtractOperations(Type serviceType, Func instance, ICalleeRegistrationInterceptor interceptor) { - Type type = instance.GetType(); - IEnumerable typesToExplore = GetTypesToExplore(type); + IEnumerable typesToExplore = GetTypesToExplore(serviceType); foreach (Type currentType in typesToExplore) { @@ -38,7 +37,7 @@ private static IEnumerable GetTypesToExplore(Type type) } private IEnumerable GetServiceMethodsOfType - (object instance, + (Func instance, Type type, ICalleeRegistrationInterceptor interceptor) { @@ -54,31 +53,32 @@ private IEnumerable GetServiceMethodsOfType } } - protected IWampRpcOperation CreateRpcMethod(object instance, ICalleeRegistrationInterceptor interceptor, MethodInfo method) + protected IWampRpcOperation CreateRpcMethod(Func instanceProvider, ICalleeRegistrationInterceptor interceptor, MethodInfo method) { string procedureUri = interceptor.GetProcedureUri(method); if (!typeof (Task).IsAssignableFrom(method.ReturnType)) { - return new SyncMethodInfoRpcOperation(instance, method, procedureUri); + MethodInfoValidation.ValidateTupleReturnType(method); + return new SyncMethodInfoRpcOperation(instanceProvider, method, procedureUri); } else { if (method.IsDefined(typeof (WampProgressiveResultProcedureAttribute))) { MethodInfoValidation.ValidateProgressiveMethod(method); - return CreateProgressiveOperation(instance, method, procedureUri); + return CreateProgressiveOperation(instanceProvider, method, procedureUri); } else { MethodInfoValidation.ValidateAsyncMethod(method); - return new AsyncMethodInfoRpcOperation(instance, method, procedureUri); + return new AsyncMethodInfoRpcOperation(instanceProvider, method, procedureUri); } } } - private static IWampRpcOperation CreateProgressiveOperation(object instance, MethodInfo method, string procedureUri) + private static IWampRpcOperation CreateProgressiveOperation(Func instanceProvider, MethodInfo method, string procedureUri) { //return new ProgressiveAsyncMethodInfoRpcOperation // (instance, method, procedureUri); @@ -92,7 +92,7 @@ private static IWampRpcOperation CreateProgressiveOperation(object instance, Met IWampRpcOperation operation = (IWampRpcOperation) Activator.CreateInstance(operationType, - instance, + instanceProvider, method, procedureUri); diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ProgressiveAsyncMethodInfoRpcOperation.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ProgressiveAsyncMethodInfoRpcOperation.cs index db8204708..b893b6c1a 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ProgressiveAsyncMethodInfoRpcOperation.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ProgressiveAsyncMethodInfoRpcOperation.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Reflection; using WampSharp.Core.Serialization; +using WampSharp.V2.Core; +using WampSharp.V2.Core.Contracts; namespace WampSharp.V2.Rpc { @@ -9,8 +11,8 @@ public class ProgressiveAsyncMethodInfoRpcOperation : AsyncMethodInfoRpcOpera { private readonly RpcParameter[] mRpcParameters; - public ProgressiveAsyncMethodInfoRpcOperation(object instance, MethodInfo method, string procedureName) : - base(instance, method, procedureName) + public ProgressiveAsyncMethodInfoRpcOperation(Func instanceProvider, MethodInfo method, string procedureName) : + base(instanceProvider, method, procedureName) { RpcParameter[] baseParameters = base.Parameters; @@ -34,7 +36,7 @@ protected override object[] GetMethodParameters(IWampRawRpcOperationRo result, argumentsWithoutProgress.Length); - result[length - 1] = new CallerProgress(caller); + result[length - 1] = new CallerProgress(caller, this); return result; } @@ -46,5 +48,23 @@ public override RpcParameter[] Parameters return mRpcParameters; } } + + private class CallerProgress : IProgress + { + private readonly IWampRawRpcOperationRouterCallback mCaller; + private readonly ProgressiveAsyncMethodInfoRpcOperation mParent; + + public CallerProgress(IWampRawRpcOperationRouterCallback caller, + ProgressiveAsyncMethodInfoRpcOperation parent) + { + mCaller = caller; + mParent = parent; + } + + public void Report(T value) + { + mParent.CallResult(mCaller, value, new YieldOptions() {Progress = true}); + } + } } } \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/EmptyResultExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/EmptyResultExtractor.cs new file mode 100644 index 000000000..35a320c07 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/EmptyResultExtractor.cs @@ -0,0 +1,6 @@ +namespace WampSharp.V2.Rpc +{ + internal class EmptyResultExtractor : WampResultExtractor + { + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/IWampResultExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/IWampResultExtractor.cs new file mode 100644 index 000000000..6406215d5 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/IWampResultExtractor.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace WampSharp.V2.Rpc +{ + internal interface IWampResultExtractor + { + object[] GetArguments(object result); + IDictionary GetArgumentKeywords(object result); + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/MultiResultExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/MultiResultExtractor.cs new file mode 100644 index 000000000..857f08f2d --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/MultiResultExtractor.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; + +namespace WampSharp.V2.Rpc +{ + internal class MultiResultExtractor : WampResultExtractor + { + public override object[] GetArguments(object result) + { + return GetFlattenResult((dynamic) result); + } + + private object[] GetFlattenResult(ICollection result) + { + return result.Cast().ToArray(); + } + + private object[] GetFlattenResult(object result) + { + return new object[] {result}; + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/NamedTupleExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/NamedTupleExtractor.cs new file mode 100644 index 000000000..e580b38a8 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/NamedTupleExtractor.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using WampSharp.Core.Utilities.ValueTuple; + +namespace WampSharp.V2.Rpc +{ + internal class NamedTupleExtractor : WampResultExtractor + { + private readonly ValueTupleDictionaryConverter mConverter; + + public NamedTupleExtractor(Type tupleType, IList transformNames) + { + mConverter = + ValueTupleDictionaryConverterBuilder.Build(tupleType, transformNames); + } + + public override IDictionary GetArgumentKeywords(object result) + { + return mConverter.ToDictionary(result); + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/PositionalTupleExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/PositionalTupleExtractor.cs new file mode 100644 index 000000000..c7ac1f104 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/PositionalTupleExtractor.cs @@ -0,0 +1,20 @@ +using System; +using WampSharp.Core.Utilities.ValueTuple; + +namespace WampSharp.V2.Rpc +{ + internal class PositionalTupleExtractor : WampResultExtractor + { + private readonly ValueTupleArrayConverter mConverter; + + public PositionalTupleExtractor(Type tupleType) + { + mConverter = ValueTupleArrayConverter.Get(tupleType); + } + + public override object[] GetArguments(object result) + { + return mConverter.ToArray(result); + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/SingleResultExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/SingleResultExtractor.cs new file mode 100644 index 000000000..7da7eade8 --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/SingleResultExtractor.cs @@ -0,0 +1,10 @@ +namespace WampSharp.V2.Rpc +{ + internal class SingleResultExtractor : WampResultExtractor + { + public override object[] GetArguments(object result) + { + return new object[] {result}; + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/WampResultExtractor.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/WampResultExtractor.cs new file mode 100644 index 000000000..44badd84b --- /dev/null +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/ResultExtractor/WampResultExtractor.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using WampSharp.Core.Utilities; +using WampSharp.Core.Utilities.ValueTuple; + +namespace WampSharp.V2.Rpc +{ + internal abstract class WampResultExtractor : IWampResultExtractor + { + private static readonly object[] mEmptyResult = new object[0]; + + public virtual object[] GetArguments(object result) + { + return mEmptyResult; + } + + public virtual IDictionary GetArgumentKeywords(object result) + { + return null; + } + + public static IWampResultExtractor GetResultExtractor(LocalRpcOperation operation) + { + IWampResultExtractor extractor = new EmptyResultExtractor(); + + if (operation.HasResult) + { + if (operation.CollectionResultTreatment == CollectionResultTreatment.SingleValue) + { + extractor = new SingleResultExtractor(); + } + else + { + extractor = new MultiResultExtractor(); + } + } + + return extractor; + } + + public static IWampResultExtractor GetValueTupleResultExtractor(MethodInfo method) + { + Type tupleType = TaskExtensions.UnwrapReturnType(method.ReturnType); + + IWampResultExtractor result = new PositionalTupleExtractor(tupleType); + + if (method.ReturnParameter.IsDefined(typeof(TupleElementNamesAttribute))) + { + TupleElementNamesAttribute attribute = + method.ReturnParameter.GetCustomAttribute(); + + int valueTupleLength = tupleType.GetValueTupleLength(); + + // If the tuple is named, return a named tuple extractor + if (attribute.TransformNames.Take(valueTupleLength).All(x => x != null)) + { + result = new NamedTupleExtractor(tupleType, attribute.TransformNames); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/SyncMethodInfoRpcOperation.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/SyncMethodInfoRpcOperation.cs index 80cab2754..e50ea1b47 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/SyncMethodInfoRpcOperation.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/Reflection/SyncMethodInfoRpcOperation.cs @@ -4,24 +4,26 @@ using System.Reflection; using WampSharp.Core.Serialization; using WampSharp.Core.Utilities; +using WampSharp.Core.Utilities.ValueTuple; using WampSharp.V2.Core.Contracts; namespace WampSharp.V2.Rpc { public class SyncMethodInfoRpcOperation : SyncLocalRpcOperation { - private readonly object mInstance; + private readonly Func mInstanceProvider; private readonly MethodInfo mMethod; private readonly Func mMethodInvoker; private readonly MethodInfoHelper mHelper; private readonly RpcParameter[] mParameters; private readonly bool mHasResult; private readonly CollectionResultTreatment mCollectionResultTreatment; + private IWampResultExtractor mResultExtractor; - public SyncMethodInfoRpcOperation(object instance, MethodInfo method, string procedureName) : + public SyncMethodInfoRpcOperation(Func instanceProvider, MethodInfo method, string procedureName) : base(procedureName) { - mInstance = instance; + mInstanceProvider = instanceProvider; mMethod = method; mMethodInvoker = MethodInvokeGenerator.CreateInvokeMethod(method); @@ -44,6 +46,13 @@ public SyncMethodInfoRpcOperation(object instance, MethodInfo method, string pro .Where(x => !x.IsOut) .Select(parameter => new RpcParameter(parameter)) .ToArray(); + + mResultExtractor = WampResultExtractor.GetResultExtractor(this); + + if (method.ReturnsTuple()) + { + mResultExtractor = WampResultExtractor.GetValueTupleResultExtractor(method); + } } public override RpcParameter[] Parameters @@ -76,8 +85,12 @@ protected override object InvokeSync object[] parameters = mHelper.GetArguments(unpacked); + object instance = mInstanceProvider(); + + ValidateInstanceType(instance, mMethod); + object result = - mMethodInvoker(mInstance, parameters); + mMethodInvoker(instance, parameters); outputs = mHelper.GetOutOrRefValues(parameters); @@ -89,9 +102,35 @@ protected override object InvokeSync } } + protected override object[] GetResultArguments(object result) + { + return mResultExtractor.GetArguments(result); + } + + protected override IDictionary GetResultArgumentKeywords + (object result, IDictionary outputs) + { + IDictionary argumentKeywords = mResultExtractor.GetArgumentKeywords(result); + + if (argumentKeywords == null) + { + return outputs; + } + + if (outputs != null) + { + foreach (KeyValuePair keyValuePair in outputs) + { + argumentKeywords[keyValuePair.Key] = keyValuePair.Value; + } + } + + return argumentKeywords; + } + protected bool Equals(SyncMethodInfoRpcOperation other) { - return Equals(mInstance, other.mInstance) && Equals(mMethod, other.mMethod) && + return Equals(mInstanceProvider, other.mInstanceProvider) && Equals(mMethod, other.mMethod) && string.Equals(Procedure, other.Procedure); } @@ -107,7 +146,7 @@ public override int GetHashCode() { unchecked { - var hashCode = (mInstance != null ? mInstance.GetHashCode() : 0); + var hashCode = (mInstanceProvider != null ? mInstanceProvider.GetHashCode() : 0); hashCode = (hashCode*397) ^ (mMethod != null ? mMethod.GetHashCode() : 0); hashCode = (hashCode*397) ^ (Procedure != null ? Procedure.GetHashCode() : 0); return hashCode; diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/SyncLocalRpcOperation.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/SyncLocalRpcOperation.cs index 57744cb01..c9dbcac9c 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/SyncLocalRpcOperation.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Callee/SyncLocalRpcOperation.cs @@ -36,7 +36,7 @@ protected override void InnerInvoke(IWampRawRpcOperationRouterCallback } catch (WampException ex) { - mLogger.ErrorFormat(ex, "An error occured while calling {0}", this.Procedure); + mLogger.ErrorFormat(ex, "An error occured while calling {ProcedureUri}", this.Procedure); IWampErrorCallback callback = new WampRpcErrorCallback(caller); callback.Error(ex); } @@ -48,6 +48,25 @@ protected override void InnerInvoke(IWampRawRpcOperationRouterCallback } } + protected void CallResult(IWampRawRpcOperationRouterCallback caller, object result, IDictionary outputs, YieldOptions yieldOptions = null) + { + yieldOptions = yieldOptions ?? new YieldOptions(); + object[] resultArguments = GetResultArguments(result); + + IDictionary argumentKeywords = + GetResultArgumentKeywords(result, outputs); + + CallResult(caller, + yieldOptions, + resultArguments, + argumentKeywords); + } + + protected virtual IDictionary GetResultArgumentKeywords(object result, IDictionary outputs) + { + return outputs; + } + protected abstract object InvokeSync (IWampRawRpcOperationRouterCallback caller, IWampFormatter formatter, InvocationDetails details, TMessage[] arguments, IDictionary argumentsKeywords, out IDictionary outputs); } diff --git a/src/net45/WampSharp/WAMP2/V2/Rpc/Dealer/WampRpcServer.cs b/src/net45/WampSharp/WAMP2/V2/Rpc/Dealer/WampRpcServer.cs index 513b24737..e1eb80bf5 100644 --- a/src/net45/WampSharp/WAMP2/V2/Rpc/Dealer/WampRpcServer.cs +++ b/src/net45/WampSharp/WAMP2/V2/Rpc/Dealer/WampRpcServer.cs @@ -46,7 +46,7 @@ public void Register(IWampCallee callee, long requestId, RegisterOptions options catch (WampException exception) { mLogger.ErrorFormat(exception, - "Failed registering procedure '{0}'. Registration request id: {1} ", + "Failed registering procedure '{ProcedureUri}'. Registration request id: {RequestId} ", procedure, requestId); callee.RegisterError(requestId, exception); @@ -63,7 +63,7 @@ public void Unregister(IWampCallee callee, long requestId, long registrationId) catch (WampException exception) { mLogger.ErrorFormat(exception, - "Failed unregistering procedure with registration id {0}. Unregistration request id: {1} ", + "Failed unregistering procedure with registration id {RegistrationId}. Unregistration request id: {RequestId} ", registrationId, requestId); @@ -127,7 +127,7 @@ private void ValidateCallUri(string procedure) { if (!mUriValidator.IsValid(procedure)) { - mLogger.ErrorFormat("call with invalid procedure URI '{0}'", procedure); + mLogger.ErrorFormat("call with invalid procedure URI '{ProcedureUri}'", procedure); throw new WampException(WampErrors.InvalidUri, string.Format("call with invalid procedure URI '{0}'", procedure)); diff --git a/src/net45/WampSharp/WAMP2/V2/Transports/TextBinaryTransport.cs b/src/net45/WampSharp/WAMP2/V2/Transports/TextBinaryTransport.cs index 5ce365db7..2ea520f71 100644 --- a/src/net45/WampSharp/WAMP2/V2/Transports/TextBinaryTransport.cs +++ b/src/net45/WampSharp/WAMP2/V2/Transports/TextBinaryTransport.cs @@ -49,7 +49,7 @@ protected void OnNewConnection(TConnection connection) } else { - mLogger.ErrorFormat("No handler registered for protocol '{0}'", + mLogger.ErrorFormat("No handler registered for protocol '{Protocol}'", protocol); } } diff --git a/src/net45/WampSharp/WampSharp.csproj b/src/net45/WampSharp/WampSharp.csproj index c12c5b418..ee7998980 100644 --- a/src/net45/WampSharp/WampSharp.csproj +++ b/src/net45/WampSharp/WampSharp.csproj @@ -66,6 +66,10 @@ ..\packages\System.Threading.Tasks.Dataflow.4.6.0\lib\netstandard1.1\System.Threading.Tasks.Dataflow.dll True + + ..\packages\System.ValueTuple.4.0.0-rc3-24212-01\lib\netstandard1.1\System.ValueTuple.dll + True + @@ -142,10 +146,17 @@ + + + + + + + @@ -159,7 +170,9 @@ + + @@ -167,7 +180,11 @@ + + + + @@ -225,6 +242,7 @@ + @@ -314,10 +332,16 @@ - + + + + + + + diff --git a/src/net45/WampSharp/WampSharp.csproj.DotSettings b/src/net45/WampSharp/WampSharp.csproj.DotSettings index f3011ce0d..83c68c843 100644 --- a/src/net45/WampSharp/WampSharp.csproj.DotSettings +++ b/src/net45/WampSharp/WampSharp.csproj.DotSettings @@ -91,6 +91,7 @@ True True True + True True True True diff --git a/src/net45/WampSharp/packages.config b/src/net45/WampSharp/packages.config index 23d7425db..dac833a01 100644 --- a/src/net45/WampSharp/packages.config +++ b/src/net45/WampSharp/packages.config @@ -7,4 +7,5 @@ - \ No newline at end of file + + diff --git a/src/net45/WampSharp/project.json b/src/net45/WampSharp/project.json index b549410bb..dab5a9697 100644 --- a/src/net45/WampSharp/project.json +++ b/src/net45/WampSharp/project.json @@ -28,7 +28,8 @@ "System.Runtime": "4.1.0", "System.Runtime.Serialization.Primitives": "4.1.1", "System.Security.Cryptography.Algorithms": "4.2.0", - "System.Text.RegularExpressions": "4.1.0" + "System.Text.RegularExpressions": "4.1.0", + "System.ValueTuple": "4.0.0-rc3-24212-01" } }, "uap10.0": { @@ -51,6 +52,7 @@ "System.Runtime.Serialization.Primitives": "4.1.1", "System.Security.Cryptography.Algorithms": "4.2.0", "System.Text.RegularExpressions": "4.1.0", + "System.ValueTuple": "4.0.0-rc3-24212-01", "Microsoft.TargetingPack.Private.WinRT": { "version": "1.0.1", "type": "build" diff --git a/src/pcl/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj b/src/pcl/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj index b74640db2..20e3285ac 100644 --- a/src/pcl/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj +++ b/src/pcl/Tests/WampSharp.Tests.Wampv2/WampSharp.Tests.Wampv2.csproj @@ -19,15 +19,16 @@ full false bin\Debug\ - TRACE;DEBUG;NET45;PCL + TRACE;DEBUG;NET45;PCL MANUAL_PROXY prompt 4 + false pdbonly true bin\Release\ - TRACE;NET45;PCL + TRACE;NET45;PCL MANUAL_PROXY prompt 4 @@ -63,6 +64,10 @@ True + + ..\..\packages\System.ValueTuple.4.0.0-rc3-24212-01\lib\netstandard1.1\System.ValueTuple.dll + True + @@ -139,6 +144,12 @@ Integration\RpcProxies\IErrorsService.cs + + Integration\RpcProxies\ILongValueTuplesServiceProxy.cs + + + Integration\RpcProxies\INamedTupleComplexResultService.cs + Integration\RpcProxies\ISlowSquareService.cs @@ -154,12 +165,27 @@ Integration\RpcServices\ErrorsService.cs + + Integration\RpcServices\LongValueTuplesCalleeService.cs + + + Integration\RpcServices\LongValueTuplesService.cs + + + Integration\RpcServices\NamedTupleComplexResultService.cs + + + Integration\RpcServices\PositionalTupleComplexResultService.cs + Integration\RpcServices\SlowSquareService.cs Integration\RpcServices\TimeService.cs + + Integration\PubSubSubjectTupleTests.cs + Integration\SerializedValue.cs diff --git a/src/pcl/Tests/WampSharp.Tests.Wampv2/packages.config b/src/pcl/Tests/WampSharp.Tests.Wampv2/packages.config index 7a112a29c..25054a213 100644 --- a/src/pcl/Tests/WampSharp.Tests.Wampv2/packages.config +++ b/src/pcl/Tests/WampSharp.Tests.Wampv2/packages.config @@ -7,4 +7,5 @@ + diff --git a/src/pcl/WampSharp/WampSharp.csproj b/src/pcl/WampSharp/WampSharp.csproj index c4a056ff7..d7b73f16d 100644 --- a/src/pcl/WampSharp/WampSharp.csproj +++ b/src/pcl/WampSharp/WampSharp.csproj @@ -65,6 +65,10 @@ ..\packages\System.Threading.Tasks.Dataflow.4.6.0\lib\netstandard1.1\System.Threading.Tasks.Dataflow.dll True + + ..\packages\System.ValueTuple.4.0.0-rc3-24212-01\lib\netstandard1.1\System.ValueTuple.dll + True + @@ -285,6 +289,24 @@ Core\Utilities\ThreadSafeRandom.cs + + Core\Utilities\ValueTuple\ValueTuple.cs + + + Core\Utilities\ValueTuple\ValueTupleArrayConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleDictionaryConverter.cs + + + Core\Utilities\ValueTuple\ValueTupleDictionaryConverterBuilder.cs + + + Core\Utilities\ValueTuple\ValueTupleTypeExtensions.cs + Properties\AssemblyInfo.cs @@ -297,6 +319,9 @@ WAMP2\V2\Api\CalleeProxy\CachedCalleeProxyInterceptor.cs + + WAMP2\V2\Api\CalleeProxy\Callbacks\Async\OperationResultExtractor.cs + WAMP2\V2\Api\CalleeProxy\CalleeProxyBase.cs @@ -336,9 +361,15 @@ WAMP2\V2\Api\CalleeProxy\ClientInvocationHandler.cs + + WAMP2\V2\Api\CalleeProxy\Callbacks\Async\ValueTupleValueExtractor.cs + WAMP2\V2\Api\CalleeProxy\WampIncompatibleCalleeProxyMethodException.cs + + WAMP2\V2\Api\Rx\WampTupleTopicSubject.cs + WAMP2\V2\Api\DelegatePubSub\EventHandlerGenerator.cs @@ -360,9 +391,21 @@ WAMP2\V2\Api\DelegatePubSub\WampSubscriberRegistrar.cs + + WAMP2\V2\Api\Rx\IWampEventValueTupleConverter.cs + + + WAMP2\V2\Api\Rx\SerializedValueFormatter.cs + + + WAMP2\V2\Api\Rx\WampEventValueTupleConverter.cs + WAMP2\V2\Authentication\Restriction\WampRestrictedUris.cs + + WAMP2\V2\Core\ArgumentUnpackerHelper.cs + WAMP2\V2\Core\Contracts\WampAuthenticationMethods.cs @@ -534,6 +577,9 @@ WAMP2\V2\Client\Session\WampAuthenticationNotImplementedException.cs + + WAMP2\V2\Core\Contracts\WampInvalidArgumentException.cs + WAMP2\V2\Core\Contracts\WampInvokePolicy.cs @@ -801,9 +847,6 @@ WAMP2\V2\Rpc\Callee\Reflection\ICalleeRegistrationInterceptor.cs - - WAMP2\V2\Rpc\Callee\Reflection\CallerProgress.cs - WAMP2\V2\Rpc\Callee\Reflection\MethodInfoValidation.cs @@ -813,6 +856,27 @@ WAMP2\V2\Rpc\Callee\Reflection\ProgressiveAsyncMethodInfoRpcOperation.cs + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\EmptyResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\IWampResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\MultiResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\NamedTupleExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\PositionalTupleExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\SingleResultExtractor.cs + + + WAMP2\V2\Rpc\Callee\Reflection\ResultExtractor\WampResultExtractor.cs + WAMP2\V2\Rpc\Dealer\ExactRpcOperationCatalog.cs diff --git a/src/pcl/WampSharp/packages.config b/src/pcl/WampSharp/packages.config index 3649eed01..4bca33da4 100644 --- a/src/pcl/WampSharp/packages.config +++ b/src/pcl/WampSharp/packages.config @@ -17,4 +17,5 @@ + \ No newline at end of file