├── .github
└── workflows
│ └── dotnetcore.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── GrpcDotNetNamedPipes.PerfTests
├── GrpcDotNetNamedPipes.PerfTests.csproj
├── GrpcPerformanceTests.cs
└── Helpers
│ ├── AspNetHttpContextFactory.cs
│ ├── AspNetPipeContextFactory.cs
│ ├── AspNetUdsContextFactory.cs
│ └── MultiChannelClassData.cs
├── GrpcDotNetNamedPipes.Tests
├── GrpcDotNetNamedPipes.Tests.csproj
├── GrpcNamedPipeTests.cs
├── Helpers
│ ├── ChannelContext.cs
│ ├── ChannelContextFactory.cs
│ ├── MultiChannelClassData.cs
│ ├── NamedPipeChannelContextFactory.cs
│ └── NamedPipeClassData.cs
├── TestService.proto
└── TestServiceImpl.cs
├── GrpcDotNetNamedPipes.sln
├── GrpcDotNetNamedPipes
├── GrpcDotNetNamedPipes.csproj
├── Internal
│ ├── ClientConnectionContext.cs
│ ├── Deadline.cs
│ ├── EndOfPipeException.cs
│ ├── Helpers
│ │ ├── ByteArrayBufferWriter.cs
│ │ ├── ByteArrayDeserializationContext.cs
│ │ ├── ByteArraySerializationContext.cs
│ │ ├── ConnectionLogger.cs
│ │ ├── PipeInterop.cs
│ │ └── SerializationHelpers.cs
│ ├── MessageReader.cs
│ ├── PayloadQueue.cs
│ ├── PipeReader.cs
│ ├── PlatformConfig.cs
│ ├── Protocol
│ │ ├── NamedPipeTransport.cs
│ │ ├── WriteTransaction.cs
│ │ ├── WriteTransactionQueue.cs
│ │ └── transport.proto
│ ├── RequestStreamWriterImpl.cs
│ ├── ResponseStreamWriterImpl.cs
│ ├── ServerConnectionContext.cs
│ ├── ServerStreamPool.cs
│ ├── SimpleAsyncLock.cs
│ ├── StreamWriterImpl.cs
│ └── TransportMessageHandler.cs
├── NamedPipeCallContext.cs
├── NamedPipeChannel.cs
├── NamedPipeChannelOptions.cs
├── NamedPipeErrorEventArgs.cs
├── NamedPipeServer.cs
├── NamedPipeServerOptions.cs
└── public_signing_key.snk
├── LICENSE
├── README.md
└── nuget.config
/.github/workflows/dotnetcore.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: ${{ matrix.os }}
8 | strategy:
9 | matrix:
10 | os: [windows-2022, ubuntu-24.04, macos-14]
11 | steps:
12 | - uses: actions/checkout@v4
13 | - name: Setup .NET 9
14 | uses: actions/setup-dotnet@v4
15 | with:
16 | dotnet-version: 9.0.x
17 | - name: Install dependencies
18 | run: dotnet restore
19 | - name: Build
20 | run: dotnet build GrpcDotNetNamedPipes.Tests --configuration Release --no-restore
21 | - name: Test
22 | run: dotnet test GrpcDotNetNamedPipes.Tests --no-restore -l "console;verbosity=normal"
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | [Oo]bj/
2 | [Bb]in/
3 | TestResults/
4 | .nuget/
5 | *.sln.ide/
6 | _ReSharper.*/
7 | .idea/
8 | packages/
9 | artifacts/
10 | PublishProfiles/
11 | .vs/
12 | *.user
13 | *.suo
14 | *.cache
15 | *.docstates
16 | _ReSharper.*
17 | nuget.exe
18 | *net45.csproj
19 | *net451.csproj
20 | *k10.csproj
21 | *.psess
22 | *.vsp
23 | *.pidb
24 | *.userprefs
25 | *DS_Store
26 | *.ncrunchsolution
27 | *.*sdf
28 | *.ipch
29 | *.swp
30 | *~
31 | .build/
32 | .testPublish/
33 | launchSettings.json
34 | BenchmarkDotNet.Artifacts/
35 | BDN.Generated/
36 | binaries/
37 | global.json
38 | .vscode/
39 | *.binlog
40 | build/feed
41 | .dotnet/
42 | *.log.txt
43 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 3.1.0
4 | - Add NET 8 targets
5 | - Fix an extraneous error when the pipe is closed ([#65](https://github.com/cyanfish/grpc-dotnet-namedpipes/pull/65))
6 | - Update dependency versions
7 |
8 | ## 3.0.0
9 | - Potential breaking changes:
10 | - Async calls are now fully async (they used to block until the pipe was connected)
11 | - Using a single NamedPipeChannel object is now recommended for parallel calls
12 | - Fix an issue where heavily multi-threaded calls can stall on Windows
13 | - Use custom retry logic for pipe connections for more reliable connections
14 | - Fix a small memory leak
15 | - Fix trailers not being included in responses with errors
16 | - Fix invalid connections staying open forever
17 |
18 | ## 2.1.1
19 | - Improve connection reliability in some cases
20 | - Update dependency versions
21 |
22 | ## 2.1.0
23 | - Improve streaming performance
24 | - Improve connection reliability in some cases
25 | - Implement ServerCallContext.Peer ([#37](https://github.com/cyanfish/grpc-dotnet-namedpipes/issues/37))
26 | - Set cancellation token on client disconnect ([#30](https://github.com/cyanfish/grpc-dotnet-namedpipes/issues/30))
27 | - The [readme](https://github.com/cyanfish/grpc-dotnet-namedpipes) now has a comparison matrix for ASP.NET gRPC
28 |
29 | ## 2.0.0
30 | - Add macOS and Linux support
31 | - Change build targets to: net462, net6, netstandard2.0
32 | - Bump assembly version
33 | - Set a default connection timeout of 30s (instead of unlimited)
34 | - Add NamedPipeServer.Error event for previously unlogged errors
35 |
36 | ## 1.4.4
37 | - Add strong naming to the assembly
38 |
39 | ## 1.4.2
40 | - Throw an exception when starting an already-killed server
41 |
42 | ## 1.4.1
43 | - Fix server cleanup issues
44 |
45 | ## 1.4.0
46 | - Fix cancellation issues
47 |
48 | ## 1.3.0
49 | - Add a .NET 5 build with support for pipe security options
50 |
51 | ## 1.2.0
52 | - Update to newer gRPC API (2.32)
53 |
54 | ## 1.1.2
55 | - Fix gRPC dependency version range to <2.32
56 |
57 | ## 1.1.1
58 | - Update project metadata
59 |
60 | ## 1.1.0
61 | - Add a ConnectionTimeout client option (defaults to infinite)
62 |
63 | ## 1.0.2
64 | - Improve server connection error handling
65 |
66 | ## 1.0.1
67 | - Initial public release with core functionality
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows [Google's Open Source Community
28 | Guidelines](https://opensource.google/conduct/).
29 |
--------------------------------------------------------------------------------
/GrpcDotNetNamedPipes.PerfTests/GrpcDotNetNamedPipes.PerfTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8;net462
5 | net8
6 | 13
7 | true
8 | ../GrpcDotNetNamedPipes/public_signing_key.snk
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/GrpcDotNetNamedPipes.PerfTests/GrpcPerformanceTests.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | using Google.Protobuf;
18 |
19 | namespace GrpcDotNetNamedPipes.PerfTests;
20 |
21 | public class GrpcPerformanceTests
22 | {
23 | private const int Timeout = 60_000;
24 |
25 | private readonly ITestOutputHelper _testOutputHelper;
26 |
27 | public GrpcPerformanceTests(ITestOutputHelper testOutputHelper)
28 | {
29 | _testOutputHelper = testOutputHelper;
30 | }
31 |
32 | [Theory(Timeout = Timeout)]
33 | [ClassData(typeof(MultiChannelWithAspNetClassData))]
34 | public async Task ServerStreamingManyMessagesPerformance(ChannelContextFactory factory)
35 | {
36 | using var ctx = factory.Create();
37 | var stopwatch = Stopwatch.StartNew();
38 | var call = ctx.Client.ServerStreaming(new RequestMessage { Value = 100_000 });
39 | while (await call.ResponseStream.MoveNext())
40 | {
41 | }
42 |
43 | stopwatch.Stop();
44 | _testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
45 | }
46 |
47 | [Theory(Timeout = Timeout)]
48 | [ClassData(typeof(MultiChannelWithAspNetClassData))]
49 | public void UnarySequentialChannelsPerformance(ChannelContextFactory factory)
50 | {
51 | using var ctx = factory.Create();
52 | var stopwatch = Stopwatch.StartNew();
53 | for (int i = 0; i < 1_000; i++)
54 | {
55 | var client = factory.CreateClient();
56 | client.SimpleUnary(new RequestMessage());
57 | }
58 |
59 | stopwatch.Stop();
60 | _testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
61 | }
62 |
63 | // Windows seems to stall when 32+ threads try to connect to a named pipe at once
64 | [Theory(Timeout = Timeout, Skip = "named pipes fail with too many parallel channels")]
65 | [ClassData(typeof(MultiChannelWithAspNetClassData))]
66 | public async Task UnaryParallelChannelsPerformance(ChannelContextFactory factory)
67 | {
68 | using var ctx = factory.Create();
69 | var stopwatch = Stopwatch.StartNew();
70 | var tasks = new Task[1_000];
71 | for (int i = 0; i < tasks.Length; i++)
72 | {
73 | var client = factory.CreateClient();
74 | tasks[i] = client.SimpleUnaryAsync(new RequestMessage()).ResponseAsync;
75 | }
76 |
77 | await Task.WhenAll(tasks);
78 | stopwatch.Stop();
79 | _testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
80 | }
81 |
82 | [Theory(Timeout = Timeout)]
83 | [ClassData(typeof(MultiChannelWithAspNetClassData))]
84 | public void UnarySequentialCallsPerformance(ChannelContextFactory factory)
85 | {
86 | using var ctx = factory.Create();
87 | var stopwatch = Stopwatch.StartNew();
88 | for (int i = 0; i < 1_000; i++)
89 | {
90 | ctx.Client.SimpleUnary(new RequestMessage());
91 | }
92 |
93 | stopwatch.Stop();
94 | _testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
95 | }
96 |
97 | [Theory(Timeout = Timeout)]
98 | [ClassData(typeof(MultiChannelWithAspNetClassData))]
99 | public async Task UnaryParallelCallsPerformance(ChannelContextFactory factory)
100 | {
101 | using var ctx = factory.Create();
102 | var stopwatch = Stopwatch.StartNew();
103 | var tasks = new Task[1_000];
104 | for (int i = 0; i < tasks.Length; i++)
105 | {
106 | tasks[i] = ctx.Client.SimpleUnaryAsync(new RequestMessage()).ResponseAsync;
107 | }
108 |
109 | await Task.WhenAll(tasks);
110 | stopwatch.Stop();
111 | _testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
112 | }
113 |
114 | [Theory(Timeout = Timeout)]
115 | [ClassData(typeof(MultiChannelWithAspNetClassData))]
116 | public void UnaryLargePayloadPerformance(ChannelContextFactory factory)
117 | {
118 | using var ctx = factory.Create();
119 | var bytes = new byte[100 * 1024 * 1024];
120 | var byteString = ByteString.CopyFrom(bytes);
121 | var stopwatch = Stopwatch.StartNew();
122 | ctx.Client.SimpleUnary(new RequestMessage { Binary = byteString });
123 | stopwatch.Stop();
124 | _testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
125 | }
126 |
127 | [Theory(Timeout = Timeout)]
128 | [ClassData(typeof(MultiChannelWithAspNetClassData))]
129 | public void ChannelColdStartPerformance(ChannelContextFactory factory)
130 | {
131 | // Note: This test needs to be run on its own for accurate cold start measurements.
132 | var stopwatch = Stopwatch.StartNew();
133 | using var ctx = factory.Create();
134 | ctx.Client.SimpleUnary(new RequestMessage());
135 | stopwatch.Stop();
136 | _testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
137 | }
138 |
139 | [Theory(Timeout = Timeout)]
140 | [ClassData(typeof(MultiChannelWithAspNetClassData))]
141 | public void ChannelWarmStartPerformance(ChannelContextFactory factory)
142 | {
143 | using var tempChannel = factory.Create();
144 | var stopwatch = Stopwatch.StartNew();
145 | using var ctx = factory.Create();
146 | ctx.Client.SimpleUnary(new RequestMessage());
147 | stopwatch.Stop();
148 | _testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
149 | }
150 | }
--------------------------------------------------------------------------------
/GrpcDotNetNamedPipes.PerfTests/Helpers/AspNetHttpContextFactory.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #if NET6_0_OR_GREATER
18 | using System.Net.Http;
19 | using Grpc.Net.Client;
20 | using Microsoft.AspNetCore.Builder;
21 | using Microsoft.AspNetCore.Hosting;
22 | using Microsoft.AspNetCore.Hosting.Server;
23 | using Microsoft.AspNetCore.Hosting.Server.Features;
24 | using Microsoft.AspNetCore.Server.Kestrel.Core;
25 | using Microsoft.Extensions.DependencyInjection;
26 | using Microsoft.Extensions.Hosting;
27 |
28 | namespace GrpcDotNetNamedPipes.PerfTests.Helpers;
29 |
30 | public class AspNetHttpContextFactory : ChannelContextFactory
31 | {
32 | private int _port;
33 |
34 | public override ChannelContext Create(ITestOutputHelper output = null)
35 | {
36 | var builder = WebApplication.CreateBuilder();
37 | builder.Services.AddGrpc(opts => opts.MaxReceiveMessageSize = int.MaxValue);
38 | builder.WebHost.UseUrls("https://127.0.0.1:0");
39 | builder.WebHost.ConfigureKestrel(opts =>
40 | {
41 | opts.Limits.MaxRequestBodySize = int.MaxValue;
42 | opts.ConfigureEndpointDefaults(c => c.Protocols = HttpProtocols.Http2);
43 | });
44 | var app = builder.Build();
45 | app.MapGrpcService();
46 | app.Start();
47 | var server = app.Services.GetRequiredService();
48 | var addressFeature = server.Features.Get();
49 | foreach (var address in addressFeature.Addresses)
50 | {
51 | _port = int.Parse(address.Split(":").Last());
52 | }
53 |
54 | return new ChannelContext
55 | {
56 | Impl = new TestServiceImpl(), // TODO: Match instance
57 | Client = CreateClient(output),
58 | OnDispose = () => app.StopAsync()
59 | };
60 | }
61 |
62 | public override TestService.TestServiceClient CreateClient(ITestOutputHelper output = null)
63 | {
64 | var httpHandler = new HttpClientHandler();
65 | httpHandler.ServerCertificateCustomValidationCallback =
66 | HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
67 | return new TestService.TestServiceClient(GrpcChannel.ForAddress($"https://127.0.0.1:{_port}",
68 | new GrpcChannelOptions { HttpHandler = httpHandler, MaxReceiveMessageSize = int.MaxValue }));
69 | }
70 |
71 | public override string ToString()
72 | {
73 | return "aspnet-http";
74 | }
75 | }
76 | #endif
--------------------------------------------------------------------------------
/GrpcDotNetNamedPipes.PerfTests/Helpers/AspNetPipeContextFactory.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #if NET8_0_OR_GREATER
18 | using System.Net.Http;
19 | using System.Security.Principal;
20 | using Grpc.Net.Client;
21 | using Microsoft.AspNetCore.Builder;
22 | using Microsoft.AspNetCore.Hosting;
23 | using Microsoft.AspNetCore.Server.Kestrel.Core;
24 | using Microsoft.Extensions.DependencyInjection;
25 | using Microsoft.Extensions.Hosting;
26 |
27 | namespace GrpcDotNetNamedPipes.PerfTests.Helpers;
28 |
29 | public class AspNetPipeContextFactory : ChannelContextFactory
30 | {
31 | private string _pipe;
32 |
33 | public override ChannelContext Create(ITestOutputHelper output = null)
34 | {
35 | _pipe = $"pipe/{Guid.NewGuid()}";
36 | var builder = WebApplication.CreateBuilder();
37 | builder.Services.AddGrpc(opts => opts.MaxReceiveMessageSize = int.MaxValue);
38 | builder.WebHost.UseUrls("https://127.0.0.1:0");
39 | builder.WebHost.ConfigureKestrel(opts =>
40 | {
41 | opts.Limits.MaxRequestBodySize = int.MaxValue;
42 | opts.ListenNamedPipe(_pipe, c => c.Protocols = HttpProtocols.Http2);
43 | });
44 | var app = builder.Build();
45 | app.MapGrpcService();
46 | app.Start();
47 |
48 | return new ChannelContext
49 | {
50 | Impl = new TestServiceImpl(), // TODO: Match instance
51 | Client = CreateClient(output),
52 | OnDispose = () => app.StopAsync()
53 | };
54 | }
55 |
56 | public override TestService.TestServiceClient CreateClient(ITestOutputHelper output = null)
57 | {
58 | var connectionFactory = new NamedPipesConnectionFactory(_pipe);
59 | var socketsHttpHandler = new SocketsHttpHandler
60 | {
61 | ConnectCallback = connectionFactory.ConnectAsync
62 | };
63 | return new TestService.TestServiceClient(GrpcChannel.ForAddress("http://localhost",
64 | new GrpcChannelOptions { HttpHandler = socketsHttpHandler, MaxReceiveMessageSize = int.MaxValue }));
65 | }
66 |
67 | public override string ToString()
68 | {
69 | return "aspnet-pipe";
70 | }
71 |
72 | private class NamedPipesConnectionFactory
73 | {
74 | private readonly string pipeName;
75 |
76 | public NamedPipesConnectionFactory(string pipeName)
77 | {
78 | this.pipeName = pipeName;
79 | }
80 |
81 | public async ValueTask ConnectAsync(SocketsHttpConnectionContext _,
82 | CancellationToken cancellationToken = default)
83 | {
84 | var clientStream = new NamedPipeClientStream(
85 | serverName: ".",
86 | pipeName: this.pipeName,
87 | direction: PipeDirection.InOut,
88 | options: PipeOptions.WriteThrough | PipeOptions.Asynchronous,
89 | impersonationLevel: TokenImpersonationLevel.Anonymous);
90 |
91 | try
92 | {
93 | await clientStream.ConnectAsync(cancellationToken).ConfigureAwait(false);
94 | return clientStream;
95 | }
96 | catch
97 | {
98 | clientStream.Dispose();
99 | throw;
100 | }
101 | }
102 | }
103 | }
104 | #endif
--------------------------------------------------------------------------------
/GrpcDotNetNamedPipes.PerfTests/Helpers/AspNetUdsContextFactory.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #if NET6_0_OR_GREATER
18 | using System.Net;
19 | using System.Net.Http;
20 | using System.Net.Sockets;
21 | using Grpc.Net.Client;
22 | using Microsoft.AspNetCore.Builder;
23 | using Microsoft.AspNetCore.Hosting;
24 | using Microsoft.AspNetCore.Server.Kestrel.Core;
25 | using Microsoft.Extensions.DependencyInjection;
26 | using Microsoft.Extensions.Hosting;
27 |
28 | namespace GrpcDotNetNamedPipes.PerfTests.Helpers;
29 |
30 | public class AspNetUdsContextFactory : ChannelContextFactory
31 | {
32 | private string _path;
33 |
34 | public override ChannelContext Create(ITestOutputHelper output = null)
35 | {
36 | _path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
37 | var builder = WebApplication.CreateBuilder();
38 | builder.Services.AddGrpc(opts => opts.MaxReceiveMessageSize = int.MaxValue);
39 | builder.WebHost.UseUrls("https://127.0.0.1:0");
40 | builder.WebHost.ConfigureKestrel(opts =>
41 | {
42 | opts.Limits.MaxRequestBodySize = int.MaxValue;
43 | opts.ListenUnixSocket(_path, c => c.Protocols = HttpProtocols.Http2);
44 | });
45 | var app = builder.Build();
46 | app.MapGrpcService();
47 | app.Start();
48 |
49 | return new ChannelContext
50 | {
51 | Impl = new TestServiceImpl(), // TODO: Match instance
52 | Client = CreateClient(output),
53 | OnDispose = () => app.StopAsync()
54 | };
55 | }
56 |
57 | public override TestService.TestServiceClient CreateClient(ITestOutputHelper output = null)
58 | {
59 | var udsEndPoint = new UnixDomainSocketEndPoint(_path);
60 | var connectionFactory = new UnixDomainSocketsConnectionFactory(udsEndPoint);
61 | var socketsHttpHandler = new SocketsHttpHandler
62 | {
63 | ConnectCallback = connectionFactory.ConnectAsync
64 | };
65 | return new TestService.TestServiceClient(GrpcChannel.ForAddress("http://localhost",
66 | new GrpcChannelOptions { HttpHandler = socketsHttpHandler, MaxReceiveMessageSize = int.MaxValue }));
67 | }
68 |
69 | public override string ToString()
70 | {
71 | return "aspnet-uds";
72 | }
73 |
74 | private class UnixDomainSocketsConnectionFactory
75 | {
76 | private readonly EndPoint endPoint;
77 |
78 | public UnixDomainSocketsConnectionFactory(EndPoint endPoint)
79 | {
80 | this.endPoint = endPoint;
81 | }
82 |
83 | public async ValueTask ConnectAsync(SocketsHttpConnectionContext _,
84 | CancellationToken cancellationToken = default)
85 | {
86 | var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
87 |
88 | try
89 | {
90 | await socket.ConnectAsync(this.endPoint, cancellationToken).ConfigureAwait(false);
91 | return new NetworkStream(socket, true);
92 | }
93 | catch
94 | {
95 | socket.Dispose();
96 | throw;
97 | }
98 | }
99 | }
100 | }
101 | #endif
--------------------------------------------------------------------------------
/GrpcDotNetNamedPipes.PerfTests/Helpers/MultiChannelClassData.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | using System.Collections;
18 | using System.Runtime.InteropServices;
19 |
20 | namespace GrpcDotNetNamedPipes.PerfTests.Helpers;
21 |
22 | public class MultiChannelWithAspNetClassData : IEnumerable