Skip to content

Commit b36ea05

Browse files
committed
Big refactoring
- File scoped namepaces, collection expressions, target type new, top level statements, IHostApplicationBuilder
1 parent d101494 commit b36ea05

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1946
-2281
lines changed
Lines changed: 36 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,55 @@
1-
using System;
21
using System.Net;
32
using System.Security.Cryptography.X509Certificates;
4-
using System.Threading.Tasks;
53
using Bedrock.Framework;
64
using Microsoft.AspNetCore.Connections;
75
using Microsoft.AspNetCore.SignalR;
86
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.Hosting;
98
using Microsoft.Extensions.Logging;
9+
using ServerApplication;
1010

11-
namespace ServerApplication
12-
{
13-
public partial class Program
14-
{
15-
public static async Task Main(string[] args)
16-
{
17-
// Manual wire up of the server
18-
var services = new ServiceCollection();
19-
services.AddLogging(builder =>
20-
{
21-
builder.SetMinimumLevel(LogLevel.Debug);
22-
builder.AddConsole();
23-
});
24-
25-
services.AddSignalR();
26-
27-
var serviceProvider = services.BuildServiceProvider();
28-
29-
var server = new ServerBuilder(serviceProvider)
30-
.UseSockets(sockets =>
31-
{
32-
// Echo server
33-
sockets.ListenLocalhost(5000,
34-
builder => builder.UseConnectionLogging().UseConnectionHandler<EchoServerApplication>());
11+
var builder = Host.CreateApplicationBuilder();
3512

36-
// HTTP/1.1 server
37-
sockets.Listen(IPAddress.Loopback, 5001,
38-
builder => builder.UseConnectionLogging().UseConnectionHandler<HttpApplication>());
13+
builder.Logging.SetMinimumLevel(LogLevel.Debug);
3914

40-
// SignalR Hub
41-
sockets.Listen(IPAddress.Loopback, 5002,
42-
builder => builder.UseConnectionLogging().UseHub<Chat>());
15+
builder.Services.AddSignalR();
4316

44-
// MQTT application
45-
sockets.Listen(IPAddress.Loopback, 5003,
46-
builder => builder.UseConnectionLogging().UseConnectionHandler<MqttApplication>());
47-
48-
// Echo Server with TLS
49-
sockets.Listen(IPAddress.Loopback, 5004,
50-
builder => builder.UseServerTls(options =>
51-
{
52-
options.LocalCertificate = X509CertificateLoader.LoadPkcs12FromFile("testcert.pfx", "testcert");
53-
54-
// NOTE: Do not do this in a production environment
55-
options.AllowAnyRemoteCertificate();
56-
})
57-
.UseConnectionLogging().UseConnectionHandler<EchoServerApplication>());
17+
builder.ConfigureServer(server =>
18+
{
19+
server.UseSockets(sockets =>
20+
{
21+
// Echo server
22+
sockets.ListenLocalhost(5000,
23+
builder => builder.UseConnectionLogging().UseConnectionHandler<EchoServerApplication>());
5824

59-
sockets.Listen(IPAddress.Loopback, 5005,
60-
builder => builder.UseConnectionLogging().UseConnectionHandler<MyCustomProtocol>());
61-
})
62-
.Build();
25+
// HTTP/1.1 server
26+
sockets.Listen(IPAddress.Loopback, 5001,
27+
builder => builder.UseConnectionLogging().UseConnectionHandler<HttpApplication>());
6328

64-
var logger = serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<Program>();
29+
// SignalR Hub
30+
sockets.Listen(IPAddress.Loopback, 5002,
31+
builder => builder.UseConnectionLogging().UseHub<Chat>());
6532

66-
await server.StartAsync();
33+
// MQTT application
34+
sockets.Listen(IPAddress.Loopback, 5003,
35+
builder => builder.UseConnectionLogging().UseConnectionHandler<MqttApplication>());
6736

68-
foreach (var ep in server.EndPoints)
37+
// Echo Server with TLS
38+
sockets.Listen(IPAddress.Loopback, 5004,
39+
builder => builder.UseServerTls(options =>
6940
{
70-
logger.LogInformation("Listening on {EndPoint}", ep);
71-
}
41+
options.LocalCertificate = X509CertificateLoader.LoadPkcs12FromFile("testcert.pfx", "testcert");
7242

73-
var tcs = new TaskCompletionSource<object>();
74-
Console.CancelKeyPress += (sender, e) =>
75-
{
76-
tcs.TrySetResult(null);
77-
e.Cancel = true;
78-
};
43+
// NOTE: Do not do this in a production environment
44+
options.AllowAnyRemoteCertificate();
45+
})
46+
.UseConnectionLogging().UseConnectionHandler<EchoServerApplication>());
47+
48+
sockets.Listen(IPAddress.Loopback, 5005,
49+
builder => builder.UseConnectionLogging().UseConnectionHandler<MyCustomProtocol>());
50+
});
51+
});
7952

80-
await tcs.Task;
53+
var host = builder.Build();
8154

82-
await server.StopAsync();
83-
}
84-
}
85-
}
55+
host.Run();

src/Bedrock.Framework/Client/Client.cs

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,23 @@
33
using System.Threading.Tasks;
44
using Microsoft.AspNetCore.Connections;
55

6-
namespace Bedrock.Framework
6+
namespace Bedrock.Framework;
7+
8+
public class Client(IConnectionFactory connectionFactory, ConnectionDelegate application) : IConnectionFactory
79
{
8-
public class Client : IConnectionFactory
10+
public async ValueTask<ConnectionContext> ConnectAsync(EndPoint endpoint, CancellationToken cancellationToken = default)
911
{
10-
private readonly IConnectionFactory _connectionFactory;
11-
private readonly ConnectionDelegate _application;
12-
13-
public Client(IConnectionFactory connectionFactory, ConnectionDelegate application)
14-
{
15-
_connectionFactory = connectionFactory;
16-
_application = application;
17-
}
18-
19-
public async ValueTask<ConnectionContext> ConnectAsync(EndPoint endpoint, CancellationToken cancellationToken = default)
20-
{
21-
var connection = await _connectionFactory.ConnectAsync(endpoint, cancellationToken).ConfigureAwait(false);
12+
var connection = await connectionFactory.ConnectAsync(endpoint, cancellationToken).ConfigureAwait(false);
2213

23-
// Since nothing is being returned from this middleware, we need to wait for the last middleware to run
24-
// until we yield this call. Stash a tcs in the items bag that allows this code to get notified
25-
// when the middleware ran
26-
var connectionContextWithDelegate = new ConnectionContextWithDelegate(connection, _application);
14+
// Since nothing is being returned from this middleware, we need to wait for the last middleware to run
15+
// until we yield this call. Stash a tcs in the items bag that allows this code to get notified
16+
// when the middleware ran
17+
var connectionContextWithDelegate = new ConnectionContextWithDelegate(connection, application);
2718

28-
// Execute the middleware pipeline
29-
connectionContextWithDelegate.Start();
19+
// Execute the middleware pipeline
20+
connectionContextWithDelegate.Start();
3021

31-
// Wait for it the most inner middleware to run
32-
return await connectionContextWithDelegate.Initialized.Task.ConfigureAwait(false);
33-
}
22+
// Wait for it the most inner middleware to run
23+
return await connectionContextWithDelegate.Initialized.Task.ConfigureAwait(false);
3424
}
3525
}

src/Bedrock.Framework/Client/ClientBuilder.cs

Lines changed: 64 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -5,92 +5,91 @@
55
using Bedrock.Framework.Infrastructure;
66
using Microsoft.AspNetCore.Connections;
77

8-
namespace Bedrock.Framework
8+
namespace Bedrock.Framework;
9+
10+
public partial class ClientBuilder : IConnectionBuilder
911
{
10-
public partial class ClientBuilder : IConnectionBuilder
11-
{
12-
private readonly ConnectionBuilder _connectionBuilder;
12+
private readonly ConnectionBuilder _connectionBuilder;
1313

14-
public ClientBuilder() : this(EmptyServiceProvider.Instance)
15-
{
14+
public ClientBuilder() : this(EmptyServiceProvider.Instance)
15+
{
1616

17-
}
17+
}
1818

19-
public ClientBuilder(IServiceProvider serviceProvider)
20-
{
21-
_connectionBuilder = new ConnectionBuilder(serviceProvider);
22-
}
19+
public ClientBuilder(IServiceProvider serviceProvider)
20+
{
21+
_connectionBuilder = new ConnectionBuilder(serviceProvider);
22+
}
2323

24-
internal static object Key { get; } = new object();
24+
internal static object Key { get; } = new object();
2525

26-
private IConnectionFactory ConnectionFactory { get; set; } = new ThrowConnectionFactory();
26+
private IConnectionFactory ConnectionFactory { get; set; } = new ThrowConnectionFactory();
2727

28-
public IServiceProvider ApplicationServices => _connectionBuilder.ApplicationServices;
28+
public IServiceProvider ApplicationServices => _connectionBuilder.ApplicationServices;
2929

30-
public Client Build()
30+
public Client Build()
31+
{
32+
// Middleware currently a single linear execution flow without a return value.
33+
// We need to return the connection when it reaches the innermost middleware (D in this case)
34+
// Then we need to wait until dispose is called to unwind that pipeline.
35+
36+
// A ->
37+
// B ->
38+
// C ->
39+
// D
40+
// C <-
41+
// B <-
42+
// A <-
43+
44+
_connectionBuilder.Run(connection =>
3145
{
32-
// Middleware currently a single linear execution flow without a return value.
33-
// We need to return the connection when it reaches the innermost middleware (D in this case)
34-
// Then we need to wait until dispose is called to unwind that pipeline.
35-
36-
// A ->
37-
// B ->
38-
// C ->
39-
// D
40-
// C <-
41-
// B <-
42-
// A <-
43-
44-
_connectionBuilder.Run(connection =>
46+
if (connection is ConnectionContextWithDelegate connectionContextWithDelegate)
4547
{
46-
if (connection is ConnectionContextWithDelegate connectionContextWithDelegate)
47-
{
48-
connectionContextWithDelegate.Initialized.TrySetResult(connectionContextWithDelegate);
48+
connectionContextWithDelegate.Initialized.TrySetResult(connectionContextWithDelegate);
4949

5050

51-
// This task needs to stay around until the connection is disposed
52-
// only then can we unwind the middleware chain
53-
return connectionContextWithDelegate.ExecutionTask;
54-
}
51+
// This task needs to stay around until the connection is disposed
52+
// only then can we unwind the middleware chain
53+
return connectionContextWithDelegate.ExecutionTask;
54+
}
5555

56-
// REVIEW: Do we throw in this case? It's edgy but possible to call next with a differnt
57-
// connection delegate that originally given
58-
return Task.CompletedTask;
59-
});
56+
// REVIEW: Do we throw in this case? It's edgy but possible to call next with a differnt
57+
// connection delegate that originally given
58+
return Task.CompletedTask;
59+
});
6060

61-
var application = _connectionBuilder.Build();
61+
var application = _connectionBuilder.Build();
6262

63-
return new Client(ConnectionFactory, application);
64-
}
63+
return new Client(ConnectionFactory, application);
64+
}
6565

66-
public ClientBuilder UseConnectionFactory(IConnectionFactory connectionFactory)
67-
{
68-
ConnectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
69-
return this;
70-
}
66+
public ClientBuilder UseConnectionFactory(IConnectionFactory connectionFactory)
67+
{
68+
ConnectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
69+
return this;
70+
}
7171

72-
public ClientBuilder Use(Func<IConnectionFactory, IConnectionFactory> middleware)
73-
{
74-
ConnectionFactory = middleware(ConnectionFactory);
75-
return this;
76-
}
72+
public ClientBuilder Use(Func<IConnectionFactory, IConnectionFactory> middleware)
73+
{
74+
ConnectionFactory = middleware(ConnectionFactory);
75+
return this;
76+
}
7777

78-
public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
79-
{
80-
return _connectionBuilder.Use(middleware);
81-
}
78+
public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
79+
{
80+
return _connectionBuilder.Use(middleware);
81+
}
8282

83-
ConnectionDelegate IConnectionBuilder.Build()
84-
{
85-
return _connectionBuilder.Build();
86-
}
83+
ConnectionDelegate IConnectionBuilder.Build()
84+
{
85+
return _connectionBuilder.Build();
86+
}
8787

88-
private class ThrowConnectionFactory : IConnectionFactory
88+
private class ThrowConnectionFactory : IConnectionFactory
89+
{
90+
public ValueTask<ConnectionContext> ConnectAsync(EndPoint endpoint, CancellationToken cancellationToken = default)
8991
{
90-
public ValueTask<ConnectionContext> ConnectAsync(EndPoint endpoint, CancellationToken cancellationToken = default)
91-
{
92-
throw new InvalidOperationException("No transport configured. Set the ConnectionFactory property.");
93-
}
92+
throw new InvalidOperationException("No transport configured. Set the ConnectionFactory property.");
9493
}
9594
}
9695
}

src/Bedrock.Framework/Hosting/ServerHostedService.cs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,19 @@
33
using Microsoft.Extensions.Hosting;
44
using Microsoft.Extensions.Options;
55

6-
namespace Bedrock.Framework
7-
{
8-
public class ServerHostedService : IHostedService
9-
{
10-
private readonly Server _server;
6+
namespace Bedrock.Framework;
117

12-
public ServerHostedService(IOptions<ServerHostedServiceOptions> options)
13-
{
14-
_server = options.Value.ServerBuilder.Build();
15-
}
8+
public class ServerHostedService(IOptions<ServerHostedServiceOptions> options) : IHostedService
9+
{
10+
private readonly Server _server = options.Value.ServerBuilder.Build();
1611

17-
public Task StartAsync(CancellationToken cancellationToken)
18-
{
19-
return _server.StartAsync(cancellationToken);
20-
}
12+
public Task StartAsync(CancellationToken cancellationToken)
13+
{
14+
return _server.StartAsync(cancellationToken);
15+
}
2116

22-
public Task StopAsync(CancellationToken cancellationToken)
23-
{
24-
return _server.StopAsync(cancellationToken);
25-
}
17+
public Task StopAsync(CancellationToken cancellationToken)
18+
{
19+
return _server.StopAsync(cancellationToken);
2620
}
2721
}
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Text;
1+
namespace Bedrock.Framework;
42

5-
namespace Bedrock.Framework
3+
public class ServerHostedServiceOptions
64
{
7-
public class ServerHostedServiceOptions
8-
{
9-
public ServerBuilder ServerBuilder { get; set; }
10-
}
5+
public ServerBuilder ServerBuilder { get; set; }
116
}

0 commit comments

Comments
 (0)