From fb387ed03d9e859a48bf49a3d86643d1b687aece Mon Sep 17 00:00:00 2001 From: moozzyk Date: Thu, 6 Oct 2016 10:43:12 -0700 Subject: [PATCH] Decoupling formatters from endpoints Moving formatters out from Sockets --- .../SocketsSample/EndPoints/ChatEndPoint.cs | 1 - .../SocketsSample/EndPoints/HubEndpoint.cs | 5 +- .../SocketsSample/EndPoints/RpcEndpoint.cs | 14 ++--- samples/SocketsSample/FormatterExtensions.cs | 36 +++++++++++++ samples/SocketsSample/IFormatter.cs | 12 +++++ samples/SocketsSample/SocketFormatters.cs | 43 +++++++++++++++ samples/SocketsSample/Startup.cs | 23 ++++---- samples/SocketsSample/wwwroot/hubs.html | 11 ++-- .../EndPointFormatters.cs | 40 -------------- .../HttpDispatcherAppBuilderExtensions.cs | 52 +------------------ .../SocketFormatters.cs | 33 ------------ 11 files changed, 118 insertions(+), 152 deletions(-) create mode 100644 samples/SocketsSample/FormatterExtensions.cs create mode 100644 samples/SocketsSample/IFormatter.cs create mode 100644 samples/SocketsSample/SocketFormatters.cs delete mode 100644 src/Microsoft.AspNetCore.Sockets/EndPointFormatters.cs delete mode 100644 src/Microsoft.AspNetCore.Sockets/SocketFormatters.cs diff --git a/samples/SocketsSample/EndPoints/ChatEndPoint.cs b/samples/SocketsSample/EndPoints/ChatEndPoint.cs index 2360a7698e..f75545d839 100644 --- a/samples/SocketsSample/EndPoints/ChatEndPoint.cs +++ b/samples/SocketsSample/EndPoints/ChatEndPoint.cs @@ -12,7 +12,6 @@ namespace SocketsSample { public ChatEndPoint() { - Console.Write(0); } public override async Task OnConnected(Connection connection) diff --git a/samples/SocketsSample/EndPoints/HubEndpoint.cs b/samples/SocketsSample/EndPoints/HubEndpoint.cs index 640e5fab2c..fe0abc9044 100644 --- a/samples/SocketsSample/EndPoints/HubEndpoint.cs +++ b/samples/SocketsSample/EndPoints/HubEndpoint.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Channels; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using SocketsSample.Hubs; @@ -78,7 +79,9 @@ namespace SocketsSample foreach (var connection in _endPoint.Connections) { // TODO: separate serialization from writing to stream - var formatter = _endPoint.GetFormatter((string)connection.Metadata["formatType"]); + var formatter = _endPoint._serviceProvider.GetRequiredService() + .GetFormatter((string)connection.Metadata["formatType"]); + tasks.Add(formatter.WriteAsync(message, connection.Channel.GetStream())); } diff --git a/samples/SocketsSample/EndPoints/RpcEndpoint.cs b/samples/SocketsSample/EndPoints/RpcEndpoint.cs index de7610c9eb..18b8bc8d16 100644 --- a/samples/SocketsSample/EndPoints/RpcEndpoint.cs +++ b/samples/SocketsSample/EndPoints/RpcEndpoint.cs @@ -36,18 +36,13 @@ namespace SocketsSample RegisterRPCEndPoint(typeof(Echo)); } - protected IFormatter GetFormatter(string format) - { - return _serviceProvider - .GetRequiredService().GetEndPointFormatters(GetType()) - .GetFormatter(format); - } - public override async Task OnConnected(Connection connection) { // TODO: Dispatch from the caller await Task.Yield(); - var formatter = GetFormatter((string)connection.Metadata["formatType"]); + + var formatter = _serviceProvider.GetRequiredService() + .GetFormatter((string)connection.Metadata["formatType"]); while (true) { @@ -98,7 +93,8 @@ namespace SocketsSample }; } - var resultFormatter = GetFormatter((string)connection.Metadata["formatType"]); + var resultFormatter = _serviceProvider.GetRequiredService(). + GetFormatter((string)connection.Metadata["formatType"]); await resultFormatter.WriteAsync(result, connection.Channel.GetStream()); } } diff --git a/samples/SocketsSample/FormatterExtensions.cs b/samples/SocketsSample/FormatterExtensions.cs new file mode 100644 index 0000000000..687fee2ffe --- /dev/null +++ b/samples/SocketsSample/FormatterExtensions.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Sockets; +using Microsoft.Extensions.DependencyInjection; + +namespace SocketsSample +{ + public static class FormatterExtensions + { + public static IApplicationBuilder UseFormatters(this IApplicationBuilder app, Action registerFormatters) + { + var formatters = app.ApplicationServices.GetRequiredService(); + registerFormatters(new FormatterBuilder(formatters)); + return app; + } + } + + public class FormatterBuilder + { + private SocketFormatters _socketFormatters; + + public FormatterBuilder(SocketFormatters socketFormatters) + { + _socketFormatters = socketFormatters; + } + + public void MapFormatter(string format) + where TFormatterType : IFormatter + { + _socketFormatters.RegisterFormatter(format); + } + } +} diff --git a/samples/SocketsSample/IFormatter.cs b/samples/SocketsSample/IFormatter.cs new file mode 100644 index 0000000000..78eb11b4a2 --- /dev/null +++ b/samples/SocketsSample/IFormatter.cs @@ -0,0 +1,12 @@ +using System.IO; +using System.Threading.Tasks; + +namespace SocketsSample +{ + // TODO: Is this name too generic? + public interface IFormatter + { + Task ReadAsync(Stream stream); + Task WriteAsync(T value, Stream stream); + } +} diff --git a/samples/SocketsSample/SocketFormatters.cs b/samples/SocketsSample/SocketFormatters.cs new file mode 100644 index 0000000000..08175fd8c8 --- /dev/null +++ b/samples/SocketsSample/SocketFormatters.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Sockets; +using Microsoft.Extensions.DependencyInjection; + +namespace SocketsSample +{ + public class SocketFormatters + { + private IServiceProvider _serviceProvider; + private Dictionary> _formatters = new Dictionary>(); + + public SocketFormatters(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public void RegisterFormatter(string format) + where TFormatterType : IFormatter + { + Dictionary formatFormatters; + if (!_formatters.TryGetValue(format, out formatFormatters)) + { + formatFormatters = _formatters[format] = new Dictionary(); + } + + formatFormatters[typeof(T)] = typeof(TFormatterType); + } + + public IFormatter GetFormatter(string format) + { + Dictionary formatters; + Type targetFormatterType; + + if (_formatters.TryGetValue(format, out formatters) && formatters.TryGetValue(typeof(T), out targetFormatterType)) + { + return (IFormatter)_serviceProvider.GetRequiredService(targetFormatterType); + } + + throw new InvalidOperationException($"No formatter register for format '{format}' and type '{typeof(T).GetType().FullName}'"); + } + } +} \ No newline at end of file diff --git a/samples/SocketsSample/Startup.cs b/samples/SocketsSample/Startup.cs index 6e46ae8e61..4695f136be 100644 --- a/samples/SocketsSample/Startup.cs +++ b/samples/SocketsSample/Startup.cs @@ -39,17 +39,20 @@ namespace SocketsSample app.UseDeveloperExceptionPage(); } - app.UseSockets(endpoints => - { - endpoints.Configure() - .MapRoute("/hubs") - .MapFormatter("line") - .MapFormatter("line") - .MapFormatter>("json") - .MapFormatter>("json"); - endpoints.Configure().MapRoute("/chat"); - endpoints.Configure().MapRoute("/jsonrpc"); + app.UseSockets(routes => + { + routes.MapSocketEndpoint("/hubs"); + routes.MapSocketEndpoint("/chat"); + routes.MapSocketEndpoint("/jsonrpc"); + }); + + app.UseFormatters(formatters=> + { + formatters.MapFormatter("line"); + formatters.MapFormatter("line"); + formatters.MapFormatter>("json"); + formatters.MapFormatter>("json"); }); } } diff --git a/samples/SocketsSample/wwwroot/hubs.html b/samples/SocketsSample/wwwroot/hubs.html index 9eb2f83a47..0f4eeb5ea6 100644 --- a/samples/SocketsSample/wwwroot/hubs.html +++ b/samples/SocketsSample/wwwroot/hubs.html @@ -81,13 +81,13 @@ document.addEventListener('DOMContentLoaded', () => { let connectButton = document.getElementById('connect'); connectButton.addEventListener('click', () => { - run(document.getElementById('format').value, document.getElementById('formatType').value); + run(document.getElementById('formatType').value); connectButton.disabled = true; }); }); - function run(format, formatType) { - var conn = new hubConnection(`ws://${document.location.host}/hubs/ws?format=${format}&formatType=${formatType}`); + function run(formatType) { + var conn = new hubConnection(`ws://${document.location.host}/hubs/ws?formatType=${formatType}`); conn.on('Send', function (message) { var child = document.createElement('li'); @@ -114,11 +114,6 @@

WebSockets

- -