diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 000000000..1674327de
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,7 @@
+
+
+ true
+ 7.3
+ $(NoWarn);CS1591
+
+
diff --git a/MagicOnion.sln b/MagicOnion.sln
index 4826460c1..3cc281676 100644
--- a/MagicOnion.sln
+++ b/MagicOnion.sln
@@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{7ACC27E8
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandbox", "sandbox", "{7682EFFC-681C-4DCC-B5E7-D8449E42DAC9}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicOnion.Tests", "tests\MagicOnion.Tests\MagicOnion.Tests.csproj", "{879C8453-8995-4D9A-964F-2FEA2B84FF1A}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MagicOnion", "src\MagicOnion\MagicOnion.csproj", "{C79CE0BF-ED4C-47BE-822E-E82CF83FC68A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{7F61607D-5772-4E41-9D37-04E6AE7E47BA}"
@@ -25,8 +23,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{7F61607D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MagicOnion.HttpGateway", "src\MagicOnion.HttpGateway\MagicOnion.HttpGateway.csproj", "{FCE03661-803E-4629-944F-45DB6B444320}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MagicOnion.Tests.NetCore", "tests\MagicOnion.Tests.NetCore\MagicOnion.Tests.NetCore.csproj", "{A0E9C1EA-6E7F-4CF1-81D2-21EAC6ACAE67}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandbox.NetCoreServer", "sandbox\Sandbox.NetCoreServer\Sandbox.NetCoreServer.csproj", "{8174DFB5-0C46-440C-A225-C3A9851C2700}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicCodeDumper", "sandbox\DynamicCodeDumper\DynamicCodeDumper.csproj", "{A2156D81-1A67-4EAC-8A74-3E459385E4A0}"
@@ -43,16 +39,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MagicOnion.Hosting", "src\M
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MagicOnion.Hosting.Tests", "tests\MagicOnion.Hosting.Tests\MagicOnion.Hosting.Tests.csproj", "{5A381446-409B-4532-8B1A-877D996F7575}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicOnion.NetCoreTests", "tests\MagicOnion.NetCoreTests\MagicOnion.NetCoreTests.csproj", "{9130778E-4B00-436C-BD1F-1DFDF95AD2CC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {879C8453-8995-4D9A-964F-2FEA2B84FF1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {879C8453-8995-4D9A-964F-2FEA2B84FF1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {879C8453-8995-4D9A-964F-2FEA2B84FF1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {879C8453-8995-4D9A-964F-2FEA2B84FF1A}.Release|Any CPU.Build.0 = Release|Any CPU
{C79CE0BF-ED4C-47BE-822E-E82CF83FC68A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C79CE0BF-ED4C-47BE-822E-E82CF83FC68A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C79CE0BF-ED4C-47BE-822E-E82CF83FC68A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -61,10 +55,6 @@ Global
{FCE03661-803E-4629-944F-45DB6B444320}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FCE03661-803E-4629-944F-45DB6B444320}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FCE03661-803E-4629-944F-45DB6B444320}.Release|Any CPU.Build.0 = Release|Any CPU
- {A0E9C1EA-6E7F-4CF1-81D2-21EAC6ACAE67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A0E9C1EA-6E7F-4CF1-81D2-21EAC6ACAE67}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A0E9C1EA-6E7F-4CF1-81D2-21EAC6ACAE67}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A0E9C1EA-6E7F-4CF1-81D2-21EAC6ACAE67}.Release|Any CPU.Build.0 = Release|Any CPU
{8174DFB5-0C46-440C-A225-C3A9851C2700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8174DFB5-0C46-440C-A225-C3A9851C2700}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8174DFB5-0C46-440C-A225-C3A9851C2700}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -93,15 +83,17 @@ Global
{5A381446-409B-4532-8B1A-877D996F7575}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A381446-409B-4532-8B1A-877D996F7575}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A381446-409B-4532-8B1A-877D996F7575}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9130778E-4B00-436C-BD1F-1DFDF95AD2CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9130778E-4B00-436C-BD1F-1DFDF95AD2CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9130778E-4B00-436C-BD1F-1DFDF95AD2CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9130778E-4B00-436C-BD1F-1DFDF95AD2CC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {879C8453-8995-4D9A-964F-2FEA2B84FF1A} = {7ACC27E8-8FBE-4807-B91F-B89AF3CFF7E0}
{C79CE0BF-ED4C-47BE-822E-E82CF83FC68A} = {1987061F-8970-4018-8D58-6932961C9EB4}
{FCE03661-803E-4629-944F-45DB6B444320} = {1987061F-8970-4018-8D58-6932961C9EB4}
- {A0E9C1EA-6E7F-4CF1-81D2-21EAC6ACAE67} = {7ACC27E8-8FBE-4807-B91F-B89AF3CFF7E0}
{8174DFB5-0C46-440C-A225-C3A9851C2700} = {7682EFFC-681C-4DCC-B5E7-D8449E42DAC9}
{A2156D81-1A67-4EAC-8A74-3E459385E4A0} = {7682EFFC-681C-4DCC-B5E7-D8449E42DAC9}
{5637ED33-7EB8-4C30-94EE-947C58FDE363} = {1987061F-8970-4018-8D58-6932961C9EB4}
@@ -109,6 +101,7 @@ Global
{A1DB4A40-10FE-61E7-9ADF-1D16330A9BF3} = {5C86A5C9-ECE1-4FB9-B48C-A9DCF9C3FECC}
{72B2FD95-57B6-400B-95D0-96E19EBCF44B} = {1987061F-8970-4018-8D58-6932961C9EB4}
{5A381446-409B-4532-8B1A-877D996F7575} = {7ACC27E8-8FBE-4807-B91F-B89AF3CFF7E0}
+ {9130778E-4B00-436C-BD1F-1DFDF95AD2CC} = {7ACC27E8-8FBE-4807-B91F-B89AF3CFF7E0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D5B2E7E3-B727-40A1-BE68-7BAC9B9DE2FE}
diff --git a/nuget/MagicOnion.Hosting.nuspec b/nuget/MagicOnion.Hosting.nuspec
index a908c5ddd..782f95c92 100644
--- a/nuget/MagicOnion.Hosting.nuspec
+++ b/nuget/MagicOnion.Hosting.nuspec
@@ -2,7 +2,7 @@
MagicOnion.Hosting
- 2.0.4
+ 2.0.5
MagicOnion.Hosting
neuecc
neuecc
@@ -13,7 +13,7 @@
gRPC, HTTP2
-
+
diff --git a/nuget/MagicOnion.HttpGateway.nuspec b/nuget/MagicOnion.HttpGateway.nuspec
index 555bba51f..fdf862767 100644
--- a/nuget/MagicOnion.HttpGateway.nuspec
+++ b/nuget/MagicOnion.HttpGateway.nuspec
@@ -2,7 +2,7 @@
MagicOnion.HttpGateway
- 2.0.4
+ 2.0.5
MagicOnion.HttpGateway
neuecc
neuecc
@@ -13,7 +13,7 @@
gRPC, HTTP2
-
+
diff --git a/nuget/MagicOnion.Redis.nuspec b/nuget/MagicOnion.Redis.nuspec
index 2845622a0..7f72d9c0e 100644
--- a/nuget/MagicOnion.Redis.nuspec
+++ b/nuget/MagicOnion.Redis.nuspec
@@ -2,7 +2,7 @@
MagicOnion.Redis
- 2.0.4
+ 2.0.5
MagicOnion
neuecc
neuecc
@@ -13,7 +13,7 @@
gRPC, HTTP2
-
+
diff --git a/nuget/MagicOnion.nuspec b/nuget/MagicOnion.nuspec
index 7199128b7..272a77867 100644
--- a/nuget/MagicOnion.nuspec
+++ b/nuget/MagicOnion.nuspec
@@ -2,7 +2,7 @@
MagicOnion
- 2.0.4
+ 2.0.5
MagicOnion
neuecc
neuecc
@@ -13,7 +13,7 @@
gRPC, HTTP2
-
+
@@ -21,7 +21,7 @@
-
+
@@ -29,7 +29,7 @@
-
+
@@ -39,7 +39,7 @@
-
+
diff --git a/nuget/push.bat b/nuget/push.bat
index 5c3632412..8e9a2b50e 100644
--- a/nuget/push.bat
+++ b/nuget/push.bat
@@ -1,4 +1,4 @@
-nuget push MagicOnion.2.0.4.nupkg -Source https://www.nuget.org/api/v2/package
-nuget push MagicOnion.HttpGateway.2.0.4.nupkg -Source https://www.nuget.org/api/v2/package
-nuget push MagicOnion.Redis.2.0.4.nupkg -Source https://www.nuget.org/api/v2/package
-nuget push MagicOnion.Hosting.2.0.4.nupkg -Source https://www.nuget.org/api/v2/package
\ No newline at end of file
+nuget push MagicOnion.2.0.5.nupkg -Source https://www.nuget.org/api/v2/package
+nuget push MagicOnion.HttpGateway.2.0.5.nupkg -Source https://www.nuget.org/api/v2/package
+nuget push MagicOnion.Redis.2.0.5.nupkg -Source https://www.nuget.org/api/v2/package
+nuget push MagicOnion.Hosting.2.0.5.nupkg -Source https://www.nuget.org/api/v2/package
\ No newline at end of file
diff --git a/sandbox/Sandbox.NetCoreServer/Sandbox.NetCoreServer.csproj b/sandbox/Sandbox.NetCoreServer/Sandbox.NetCoreServer.csproj
index 31a66e2c6..5a603b18d 100644
--- a/sandbox/Sandbox.NetCoreServer/Sandbox.NetCoreServer.csproj
+++ b/sandbox/Sandbox.NetCoreServer/Sandbox.NetCoreServer.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/ChatShare.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/ChatShare.cs
index 0929bfce6..7765a0685 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/ChatShare.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/ChatShare.cs
@@ -94,7 +94,7 @@ public class GamingHubClient : IGamingHubReceiver
public async Task ConnectAsync(Channel grpcChannel, string roomName, string playerName)
{
- var client = StreamingHubClient.Connect(grpcChannel, this);
+ client = StreamingHubClient.Connect(grpcChannel, this);
var roomPlayers = await client.JoinAsync(roomName, playerName, Vector3.zero, Quaternion.identity);
foreach (var player in roomPlayers)
diff --git a/src/MagicOnion.Hosting/MagicOnion.Hosting.csproj b/src/MagicOnion.Hosting/MagicOnion.Hosting.csproj
index eb647808f..6337a0ae4 100644
--- a/src/MagicOnion.Hosting/MagicOnion.Hosting.csproj
+++ b/src/MagicOnion.Hosting/MagicOnion.Hosting.csproj
@@ -1,4 +1,4 @@
-
+
Library
@@ -7,8 +7,11 @@
-
+
+
+
+
diff --git a/src/MagicOnion.HttpGateway/MagicOnion.HttpGateway.csproj b/src/MagicOnion.HttpGateway/MagicOnion.HttpGateway.csproj
index ff13690f0..2ef666c83 100644
--- a/src/MagicOnion.HttpGateway/MagicOnion.HttpGateway.csproj
+++ b/src/MagicOnion.HttpGateway/MagicOnion.HttpGateway.csproj
@@ -33,7 +33,7 @@
-
+
diff --git a/src/MagicOnion/MagicOnion.csproj b/src/MagicOnion/MagicOnion.csproj
index 4b46774d5..3200dc19b 100644
--- a/src/MagicOnion/MagicOnion.csproj
+++ b/src/MagicOnion/MagicOnion.csproj
@@ -67,7 +67,7 @@
-
+
diff --git a/src/MagicOnion/_AssemblyInfo.cs b/src/MagicOnion/_AssemblyInfo.cs
index 74a22b6d0..ccd74d7a4 100644
--- a/src/MagicOnion/_AssemblyInfo.cs
+++ b/src/MagicOnion/_AssemblyInfo.cs
@@ -14,5 +14,5 @@
[assembly: Guid("cbfa1f05-746b-47e1-8432-d709f88ce24e")]
-[assembly: AssemblyVersion("2.0.4")]
-[assembly: AssemblyFileVersion("2.0.4")]
+[assembly: AssemblyVersion("2.0.5")]
+[assembly: AssemblyFileVersion("2.0.5")]
diff --git a/tests/MagicOnion.Hosting.Tests/TestService.cs b/tests/MagicOnion.Hosting.Tests/TestService.cs
index 7e2484d65..4b739d910 100644
--- a/tests/MagicOnion.Hosting.Tests/TestService.cs
+++ b/tests/MagicOnion.Hosting.Tests/TestService.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CS1998
+
using System;
using MagicOnion;
using MagicOnion.Server;
@@ -15,4 +17,5 @@ public async UnaryResult Sum(int x, int y)
return x + y;
}
}
-}
\ No newline at end of file
+}
+#pragma warning restore CS1998
diff --git a/tests/MagicOnion.NetCoreTests/MagicOnion.NetCoreTests.csproj b/tests/MagicOnion.NetCoreTests/MagicOnion.NetCoreTests.csproj
new file mode 100644
index 000000000..1cdabe736
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/MagicOnion.NetCoreTests.csproj
@@ -0,0 +1,22 @@
+
+
+
+ netcoreapp2.1
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/MagicOnion.NetCoreTests/Tests/ArgumentPatternTest.cs b/tests/MagicOnion.NetCoreTests/Tests/ArgumentPatternTest.cs
new file mode 100644
index 000000000..f1fd6d048
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/Tests/ArgumentPatternTest.cs
@@ -0,0 +1,369 @@
+using Grpc.Core;
+using FluentAssertions;
+using MagicOnion.Client;
+using MagicOnion.Server;
+using MessagePack;
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace MagicOnion.Tests
+{
+ [MessagePackObject]
+ public class MyRequest
+ {
+ [Key(0)]
+ public virtual int Id { get; set; }
+ [Key(1)]
+ public virtual string Data { get; set; }
+ }
+
+ [MessagePackObject]
+ public struct MyStructRequest
+ {
+ [Key(0)]
+ public int X;
+ [Key(1)]
+ public int Y;
+
+ public MyStructRequest(int x, int y)
+ {
+ this.X = x;
+ this.Y = y;
+ }
+ }
+
+ [MessagePackObject]
+ public struct MyStructResponse
+ {
+ [Key(0)]
+ public int X;
+ [Key(1)]
+ public int Y;
+
+ public MyStructResponse(int x, int y)
+ {
+ this.X = x;
+ this.Y = y;
+ }
+ }
+
+
+ [MessagePackObject]
+ public class MyResponse
+ {
+ [Key(0)]
+ public virtual int Id { get; set; }
+ [Key(1)]
+ public virtual string Data { get; set; }
+ }
+
+
+ public interface IArgumentPattern : IService
+ {
+ UnaryResult Unary1(int x, int y, string z = "unknown");
+ UnaryResult Unary2(MyRequest req);
+ UnaryResult Unary3();
+ UnaryResult Unary4();
+ UnaryResult Unary5(MyStructRequest req);
+
+
+ Task> ServerStreamingResult1(int x, int y, string z = "unknown");
+ Task> ServerStreamingResult2(MyRequest req);
+ Task> ServerStreamingResult3();
+ Task> ServerStreamingResult4();
+ Task> ServerStreamingResult5(MyStructRequest req);
+ }
+
+ public class ArgumentPattern : ServiceBase, IArgumentPattern
+ {
+
+ public UnaryResult Unary1(int x, int y, string z = "unknown")
+ {
+ return UnaryResult(new MyResponse
+ {
+ Id = x + y,
+ Data = z
+ });
+ }
+
+ public UnaryResult Unary2(MyRequest req)
+ {
+ return UnaryResult(new MyResponse
+ {
+ Id = req.Id,
+ Data = req.Data
+ });
+ }
+
+ public UnaryResult Unary3()
+ {
+ return UnaryResult(new MyResponse
+ {
+ Id = -1,
+ Data = "NoArg"
+ });
+ }
+
+ public UnaryResult Unary4()
+ {
+ return UnaryResult(Nil.Default);
+ }
+
+ public UnaryResult Unary5(MyStructRequest req)
+ {
+ return UnaryResult(new MyStructResponse
+ {
+ X = req.X,
+ Y = req.Y
+ });
+ }
+
+
+ public async Task> ServerStreamingResult1(int x, int y, string z = "unknown")
+ {
+ var stream = GetServerStreamingContext();
+ await stream.WriteAsync(new MyResponse { Id = x + y, Data = z });
+ return stream.Result();
+ }
+
+ public async Task> ServerStreamingResult2(MyRequest req)
+ {
+ var stream = GetServerStreamingContext();
+ await stream.WriteAsync(new MyResponse { Id = req.Id, Data = req.Data });
+ return stream.Result();
+ }
+
+ public async Task> ServerStreamingResult3()
+ {
+ var stream = GetServerStreamingContext();
+ await stream.WriteAsync(new MyResponse { Id = -1, Data = "empty" });
+ return stream.Result();
+ }
+
+ public async Task> ServerStreamingResult4()
+ {
+ var stream = GetServerStreamingContext();
+ await stream.WriteAsync(Nil.Default);
+ return stream.Result();
+ }
+
+ public async Task> ServerStreamingResult5(MyStructRequest req)
+ {
+ var stream = GetServerStreamingContext();
+ await stream.WriteAsync(new MyStructResponse { X = req.X, Y = req.Y });
+ return stream.Result();
+ }
+ }
+
+ [Collection(nameof(AllAssemblyGrpcServerFixture))]
+ public class ArgumentPatternTest
+ {
+ ITestOutputHelper logger;
+ Channel channel;
+
+ public ArgumentPatternTest(ITestOutputHelper logger, ServerFixture server)
+ {
+ this.logger = logger;
+ this.channel = server.DefaultChannel;
+ }
+
+ [Fact]
+ public async Task Unary1()
+ {
+ {
+ var client = MagicOnionClient.Create(channel);
+
+ var result = await client.Unary1(10, 20, "hogehoge");
+
+ result.Id.Should().Be(30);
+ result.Data.Should().Be("hogehoge");
+ }
+ {
+ var client = new ArgumentPatternManualClient(channel);
+
+ var result = await client.Unary1(10, 20, "__omit_last_argument__");
+
+ result.Id.Should().Be(30);
+ result.Data.Should().Be("unknown");
+ }
+ }
+
+ [Fact]
+ public async Task Unary2()
+ {
+ var client = MagicOnionClient.Create(channel);
+
+ var result = await client.Unary2(new MyRequest { Id = 30, Data = "huga" });
+
+ result.Id.Should().Be(30);
+ result.Data.Should().Be("huga");
+ }
+
+ [Fact]
+ public async Task Unary3()
+ {
+ var client = MagicOnionClient.Create(channel);
+
+ var result = await client.Unary3();
+
+ result.Id.Should().Be(-1);
+ result.Data.Should().Be("NoArg");
+ }
+
+ [Fact]
+ public async Task Unary4()
+ {
+ var client = MagicOnionClient.Create(channel);
+
+ var result = await client.Unary4();
+ result.Should().Be(Nil.Default);
+ }
+
+ [Fact]
+ public async Task Unary5()
+ {
+ var client = MagicOnionClient.Create(channel);
+
+ var result = await client.Unary5(new MyStructRequest(999, 9999));
+ result.X.Should().Be(999);
+ result.Y.Should().Be(9999);
+ }
+
+ [Fact]
+ public async Task ServerStreaming()
+ {
+ var client = MagicOnionClient.Create(channel);
+
+ {
+ var callResult = await client.ServerStreamingResult1(10, 100, "aaa");
+ var result = await callResult.ResponseStream.AsAsyncEnumerable().First();
+ result.Id.Should().Be(110);
+ result.Data.Should().Be("aaa");
+ }
+
+ {
+ var callResult = await client.ServerStreamingResult2(new MyRequest { Id = 999, Data = "zzz" });
+ var result = await callResult.ResponseStream.AsAsyncEnumerable().First();
+ result.Id.Should().Be(999);
+ result.Data.Should().Be("zzz");
+ }
+
+ {
+ var callResult = await client.ServerStreamingResult3();
+ var result = await callResult.ResponseStream.AsAsyncEnumerable().First();
+ result.Id.Should().Be(-1);
+ result.Data.Should().Be("empty");
+ }
+
+ {
+ var callResult = await client.ServerStreamingResult4();
+ var result = await callResult.ResponseStream.AsAsyncEnumerable().First();
+ result.Should().Be(Nil.Default);
+ }
+
+ {
+ var callResult = await client.ServerStreamingResult5(new MyStructRequest { X = 9, Y = 100 });
+ var result = await callResult.ResponseStream.AsAsyncEnumerable().First();
+ result.X.Should().Be(9);
+ result.Y.Should().Be(100);
+ }
+ }
+
+ [Ignore] // client is not service.
+ class ArgumentPatternManualClient : IArgumentPattern
+ {
+ readonly CallInvoker invoker;
+
+ public ArgumentPatternManualClient(Channel channel)
+ {
+ this.invoker = new DefaultCallInvoker(channel);
+ }
+
+ public Task> ServerStreamingResult1(int x, int y, string z = "unknown")
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task> ServerStreamingResult2(MyRequest req)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task> ServerStreamingResult3()
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task> ServerStreamingResult4()
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task> ServerStreamingResult5(MyStructRequest req)
+ {
+ throw new NotImplementedException();
+ }
+
+ public UnaryResult Unary1(int x, int y, string z = "unknown")
+ {
+ var tuple = new DynamicArgumentTuple(x, y);
+
+ var method = new Method(MethodType.Unary, "IArgumentPattern", "Unary1", MagicOnionMarshallers.ThroughMarshaller, MagicOnionMarshallers.ThroughMarshaller);
+ var request = LZ4MessagePackSerializer.Serialize(tuple);
+
+ var callResult = invoker.AsyncUnaryCall(method, null, default(CallOptions), request);
+
+ return new UnaryResult(callResult, MessagePackSerializer.DefaultResolver);
+ }
+
+ public UnaryResult Unary2(MyRequest req)
+ {
+ throw new NotImplementedException();
+ }
+
+ public UnaryResult Unary3()
+ {
+ throw new NotImplementedException();
+ }
+
+ public UnaryResult Unary4()
+ {
+ throw new NotImplementedException();
+ }
+
+ public UnaryResult Unary5(MyStructRequest req)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IArgumentPattern WithCancellationToken(CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IArgumentPattern WithDeadline(DateTime deadline)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IArgumentPattern WithHeaders(Metadata headers)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IArgumentPattern WithHost(string host)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IArgumentPattern WithOptions(CallOptions option)
+ {
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
diff --git a/tests/MagicOnion.NetCoreTests/Tests/ClientConfigTest.cs b/tests/MagicOnion.NetCoreTests/Tests/ClientConfigTest.cs
new file mode 100644
index 000000000..6e30efae7
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/Tests/ClientConfigTest.cs
@@ -0,0 +1,148 @@
+using Grpc.Core;
+using FluentAssertions;
+using MagicOnion.Client;
+using MagicOnion.Server;
+using MessagePack;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace MagicOnion.Tests
+{
+ [MessagePackObject]
+ public class SerializableCallContext
+ {
+ [Key(0)]
+ public virtual DateTime Deadline { get; set; }
+ [Key(1)]
+ public virtual string Host { get; set; }
+ [Key(2)]
+ public virtual string Method { get; set; }
+ [Key(3)]
+ public virtual string Peer { get; set; }
+ [Key(4)]
+ public virtual Dictionary RequestHeaders { get; set; }
+ [Key(5)]
+ public virtual Dictionary ResponseTrailers { get; set; }
+ }
+
+ public interface IConfigurationChange : IService
+ {
+ UnaryResult ReturnContext();
+ }
+
+ public class ConfigurationChange : ServiceBase, IConfigurationChange
+ {
+ public UnaryResult ReturnContext()
+ {
+ var context = this.Context.CallContext;
+ var result = new SerializableCallContext
+ {
+ Deadline = context.Deadline,
+ Host = context.Host,
+ Method = context.Method,
+ Peer = context.Peer,
+ RequestHeaders = context.RequestHeaders.ToDictionary(x => x.Key, x => x.Value),
+ ResponseTrailers = context.ResponseTrailers.ToDictionary(x => x.Key, x => x.Value),
+ };
+
+ return UnaryResult(result);
+ }
+ }
+
+ [Collection(nameof(AllAssemblyGrpcServerFixture))]
+ public class ClientConfigTest
+ {
+ ITestOutputHelper logger;
+ IConfigurationChange client;
+
+ public ClientConfigTest(ITestOutputHelper logger, ServerFixture server)
+ {
+ this.logger = logger;
+ this.client = server.CreateClient();
+ }
+
+ /*
+ protected string host;
+ protected CallOptions option;
+ protected CallInvoker callInvoker;
+ */
+
+ //[Fact]
+ //public async Task WithHost()
+ //{
+ // (client.Should().Be( .AsDynamic().host as string).IsNull();
+
+ // var hostChange = client.WithHost("newhost");
+ // (hostChange.AsDynamic().host as string).Should().Be("newhost");
+
+ // var serverContext = await hostChange.ReturnContext();
+ // serverContext.Host.Should().Be("newhost");
+ //}
+
+ //[Fact]
+ //public void WithCancellation()
+ //{
+ // var cts = new CancellationTokenSource();
+ // var tk = cts.Token;
+ // var opt = (CallOptions)client.AsDynamic().option;
+ // opt.CancellationToken.IsNot(tk);
+
+ // var change = client.WithCancellationToken(tk);
+ // opt = (CallOptions)change.AsDynamic().option;
+
+ // opt.CancellationToken.Should().Be(tk);
+ //}
+
+ //[Fact]
+ //public async Task WithDeadline()
+ //{
+ // var now = DateTime.UtcNow.AddMinutes(10);
+ // var opt = (CallOptions)client.AsDynamic().option;
+ // opt.Deadline.IsNull();
+
+ // var change = client.WithDeadline(now);
+ // opt = (CallOptions)change.AsDynamic().option;
+ // opt.Deadline.Should().Be(now);
+
+ // var context = await change.ReturnContext();
+ // context.Deadline.ToString().Should().Be(now.ToString()); // almost same:)
+ //}
+
+ //[Fact]
+ //public async Task WithHeaders()
+ //{
+ // var meta = new Metadata();
+ // meta.Add("test", "aaaaa");
+
+ // var opt = (CallOptions)client.AsDynamic().option;
+ // opt.Headers.IsNull();
+
+ // var change = client.WithHeaders(meta);
+ // opt = (CallOptions)change.AsDynamic().option;
+ // opt.Headers[0].Key.Should().Be("test");
+ // opt.Headers[0].Value.Should().Be("aaaaa");
+
+ // var context = await change.ReturnContext();
+ // context.RequestHeaders["test"].Should().Be("aaaaa");
+ //}
+
+
+ //[Fact]
+ //public void WithOption()
+ //{
+ // var opt = (CallOptions)client.AsDynamic().option;
+ // opt.WriteOptions.IsNull();
+
+ // var change = client.WithOptions(new CallOptions(writeOptions: new WriteOptions(WriteFlags.BufferHint)));
+ // opt = (CallOptions)change.AsDynamic().option;
+ // opt.WriteOptions.Flags.Should().Be(WriteFlags.BufferHint);
+ //}
+
+ }
+}
diff --git a/tests/MagicOnion.NetCoreTests/Tests/FilterTest.cs b/tests/MagicOnion.NetCoreTests/Tests/FilterTest.cs
new file mode 100644
index 000000000..db347dedc
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/Tests/FilterTest.cs
@@ -0,0 +1,214 @@
+using System;
+using FluentAssertions;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MagicOnion.Server;
+using Xunit;
+using Grpc.Core;
+using MagicOnion.Client;
+using Xunit.Abstractions;
+
+namespace MagicOnion.Tests
+{
+ [Flags]
+ public enum FilterCalledStatus
+ {
+ Begin = 1,
+ Catch = 2,
+ Finally = 4
+ }
+
+ public class SimpleFilter1 : MagicOnionFilterAttribute
+ {
+ public SimpleFilter1() : this(null)
+ {
+
+ }
+
+ public SimpleFilter1(Func next) : base(next)
+ {
+ }
+
+ public async override ValueTask Invoke(ServiceContext context)
+ {
+ try
+ {
+ (context.Items["list"] as List).Add(nameof(SimpleFilter1));
+ context.Items[nameof(SimpleFilter1)] = FilterCalledStatus.Begin;
+ await Next(context);
+ }
+ catch
+ {
+ context.Items[nameof(SimpleFilter1)] = (FilterCalledStatus)context.Items[nameof(SimpleFilter1)] | FilterCalledStatus.Catch;
+ throw;
+ }
+ finally
+ {
+ context.Items[nameof(SimpleFilter1)] = (FilterCalledStatus)context.Items[nameof(SimpleFilter1)] | FilterCalledStatus.Finally;
+ }
+ }
+ }
+
+ public class MultiFilter2 : MagicOnionFilterAttribute
+ {
+ public int X { get; private set; }
+ public int Y { get; private set; }
+ public int Z { get; set; }
+
+ public MultiFilter2(int x, int y)
+ : base(null)
+ {
+ this.X = x;
+ this.Y = y;
+ }
+
+ public MultiFilter2(Func next) : base(next)
+ {
+ }
+
+ public override async ValueTask Invoke(ServiceContext context)
+ {
+ try
+ {
+ (context.Items["list"] as List).Add(nameof(MultiFilter2));
+ context.Items[nameof(MultiFilter2)] = FilterCalledStatus.Begin;
+ context.Items[nameof(MultiFilter2) + "xyz"] = Tuple.Create(X, Y, Z);
+ await Next(context);
+ }
+ catch
+ {
+ context.Items[nameof(MultiFilter2)] = (FilterCalledStatus)context.Items[nameof(MultiFilter2)] | FilterCalledStatus.Catch;
+ throw;
+ }
+ finally
+ {
+ context.Items[nameof(MultiFilter2)] = (FilterCalledStatus)context.Items[nameof(MultiFilter2)] | FilterCalledStatus.Finally;
+ }
+ }
+ }
+
+ public class MoreThanFilter3 : MagicOnionFilterAttribute
+ {
+ readonly string msg;
+
+ public MoreThanFilter3(string msg)
+ : base(null)
+ {
+ this.msg = msg;
+ }
+
+ public MoreThanFilter3(Func next) : base(next)
+ {
+ }
+
+ public async override ValueTask Invoke(ServiceContext context)
+ {
+ try
+ {
+ (context.Items["list"] as List).Add(nameof(MoreThanFilter3));
+ context.Items[nameof(MoreThanFilter3)] = FilterCalledStatus.Begin;
+ context.Items[nameof(MoreThanFilter3) + "msg"] = msg;
+ await Next(context);
+ }
+ catch
+ {
+ context.Items[nameof(MoreThanFilter3)] = (FilterCalledStatus)context.Items[nameof(MoreThanFilter3)] | FilterCalledStatus.Catch;
+ throw;
+ }
+ finally
+ {
+ context.Items[nameof(MoreThanFilter3)] = (FilterCalledStatus)context.Items[nameof(MoreThanFilter3)] | FilterCalledStatus.Finally;
+ }
+ }
+ }
+
+ public class DumpFilter : MagicOnionFilterAttribute
+ {
+ public DumpFilter() : base(null)
+ {
+
+ }
+
+ public DumpFilter(Func next) : base(next)
+ {
+ }
+
+ public override async ValueTask Invoke(ServiceContext context)
+ {
+ try
+ {
+ context.Items["list"] = new List();
+ (context.Items["list"] as List).Add(nameof(DumpFilter));
+ await Next(context);
+ }
+ catch
+ {
+ }
+ finally
+ {
+ var calls = string.Join(", ", (context.Items["list"] as List));
+ var dict = string.Join(", ", context.Items.Where(x => x.Key != "list").OrderBy(x => x.Key).Select(x => x.Key + ", " + x.Value.ToString()));
+ SetStatusCode(context, (StatusCode)999, calls + " : " + dict);
+ }
+ }
+ }
+
+ public interface IFilterTester : IService
+ {
+ UnaryResult A();
+ UnaryResult B();
+ UnaryResult C();
+ }
+
+ [DumpFilter(Order = int.MinValue)]
+ [MoreThanFilter3("put-class", Order = 244)]
+ public class FilterTester : ServiceBase, IFilterTester
+ {
+ [SimpleFilter1(Order = 10)]
+ public UnaryResult A()
+ {
+ return UnaryResult(0);
+ }
+
+ [SimpleFilter1(Order = 300)]
+ [MultiFilter2(99, 30, Z = 4595, Order = 200)]
+ public UnaryResult B()
+ {
+ return UnaryResult(999);
+ }
+
+ [SimpleFilter1(Order = int.MinValue)]
+ public UnaryResult C()
+ {
+ throw new Exception("C-Exception");
+ }
+ }
+
+
+ [Collection(nameof(AllAssemblyGrpcServerFixture))]
+ public class FilterTest
+ {
+ IFilterTester client;
+
+ public FilterTest(ITestOutputHelper logger, ServerFixture server)
+ {
+ this.client = server.CreateClient();
+ }
+
+
+ [Fact]
+ public void Filter()
+ {
+ Assert.Throws(() => client.A().GetAwaiter().GetResult()).Status.Detail
+ .Should().Be("DumpFilter, SimpleFilter1, MoreThanFilter3 : MoreThanFilter3, Begin, Finally, MoreThanFilter3msg, put-class, SimpleFilter1, Begin, Finally");
+
+ Assert.Throws(() => client.B().GetAwaiter().GetResult()).Status.Detail
+ .Should().Be("DumpFilter, MultiFilter2, MoreThanFilter3, SimpleFilter1 : MoreThanFilter3, Begin, Finally, MoreThanFilter3msg, put-class, MultiFilter2, Begin, Finally, MultiFilter2xyz, (99, 30, 4595), SimpleFilter1, Begin, Finally");
+
+ Assert.Throws(() => client.C().GetAwaiter().GetResult()).Status.Detail
+ .Should().Be("DumpFilter, SimpleFilter1, MoreThanFilter3 : MoreThanFilter3, Begin, Catch, Finally, MoreThanFilter3msg, put-class, SimpleFilter1, Begin, Catch, Finally");
+ }
+ }
+}
diff --git a/tests/MagicOnion.NetCoreTests/Tests/PartialDefinitionTest.cs b/tests/MagicOnion.NetCoreTests/Tests/PartialDefinitionTest.cs
new file mode 100644
index 000000000..bbccf56af
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/Tests/PartialDefinitionTest.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Threading.Tasks;
+using Grpc.Core;
+using MagicOnion.Client;
+using MagicOnion.Server;
+using Xunit;
+using Xunit.Abstractions;
+using FluentAssertions;
+
+namespace MagicOnion.Tests
+{
+ // note, do not allow partial definition.
+
+ //public interface IPartialDefinition : IService, IPartialDefinition2
+ //{
+ // UnaryResult Unary1(int x, int y);
+ //}
+
+
+ //public interface IPartialDefinition2
+ //{
+ // UnaryResult Unary2();
+ //}
+
+
+ //public class CombinedDefinition : ServiceBase, IPartialDefinition2
+ //{
+ // public UnaryResult Unary1(int x, int y)
+ // => this.UnaryResult(x + y);
+
+ // public UnaryResult Unary2()
+ // => this.UnaryResult(100);
+ //}
+
+
+ //[Collection(nameof(AllAssemblyGrpcServerFixture))]
+ //public class PartialDefinitionTest
+ //{
+ // ITestOutputHelper logger;
+ // IPartialDefinition client;
+
+ // public PartialDefinitionTest(ITestOutputHelper logger, ServerFixture server)
+ // {
+ // this.logger = logger;
+ // this.client = server.CreateClient();
+ // }
+
+ // [Fact]
+ // public async Task Unary1()
+ // {
+ // var r = await client.Unary1(10, 20);
+ // r.Should().Be(30);
+ // }
+
+ // [Fact]
+ // public async Task Unary2()
+ // {
+ // var r = await client.Unary2();
+ // r.Should().Be(100);
+ // }
+ //}
+}
\ No newline at end of file
diff --git a/tests/MagicOnion.NetCoreTests/Tests/ReturnStatusTest.cs b/tests/MagicOnion.NetCoreTests/Tests/ReturnStatusTest.cs
new file mode 100644
index 000000000..2acba4d43
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/Tests/ReturnStatusTest.cs
@@ -0,0 +1,130 @@
+using Grpc.Core;
+using MagicOnion.Client;
+using MagicOnion.Server;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using FluentAssertions;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace MagicOnion.Tests
+{
+ public interface IReturnStatus : IService
+ {
+ // 1 is exception
+ UnaryResult Unary1();
+ ClientStreamingResult ClientStreaming1();
+ ServerStreamingResult Serverstreaming1();
+ DuplexStreamingResult DuplexStreaming1();
+
+ // 2 is direct return
+ UnaryResult Unary2();
+ ClientStreamingResult ClientStreaming2();
+ ServerStreamingResult Serverstreaming2();
+ DuplexStreamingResult DuplexStreaming2();
+
+ // others
+ UnaryResult CustomThrow(int code);
+ }
+
+ public class ReturnStatus : ServiceBase, IReturnStatus
+ {
+ public ClientStreamingResult ClientStreaming1()
+ {
+ throw new ReturnStatusException(Grpc.Core.StatusCode.Aborted, "a");
+ }
+
+ public ClientStreamingResult ClientStreaming2()
+ {
+ return GetClientStreamingContext().ReturnStatus(Grpc.Core.StatusCode.InvalidArgument, "b");
+ }
+
+ public DuplexStreamingResult DuplexStreaming1()
+ {
+ throw new ReturnStatusException(Grpc.Core.StatusCode.Aborted, "a");
+ }
+
+ public DuplexStreamingResult DuplexStreaming2()
+ {
+ return GetDuplexStreamingContext().ReturnStatus(Grpc.Core.StatusCode.InvalidArgument, "b");
+ }
+
+ public ServerStreamingResult Serverstreaming1()
+ {
+ throw new ReturnStatusException(Grpc.Core.StatusCode.Aborted, "a");
+ }
+
+ public ServerStreamingResult Serverstreaming2()
+ {
+ return GetServerStreamingContext().ReturnStatus(Grpc.Core.StatusCode.InvalidArgument, "b");
+ }
+
+ public UnaryResult Unary1()
+ {
+ throw new ReturnStatusException(Grpc.Core.StatusCode.Aborted, "a");
+ }
+
+ public UnaryResult Unary2()
+ {
+ return ReturnStatus(Grpc.Core.StatusCode.InvalidArgument, "b");
+ }
+
+ public UnaryResult CustomThrow(int code)
+ {
+ return ReturnStatus((StatusCode)code, null);
+ }
+ }
+
+ [Collection(nameof(AllAssemblyGrpcServerFixture))]
+ public class ReturnStatusTest
+ {
+ ITestOutputHelper logger;
+ IReturnStatus client;
+
+ public ReturnStatusTest(ITestOutputHelper logger, ServerFixture server)
+ {
+ this.logger = logger;
+ this.client = server.CreateClient();
+ }
+
+ //[Fact]
+ //public void CheckException()
+ //{
+ // Assert.Throws(() => client.Unary1().ResponseAsync.GetAwaiter().GetResult())
+ // .Should().Be(x => x.Status.StatusCode == StatusCode.Aborted && x.Status.Detail == "a");
+ // Assert.Throws(() => client.ClientStreaming1().ResponseAsync.GetAwaiter().GetResult())
+ // .Should().Be(x => x.Status.StatusCode == StatusCode.Aborted && x.Status.Detail == "a");
+ // Assert.Throws(() => client.Serverstreaming1().ResponseStream.MoveNext().GetAwaiter().GetResult())
+ // .Should().Be(x => x.Status.StatusCode == StatusCode.Aborted && x.Status.Detail == "a");
+ // Assert.Throws(() => client.DuplexStreaming1().ResponseStream.MoveNext().GetAwaiter().GetResult())
+ // .Should().Be(x => x.Status.StatusCode == StatusCode.Aborted && x.Status.Detail == "a");
+ //}
+
+ //[Fact]
+ //public void CheckDirect()
+ //{
+ // Assert.Throws(() => client.Unary2().ResponseAsync.GetAwaiter().GetResult())
+ // .Should().Be(x => x.Status.StatusCode == StatusCode.InvalidArgument && x.Status.Detail == "b");
+ // Assert.Throws(() => client.ClientStreaming2().ResponseAsync.GetAwaiter().GetResult())
+ // .Should().Be(x => x.Status.StatusCode == StatusCode.InvalidArgument && x.Status.Detail == "b");
+ // Assert.Throws(() => client.Serverstreaming2().ResponseStream.MoveNext().GetAwaiter().GetResult())
+ // .Should().Be(x => x.Status.StatusCode == StatusCode.InvalidArgument && x.Status.Detail == "b");
+ // Assert.Throws(() => client.DuplexStreaming2().ResponseStream.MoveNext().GetAwaiter().GetResult())
+ // .Should().Be(x => x.Status.StatusCode == StatusCode.InvalidArgument && x.Status.Detail == "b");
+ //}
+
+ [Fact]
+ public void CheckCustomThrow()
+ {
+ var ex = Assert.Throws(() =>
+ {
+ client.CustomThrow(123).GetAwaiter().GetResult();
+ });
+
+ ex.Status.StatusCode.Should().Be((StatusCode)123);
+ }
+ }
+}
diff --git a/tests/MagicOnion.NetCoreTests/Tests/ServerErrorTest.cs b/tests/MagicOnion.NetCoreTests/Tests/ServerErrorTest.cs
new file mode 100644
index 000000000..c77d62b7a
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/Tests/ServerErrorTest.cs
@@ -0,0 +1,86 @@
+using Grpc.Core;
+using MagicOnion.Client;
+using MagicOnion.Server;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using FluentAssertions;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace MagicOnion.Tests
+{
+ public interface IOverloadMethod : IService
+ {
+ UnaryResult Hoge(int x);
+ UnaryResult Hoge(int x, int y);
+ }
+
+ [Ignore]
+ public class OverloadService : ServiceBase, IOverloadMethod
+ {
+ public UnaryResult Hoge(int x)
+ {
+ return UnaryResult(0);
+ }
+
+ public UnaryResult Hoge(int x, int y)
+ {
+ return UnaryResult(0);
+ }
+ }
+
+ public interface IArgumentMethod : IService
+ {
+ UnaryResult Hoge(int x);
+ ServerStreamingResult Huga(int x);
+ ClientStreamingResult Tako(int x);
+ DuplexStreamingResult Nano(int x);
+ }
+
+ public class ArgumentMethodService : ServiceBase, IArgumentMethod
+ {
+ public UnaryResult Hoge(int x)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ServerStreamingResult Huga(int x)
+ {
+ throw new NotImplementedException();
+ }
+
+ [Ignore]
+ public DuplexStreamingResult Nano(int x)
+ {
+ throw new NotImplementedException();
+ }
+
+ [Ignore]
+ public ClientStreamingResult Tako(int x)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class ServerErrorTest
+ {
+ //[Fact]
+ //public async Task Moge()
+ //{
+ // var service = MagicOnionEngine.BuildServerServiceDefinition(true);
+
+ // var server = new global::Grpc.Core.Server
+ // {
+ // Services = { service },
+ // Ports = { new ServerPort("localhost", 12345, ServerCredentials.Insecure) }
+ // };
+
+ // server.Start();
+
+ // //var channel = new Channel("localhost:12345", ChannelCredentials.Insecure);
+ // //await MagicOnionClient.Create(channel).Hoge(0);
+ //}
+ }
+}
diff --git a/tests/MagicOnion.NetCoreTests/Tests/SimpleTest.cs b/tests/MagicOnion.NetCoreTests/Tests/SimpleTest.cs
new file mode 100644
index 000000000..18ae6ab2d
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/Tests/SimpleTest.cs
@@ -0,0 +1,212 @@
+using Grpc.Core;
+using MagicOnion.Client;
+using MagicOnion.Server;
+using System;
+using System.Collections.Generic;
+using FluentAssertions;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace MagicOnion.Tests
+{
+ public interface ISimpleTest : IService
+ {
+ UnaryResult Unary1(int x, int y);
+ Task> Unary1Task(int x, int y);
+ UnaryResult Unary2(int x, int y);
+
+ ClientStreamingResult ClientStreaming1();
+ Task> ClientStreaming1Task();
+
+ ServerStreamingResult Serverstreaming1(int x, int y, int z);
+ Task> ServerStreaming1Task(int x, int y, int z);
+
+ DuplexStreamingResult DuplexStreaming1();
+ Task> DuplexStreaming1Task();
+ }
+
+ public class UnaryTestImpl : ServiceBase, ISimpleTest
+ {
+ public ClientStreamingResult ClientStreaming1()
+ {
+ var streaming = GetClientStreamingContext();
+
+ var list = new List();
+ // no listen from client...
+ return streaming.Result("finished:" + string.Join(", ", list));
+ }
+
+ public async Task> ClientStreaming1Task()
+ {
+ var streaming = GetClientStreamingContext();
+
+ var list = new List();
+ await streaming.ForEachAsync(x =>
+ {
+ list.Add(x);
+ });
+
+ return streaming.Result("finished:" + string.Join(", ", list));
+ }
+
+ public DuplexStreamingResult DuplexStreaming1()
+ {
+ var stream = GetDuplexStreamingContext();
+ return stream.Result();
+ }
+
+ public async Task> DuplexStreaming1Task()
+ {
+ var stream = GetDuplexStreamingContext();
+
+ var l = new List();
+
+ while (await stream.MoveNext())
+ {
+ l.Add(stream.Current);
+ await stream.WriteAsync(string.Join(", ", l));
+ }
+
+ return stream.Result();
+ }
+
+ public ServerStreamingResult Serverstreaming1(int x, int y, int z)
+ {
+ var stream = GetServerStreamingContext();
+
+ // no write?
+ return stream.Result();
+ }
+
+ public async Task> ServerStreaming1Task(int x, int y, int z)
+ {
+ var stream = GetServerStreamingContext();
+
+ var acc = 0;
+ for (int i = 0; i < z; i++)
+ {
+ acc = acc + x + y;
+ await stream.WriteAsync(acc.ToString());
+ }
+
+ return stream.Result();
+ }
+
+ public UnaryResult Unary1(int x, int y)
+ {
+ return UnaryResult(x + y);
+ }
+
+ public async Task> Unary1Task(int x, int y)
+ {
+ await Task.Yield();
+ return UnaryResult(x + y);
+ }
+
+#pragma warning disable CS1998
+
+ public async UnaryResult Unary2(int x, int y)
+ {
+ return x + y;
+ }
+
+#pragma warning restore CS1998
+
+ }
+
+ [Collection(nameof(AllAssemblyGrpcServerFixture))]
+ public class SimpleTest
+ {
+ ITestOutputHelper logger;
+ Channel channel;
+
+ public SimpleTest(ITestOutputHelper logger, ServerFixture server)
+ {
+ this.logger = logger;
+ this.channel = server.DefaultChannel;
+ }
+
+ [Fact]
+ public async Task Unary()
+ {
+ var client = MagicOnionClient.Create(channel);
+
+ var r = await client.Unary1(10, 20);
+ r.Should().Be(30);
+
+ var r2 = await await client.Unary1Task(1000, 2000);
+ r2.Should().Be(3000);
+ }
+
+ [Fact]
+ public async Task ClientStreaming()
+ {
+ var client = MagicOnionClient.Create(channel);
+ {
+ var r = await client.ClientStreaming1Task();
+ await r.RequestStream.WriteAsync(10);
+ await r.RequestStream.WriteAsync(20);
+ await r.RequestStream.WriteAsync(30);
+ await r.RequestStream.CompleteAsync();
+
+ var result = await r.ResponseAsync;
+ result.Should().Be("finished:10, 20, 30");
+ }
+ {
+ var r = client.ClientStreaming1();
+ var result = await r.ResponseAsync;
+ result.Should().Be("finished:");
+ }
+ }
+
+ [Fact]
+ public async Task ServerStreaming()
+ {
+ var client = MagicOnionClient.Create(channel);
+ {
+ var r = await client.ServerStreaming1Task(10, 20, 3);
+ await r.ResponseStream.MoveNext();
+ r.ResponseStream.Current.Should().Be("30");
+ await r.ResponseStream.MoveNext();
+ r.ResponseStream.Current.Should().Be("60");
+ await r.ResponseStream.MoveNext();
+ r.ResponseStream.Current.Should().Be("90");
+ }
+ {
+ var r = client.Serverstreaming1(100, 200, 3);
+ (await r.ResponseStream.MoveNext()).Should().BeFalse();
+ }
+ }
+
+ [Fact]
+ public async Task DuplexStreaming()
+ {
+ var client = MagicOnionClient.Create(channel);
+ {
+ var r = await client.DuplexStreaming1Task();
+
+ await r.RequestStream.WriteAsync(1000);
+ await r.ResponseStream.MoveNext();
+ r.ResponseStream.Current.Should().Be("1000");
+
+ await r.RequestStream.WriteAsync(2000);
+ await r.ResponseStream.MoveNext();
+ r.ResponseStream.Current.Should().Be("1000, 2000");
+
+ await r.RequestStream.WriteAsync(3000);
+ await r.ResponseStream.MoveNext();
+ r.ResponseStream.Current.Should().Be("1000, 2000, 3000");
+
+ await r.RequestStream.CompleteAsync();
+ (await r.ResponseStream.MoveNext()).Should().BeFalse();
+ }
+ {
+ var r = client.DuplexStreaming1();
+ (await r.ResponseStream.MoveNext()).Should().BeFalse();
+ }
+ }
+ }
+}
diff --git a/tests/MagicOnion.NetCoreTests/Tests/StreamingHubTest.cs b/tests/MagicOnion.NetCoreTests/Tests/StreamingHubTest.cs
new file mode 100644
index 000000000..c62996592
--- /dev/null
+++ b/tests/MagicOnion.NetCoreTests/Tests/StreamingHubTest.cs
@@ -0,0 +1,486 @@
+#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
+
+using Grpc.Core;
+using MagicOnion.Client;
+using MagicOnion.Server.Hubs;
+using FluentAssertions;
+using MessagePack;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace MagicOnion.Tests
+{
+ public interface IMessageReceiver
+ {
+ Task ZeroArgument();
+ Task OneArgument(int x);
+ Task MoreArgument(int x, string y, double z);
+ void VoidZeroArgument();
+ void VoidOneArgument(int x);
+ void VoidMoreArgument(int x, string y, double z);
+ Task OneArgument2(TestObject x);
+ void VoidOneArgument2(TestObject x);
+ Task OneArgument3(TestObject[] x);
+ void VoidOneArgument3(TestObject[] x);
+ }
+
+ public interface ITestHub : IStreamingHub
+ {
+ Task ZeroArgument();
+ Task OneArgument(int x);
+ Task MoreArgument(int x, string y, double z);
+
+ Task RetrunZeroArgument();
+ Task RetrunOneArgument(int x);
+ Task RetrunMoreArgument(int x, string y, double z);
+
+ Task OneArgument2(TestObject x);
+ Task RetrunOneArgument2(TestObject x);
+
+ Task OneArgument3(TestObject[] x);
+ Task RetrunOneArgument3(TestObject[] x);
+ }
+
+ [MessagePackObject]
+ public class TestObject
+ {
+ [Key(0)]
+ public int X { get; set; }
+ [Key(1)]
+ public int Y { get; set; }
+ [Key(2)]
+ public int Z { get; set; }
+ }
+
+ public class TestHub : StreamingHubBase, ITestHub
+ {
+ IGroup group;
+
+ protected override async ValueTask OnConnecting()
+ {
+ group = await Group.AddAsync("global");
+ }
+
+ protected override async ValueTask OnDisconnected()
+ {
+ if (group != null) await group.RemoveAsync(Context);
+ }
+
+
+ public async Task MoreArgument(int x, string y, double z)
+ {
+ Broadcast(group).VoidMoreArgument(x, y, z);
+ await Broadcast(group).MoreArgument(x, y, z);
+ }
+
+ public async Task OneArgument(int x)
+ {
+ Broadcast(group).VoidOneArgument(x);
+ await Broadcast(group).OneArgument(x);
+ }
+
+ public async Task OneArgument2(TestObject x)
+ {
+ Broadcast(group).VoidOneArgument2(x);
+ await Broadcast(group).OneArgument2(x);
+ }
+
+ public async Task OneArgument3(TestObject[] x)
+ {
+ Broadcast(group).VoidOneArgument3(x);
+ await Broadcast(group).OneArgument3(x);
+ }
+
+ public Task RetrunMoreArgument(int x, string y, double z)
+ {
+ return Task.FromResult(z);
+ }
+
+ public async Task RetrunOneArgument(int x)
+ {
+ return x.ToString();
+ }
+
+ public async Task RetrunOneArgument2(TestObject x)
+ {
+ return x;
+ }
+
+ public async Task RetrunOneArgument3(TestObject[] x)
+ {
+ return x;
+ }
+
+ public async Task RetrunZeroArgument()
+ {
+ return 1000;
+ }
+
+ public async Task ZeroArgument()
+ {
+ Broadcast(group).VoidZeroArgument();
+ await Broadcast(group).ZeroArgument();
+ }
+ }
+
+ [Collection(nameof(AllAssemblyGrpcServerFixture))]
+ public class BasicStreamingHubTest : IMessageReceiver, IDisposable
+ {
+ ITestOutputHelper logger;
+ Channel channel;
+ ITestHub client;
+
+ public BasicStreamingHubTest(ITestOutputHelper logger, ServerFixture server)
+ {
+ this.logger = logger;
+ this.channel = server.DefaultChannel;
+ }
+
+ [Fact]
+ public async Task ZeroArgument()
+ {
+ client = StreamingHubClient.Connect(channel, this);
+ await client.ZeroArgument();
+ await voidZeroTask.Task;
+ await zeroTask.Task;
+ // ok, pass.
+
+ await client.DisposeAsync();
+ }
+
+ [Fact]
+ public async Task OneArgument()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ await client.OneArgument(100);
+ var x = await oneTask.Task;
+ var y = await voidoneTask.Task;
+ x.Should().Be(100);
+ y.Should().Be(100);
+ await client.DisposeAsync();
+ }
+
+ [Fact]
+ public async Task MoreArgument()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ await client.MoreArgument(100, "foo", 10.3);
+ var x = await moreTask.Task;
+ var y = await voidmoreTask.Task;
+ x.Should().Be((100, "foo", 10.3));
+ y.Should().Be((100, "foo", 10.3));
+ await client.DisposeAsync();
+ }
+
+ [Fact]
+ public async Task RetrunZeroArgument()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ var v = await client.RetrunZeroArgument();
+ v.Should().Be(1000);
+ await client.DisposeAsync();
+ }
+ [Fact]
+ public async Task RetrunOneArgument()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ var v = await client.RetrunZeroArgument();
+ v.Should().Be(1000);
+ await client.DisposeAsync();
+ }
+ [Fact]
+ public async Task RetrunMoreArgument()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ var v = await client.RetrunMoreArgument(10, "foo", 30.4);
+ v.Should().Be(30.4);
+ await client.DisposeAsync();
+ }
+
+ [Fact]
+ public async Task OneArgument2()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ await client.OneArgument2(new TestObject() { X = 10, Y = 99, Z = 100 });
+ {
+ var v = await one2Task.Task;
+ v.X.Should().Be(10);
+ v.Y.Should().Be(99);
+ v.Z.Should().Be(100);
+ }
+ {
+ var v = await voidone2Task.Task;
+ v.X.Should().Be(10);
+ v.Y.Should().Be(99);
+ v.Z.Should().Be(100);
+ }
+ await client.DisposeAsync();
+ }
+ [Fact]
+ public async Task RetrunOneArgument2()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ var v = await client.RetrunOneArgument2(new TestObject() { X = 10, Y = 99, Z = 100 });
+ v.X.Should().Be(10);
+ v.Y.Should().Be(99);
+ v.Z.Should().Be(100);
+ await client.DisposeAsync();
+ }
+
+ [Fact]
+ public async Task OneArgument3()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ await client.OneArgument3(new[]
+ {
+ new TestObject() { X = 10, Y = 99, Z = 100 },
+ new TestObject() { X = 5, Y = 39, Z = 200 },
+ new TestObject() { X = 4, Y = 59, Z = 300 },
+ });
+ {
+ var v = await one3Task.Task;
+
+ v[0].X.Should().Be(10);
+ v[0].Y.Should().Be(99);
+ v[0].Z.Should().Be(100);
+
+ v[1].X.Should().Be(5);
+ v[1].Y.Should().Be(39);
+ v[1].Z.Should().Be(200);
+
+ v[2].X.Should().Be(4);
+ v[2].Y.Should().Be(59);
+ v[2].Z.Should().Be(300);
+ }
+ {
+ var v = await voidone3Task.Task;
+
+ v[0].X.Should().Be(10);
+ v[0].Y.Should().Be(99);
+ v[0].Z.Should().Be(100);
+
+ v[1].X.Should().Be(5);
+ v[1].Y.Should().Be(39);
+ v[1].Z.Should().Be(200);
+
+ v[2].X.Should().Be(4);
+ v[2].Y.Should().Be(59);
+ v[2].Z.Should().Be(300);
+ }
+ await client.DisposeAsync();
+ }
+ [Fact]
+ public async Task RetrunOneArgument3()
+ {
+ var client = StreamingHubClient.Connect(channel, this);
+ var v = await client.RetrunOneArgument3(new[]
+ {
+ new TestObject() { X = 10, Y = 99, Z = 100 },
+ new TestObject() { X = 5, Y = 39, Z = 200 },
+ new TestObject() { X = 4, Y = 59, Z = 300 },
+ });
+
+ v[0].X.Should().Be(10);
+ v[0].Y.Should().Be(99);
+ v[0].Z.Should().Be(100);
+
+ v[1].X.Should().Be(5);
+ v[1].Y.Should().Be(39);
+ v[1].Z.Should().Be(200);
+
+ v[2].X.Should().Be(4);
+ v[2].Y.Should().Be(59);
+ v[2].Z.Should().Be(300);
+ await client.DisposeAsync();
+ }
+
+
+
+ TaskCompletionSource<(int, string, double)> moreTask = new TaskCompletionSource<(int, string, double)>();
+ async Task IMessageReceiver.MoreArgument(int x, string y, double z)
+ {
+ moreTask.TrySetResult((x, y, z));
+ }
+
+ TaskCompletionSource oneTask = new TaskCompletionSource();
+ async Task IMessageReceiver.OneArgument(int x)
+ {
+ oneTask.TrySetResult(x);
+ }
+
+ TaskCompletionSource one2Task = new TaskCompletionSource();
+ async Task IMessageReceiver.OneArgument2(TestObject x)
+ {
+ one2Task.TrySetResult(x);
+ }
+
+ TaskCompletionSource one3Task = new TaskCompletionSource();
+ async Task IMessageReceiver.OneArgument3(TestObject[] x)
+ {
+ one3Task.TrySetResult(x);
+ }
+
+ TaskCompletionSource<(int, string, double)> voidmoreTask = new TaskCompletionSource<(int, string, double)>();
+ void IMessageReceiver.VoidMoreArgument(int x, string y, double z)
+ {
+ voidmoreTask.TrySetResult((x, y, z));
+ }
+
+ TaskCompletionSource voidoneTask = new TaskCompletionSource();
+ void IMessageReceiver.VoidOneArgument(int x)
+ {
+ voidoneTask.TrySetResult(x);
+ }
+
+ TaskCompletionSource voidone2Task = new TaskCompletionSource();
+ void IMessageReceiver.VoidOneArgument2(TestObject x)
+ {
+ voidone2Task.TrySetResult(x);
+ }
+
+ TaskCompletionSource voidone3Task = new TaskCompletionSource();
+ void IMessageReceiver.VoidOneArgument3(TestObject[] x)
+ {
+ voidone3Task.TrySetResult(x);
+ }
+
+ TaskCompletionSource