Skip to content

Commit e72ff9a

Browse files
authored
Merge pull request #135 from jacqueskang/history/v2.2.2
History/v2.2.2
2 parents 8e93d28 + b906149 commit e72ff9a

File tree

16 files changed

+335
-32
lines changed

16 files changed

+335
-32
lines changed

src/.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[*.cs]
2+
indent_style = space
3+
indent_size = 4
4+
insert_final_newline = true

src/IpcServiceFramework.sln

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio 15
4-
VisualStudioVersion = 15.0.27004.2002
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.28803.156
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{03210BFB-17B1-4775-A8A2-D302ECBF2F46}"
77
EndProject
@@ -13,6 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpcServiceSample.ConsoleCli
1313
EndProject
1414
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{20913218-C740-42E9-9D17-CAD973B676D0}"
1515
ProjectSection(SolutionItems) = preProject
16+
.editorconfig = .editorconfig
1617
..\.travis.yml = ..\.travis.yml
1718
Directory.Build.props = Directory.Build.props
1819
..\README.md = ..\README.md
@@ -28,6 +29,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JKang.IpcServiceFramework.C
2829
EndProject
2930
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpcServiceSample.WebServer", "IpcServiceSample.WebServer\IpcServiceSample.WebServer.csproj", "{D57727B9-81F1-439A-AD17-0DB26C8F0523}"
3031
EndProject
32+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JKang.IpcServiceFramework.IntegrationTests", "JKang.IpcServiceFramework.IntegrationTests\JKang.IpcServiceFramework.IntegrationTests.csproj", "{451DE9A3-7A34-487B-823C-FB3C6B6EF20D}"
33+
EndProject
3134
Global
3235
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3336
Debug|Any CPU = Debug|Any CPU
@@ -66,6 +69,10 @@ Global
6669
{D57727B9-81F1-439A-AD17-0DB26C8F0523}.Debug|Any CPU.Build.0 = Debug|Any CPU
6770
{D57727B9-81F1-439A-AD17-0DB26C8F0523}.Release|Any CPU.ActiveCfg = Release|Any CPU
6871
{D57727B9-81F1-439A-AD17-0DB26C8F0523}.Release|Any CPU.Build.0 = Release|Any CPU
72+
{451DE9A3-7A34-487B-823C-FB3C6B6EF20D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
73+
{451DE9A3-7A34-487B-823C-FB3C6B6EF20D}.Debug|Any CPU.Build.0 = Debug|Any CPU
74+
{451DE9A3-7A34-487B-823C-FB3C6B6EF20D}.Release|Any CPU.ActiveCfg = Release|Any CPU
75+
{451DE9A3-7A34-487B-823C-FB3C6B6EF20D}.Release|Any CPU.Build.0 = Release|Any CPU
6976
EndGlobalSection
7077
GlobalSection(SolutionProperties) = preSolution
7178
HideSolutionNode = FALSE

src/IpcServiceSample.ConsoleClient/Program.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@ private static async Task MainAsync(string[] args)
2222
{
2323
try
2424
{
25-
Console.WriteLine("Press any key to stop.");
25+
Console.WriteLine("Press any key to cancel.");
2626
var source = new CancellationTokenSource();
2727

2828
await Task.WhenAll(RunTestsAsync(source.Token), Task.Run(() =>
2929
{
3030
Console.ReadKey();
31-
Console.WriteLine("Cancelling...");
3231
source.Cancel();
3332
}));
3433
}
@@ -137,6 +136,8 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken)
137136
// test 14: use a translated stream to log data to a text file
138137
generatedId = await loggedClient.InvokeAsync(x => x.GenerateId(), cancellationToken);
139138
Console.WriteLine($"[TEST 14] Called method using stream translator for logging, generated ID is: {generatedId}");
139+
140+
Console.WriteLine("All test finished. Press any key to exit.");
140141
}
141142
}
142143
}

src/JKang.IpcServiceFramework.Client/IpcServiceClient.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public async Task InvokeAsync(Expression<Action<TInterface>> exp,
2828
CancellationToken cancellationToken = default(CancellationToken))
2929
{
3030
IpcRequest request = GetRequest(exp, new MyInterceptor());
31-
IpcResponse response = await GetResponseAsync(request, cancellationToken);
31+
IpcResponse response = await GetResponseAsync(request, cancellationToken).ConfigureAwait(false);
3232

3333
if (response.Succeed)
3434
{
@@ -44,7 +44,7 @@ public async Task<TResult> InvokeAsync<TResult>(Expression<Func<TInterface, TRes
4444
CancellationToken cancellationToken = default(CancellationToken))
4545
{
4646
IpcRequest request = GetRequest(exp, new MyInterceptor<TResult>());
47-
IpcResponse response = await GetResponseAsync(request, cancellationToken);
47+
IpcResponse response = await GetResponseAsync(request, cancellationToken).ConfigureAwait(false);
4848

4949
if (response.Succeed)
5050
{
@@ -67,7 +67,7 @@ public async Task InvokeAsync(Expression<Func<TInterface, Task>> exp,
6767
CancellationToken cancellationToken = default(CancellationToken))
6868
{
6969
IpcRequest request = GetRequest(exp, new MyInterceptor<Task>());
70-
IpcResponse response = await GetResponseAsync(request, cancellationToken);
70+
IpcResponse response = await GetResponseAsync(request, cancellationToken).ConfigureAwait(false);
7171

7272
if (response.Succeed)
7373
{
@@ -83,7 +83,7 @@ public async Task<TResult> InvokeAsync<TResult>(Expression<Func<TInterface, Task
8383
CancellationToken cancellationToken = default(CancellationToken))
8484
{
8585
IpcRequest request = GetRequest(exp, new MyInterceptor<Task<TResult>>());
86-
IpcResponse response = await GetResponseAsync(request, cancellationToken);
86+
IpcResponse response = await GetResponseAsync(request, cancellationToken).ConfigureAwait(false);
8787

8888
if (response.Succeed)
8989
{
@@ -131,7 +131,7 @@ private static IpcRequest GetRequest(Expression exp, MyInterceptor interceptor)
131131

132132
private async Task<IpcResponse> GetResponseAsync(IpcRequest request, CancellationToken cancellationToken)
133133
{
134-
using (Stream client = await ConnectToServerAsync(cancellationToken))
134+
using (Stream client = await ConnectToServerAsync(cancellationToken).ConfigureAwait(false))
135135
using (var writer = new IpcWriter(client, _serializer, leaveOpen: true))
136136
using (var reader = new IpcReader(client, _serializer, leaveOpen: true))
137137
{

src/JKang.IpcServiceFramework.Client/NamedPipe/NamedPipeIpcServiceClient.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using JKang.IpcServiceFramework.Services;
2+
using System;
23
using System.IO;
34
using System.IO.Pipes;
45
using System.Threading;
@@ -19,8 +20,8 @@ public NamedPipeIpcServiceClient(IIpcMessageSerializer serializer, IValueConvert
1920

2021
protected override async Task<Stream> ConnectToServerAsync(CancellationToken cancellationToken)
2122
{
22-
var stream = new NamedPipeClientStream(".", _pipeName, PipeDirection.InOut, PipeOptions.None);
23-
await stream.ConnectAsync(cancellationToken);
23+
var stream = new NamedPipeClientStream(".", _pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
24+
await stream.ConnectAsync((int)TimeSpan.FromSeconds(3).TotalMilliseconds, cancellationToken).ConfigureAwait(false);
2425
return stream;
2526
}
2627
}

src/JKang.IpcServiceFramework.Client/Tcp/TcpIpcServiceClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ await Task.Run(() =>
7878
cancellationToken.ThrowIfCancellationRequested();
7979
}
8080
}
81-
});
81+
}).ConfigureAwait(false);
8282

8383
cancellationToken.Register(() =>
8484
{

src/JKang.IpcServiceFramework.Core/IO/IpcReader.cs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,53 @@ public IpcReader(Stream stream, IIpcMessageSerializer serializer, bool leaveOpen
2525

2626
public async Task<IpcRequest> ReadIpcRequestAsync(CancellationToken cancellationToken = default(CancellationToken))
2727
{
28-
byte[] binary = await ReadMessageAsync(cancellationToken);
28+
byte[] binary = await ReadMessageAsync(cancellationToken).ConfigureAwait(false);
2929
return _serializer.DeserializeRequest(binary);
3030
}
3131

3232
public async Task<IpcResponse> ReadIpcResponseAsync(CancellationToken cancellationToken = default(CancellationToken))
3333
{
34-
byte[] binary = await ReadMessageAsync(cancellationToken);
34+
byte[] binary = await ReadMessageAsync(cancellationToken).ConfigureAwait(false);
3535
return _serializer.DeserializeResponse(binary);
3636
}
3737

3838
private async Task<byte[]> ReadMessageAsync(CancellationToken cancellationToken)
3939
{
40-
await _stream.ReadAsync(_lengthBuffer, 0, _lengthBuffer.Length, cancellationToken);
41-
int length = _lengthBuffer[0] | _lengthBuffer[1] << 8 | _lengthBuffer[2] << 16 | _lengthBuffer[3] << 24;
40+
int headerLength = await _stream.ReadAsync(_lengthBuffer, 0, _lengthBuffer.Length, cancellationToken);
4241

43-
byte[] bytes = new byte[length];
44-
await _stream.ReadAsync(bytes, 0, length, cancellationToken);
42+
if (headerLength != 4)
43+
{
44+
throw new ArgumentOutOfRangeException($"Header length must be 4 but was {headerLength}");
45+
}
46+
47+
int expectedLength = _lengthBuffer[0] | _lengthBuffer[1] << 8 | _lengthBuffer[2] << 16 | _lengthBuffer[3] << 24;
48+
byte[] bytes = new byte[expectedLength];
49+
int totalBytesReceived = 0;
50+
int remainingBytes = expectedLength;
51+
52+
using (var ms = new MemoryStream())
53+
{
54+
while (totalBytesReceived < expectedLength)
55+
{
56+
int dataLength = await _stream.ReadAsync(bytes, 0, remainingBytes, cancellationToken);
57+
58+
if (dataLength == 0)
59+
{
60+
break; // end of stream or stream shut down.
61+
}
62+
63+
ms.Write(bytes, 0, dataLength);
64+
totalBytesReceived += dataLength;
65+
remainingBytes -= dataLength;
66+
}
67+
68+
bytes = ms.ToArray();
69+
}
70+
71+
if (totalBytesReceived != expectedLength)
72+
{
73+
throw new System.ArgumentOutOfRangeException($"Data length must be {expectedLength} but was {totalBytesReceived}");
74+
}
4575

4676
return bytes;
4777
}

src/JKang.IpcServiceFramework.Core/IO/IpcWriter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ public async Task WriteAsync(IpcRequest request,
2727
CancellationToken cancellationToken = default(CancellationToken))
2828
{
2929
byte[] binary = _serializer.SerializeRequest(request);
30-
await WriteMessageAsync(binary, cancellationToken);
30+
await WriteMessageAsync(binary, cancellationToken).ConfigureAwait(false);
3131
}
3232

3333
public async Task WriteAsync(IpcResponse response,
3434
CancellationToken cancellationToken = default(CancellationToken))
3535
{
3636
byte[] binary = _serializer.SerializeResponse(response);
37-
await WriteMessageAsync(binary, cancellationToken);
37+
await WriteMessageAsync(binary, cancellationToken).ConfigureAwait(false);
3838
}
3939

4040
private async Task WriteMessageAsync(byte[] binary, CancellationToken cancellationToken)
@@ -45,8 +45,8 @@ private async Task WriteMessageAsync(byte[] binary, CancellationToken cancellati
4545
_lengthBuffer[2] = (byte)(length >> 16);
4646
_lengthBuffer[3] = (byte)(length >> 24);
4747

48-
await _stream.WriteAsync(_lengthBuffer, 0, _lengthBuffer.Length, cancellationToken);
49-
await _stream.WriteAsync(binary, 0, binary.Length, cancellationToken);
48+
await _stream.WriteAsync(_lengthBuffer, 0, _lengthBuffer.Length, cancellationToken).ConfigureAwait(false);
49+
await _stream.WriteAsync(binary, 0, binary.Length, cancellationToken).ConfigureAwait(false);
5050
}
5151

5252
#region IDisposible
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using AutoFixture.Xunit2;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Globalization;
6+
using System.Net;
7+
using System.Numerics;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using Xunit;
11+
12+
namespace JKang.IpcServiceFramework.IntegrationTests
13+
{
14+
public class ContractTest : IDisposable
15+
{
16+
private readonly CancellationTokenSource _cancellationToken;
17+
private readonly int _port;
18+
private readonly IpcServiceClient<ITestService> _client;
19+
20+
public ContractTest()
21+
{
22+
// configure DI
23+
IServiceCollection services = new ServiceCollection()
24+
.AddIpc(builder => builder.AddNamedPipe().AddService<ITestService, TestService>());
25+
_port = new Random().Next(10000, 50000);
26+
IIpcServiceHost host = new IpcServiceHostBuilder(services.BuildServiceProvider())
27+
.AddTcpEndpoint<ITestService>(
28+
name: Guid.NewGuid().ToString(),
29+
ipEndpoint: IPAddress.Loopback,
30+
port: _port)
31+
.Build();
32+
_cancellationToken = new CancellationTokenSource();
33+
host.RunAsync(_cancellationToken.Token);
34+
35+
_client = new IpcServiceClientBuilder<ITestService>()
36+
.UseTcp(IPAddress.Loopback, _port)
37+
.Build();
38+
}
39+
40+
[Theory, AutoData]
41+
public async Task SimpleType(float a, float b)
42+
{
43+
float actual = await _client.InvokeAsync(x => x.AddFloat(a, b));
44+
float expected = new TestService().AddFloat(a, b);
45+
Assert.Equal(expected, actual);
46+
}
47+
48+
[Theory, AutoData]
49+
public async Task ComplexType(Complex a, Complex b)
50+
{
51+
Complex actual = await _client.InvokeAsync(x => x.AddComplex(a, b));
52+
Complex expected = new TestService().AddComplex(a, b);
53+
Assert.Equal(expected, actual);
54+
}
55+
56+
[Theory, AutoData]
57+
public async Task ComplexTypeArray(IEnumerable<Complex> array)
58+
{
59+
Complex actual = await _client.InvokeAsync(x => x.SumComplexArray(array));
60+
Complex expected = new TestService().SumComplexArray(array);
61+
Assert.Equal(expected, actual);
62+
}
63+
64+
[Fact]
65+
public async Task ReturnVoid()
66+
{
67+
await _client.InvokeAsync(x => x.DoNothing());
68+
}
69+
70+
[Theory, InlineData(" 2008-06-11T16:11:20.0904778Z", DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowWhiteSpaces)]
71+
public async Task EnumParameter(string value, DateTimeStyles styles)
72+
{
73+
DateTime actual = await _client.InvokeAsync(x => x.ParseDate(value, styles));
74+
DateTime expected = new TestService().ParseDate(value, styles);
75+
Assert.Equal(expected, actual);
76+
}
77+
78+
[Theory, AutoData]
79+
public async Task ByteArray(byte[] input)
80+
{
81+
byte[] actual = await _client.InvokeAsync(x => x.ReverseBytes(input));
82+
byte[] expected = new TestService().ReverseBytes(input);
83+
Assert.Equal(expected, actual);
84+
}
85+
86+
[Fact]
87+
public async Task GenericParameter()
88+
{
89+
decimal actual = await _client.InvokeAsync(x => x.GetDefaultValue<decimal>());
90+
decimal expected = new TestService().GetDefaultValue<decimal>();
91+
Assert.Equal(expected, actual);
92+
}
93+
94+
[Fact]
95+
public async Task AsyncOperation()
96+
{
97+
long actual = await _client.InvokeAsync(x => x.WaitAsync(500));
98+
Assert.True(actual >= 450);
99+
}
100+
101+
public void Dispose()
102+
{
103+
_cancellationToken.Cancel();
104+
}
105+
}
106+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using AutoFixture.Xunit2;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Globalization;
6+
using System.IO;
7+
using System.Net;
8+
using System.Numerics;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using Xunit;
12+
13+
namespace JKang.IpcServiceFramework.IntegrationTests
14+
{
15+
public class EdgeCaseTest : IDisposable
16+
{
17+
private readonly CancellationTokenSource _cancellationToken;
18+
private readonly int _port;
19+
private readonly IpcServiceClient<ITestService> _client;
20+
21+
public EdgeCaseTest()
22+
{
23+
// configure DI
24+
IServiceCollection services = new ServiceCollection()
25+
.AddIpc(builder => builder.AddNamedPipe().AddService<ITestService, TestService>());
26+
_port = new Random().Next(10000, 50000);
27+
IIpcServiceHost host = new IpcServiceHostBuilder(services.BuildServiceProvider())
28+
.AddTcpEndpoint<ITestService>(
29+
name: Guid.NewGuid().ToString(),
30+
ipEndpoint: IPAddress.Loopback,
31+
port: _port)
32+
.Build();
33+
_cancellationToken = new CancellationTokenSource();
34+
host.RunAsync(_cancellationToken.Token);
35+
36+
_client = new IpcServiceClientBuilder<ITestService>()
37+
.UseTcp(IPAddress.Loopback, _port)
38+
.Build();
39+
}
40+
41+
[Fact]
42+
public async Task HugeMessage()
43+
{
44+
byte[] buffer = new byte[100000000]; // 100MB
45+
new Random().NextBytes(buffer);
46+
byte[] result = await _client.InvokeAsync(x => x.ReverseBytes(buffer));
47+
}
48+
49+
public void Dispose()
50+
{
51+
_cancellationToken.Cancel();
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)