diff --git a/appveyor.yml b/appveyor.yml index be95b88d6f..35e5ab6828 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,4 @@ +image: Visual Studio 2015 init: - git config --global core.autocrlf true branches: @@ -10,4 +11,4 @@ build_script: - build.cmd --quiet verify clone_depth: 1 test: off -deploy: off \ No newline at end of file +deploy: off diff --git a/global.json b/global.json index ec96aa7abe..ba47784c29 100644 --- a/global.json +++ b/global.json @@ -6,4 +6,4 @@ "sdk": { "version": "1.0.0-preview2-1-003180" } -} \ No newline at end of file +} diff --git a/samples/ChatSample/Hubs/Chat.cs b/samples/ChatSample/Hubs/Chat.cs index be4786839c..1d8d9fa74c 100644 --- a/samples/ChatSample/Hubs/Chat.cs +++ b/samples/ChatSample/Hubs/Chat.cs @@ -18,7 +18,7 @@ namespace ChatSample.Hubs { if (!Context.User.Identity.IsAuthenticated) { - Context.Connection.Channel.Dispose(); + Context.Connection.Transport.Dispose(); } return Task.CompletedTask; diff --git a/samples/ChatSample/project.json b/samples/ChatSample/project.json index aa13fd24c6..12dfe09739 100644 --- a/samples/ChatSample/project.json +++ b/samples/ChatSample/project.json @@ -90,4 +90,4 @@ "prepublish": [ "bower install" ], "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] } -} \ No newline at end of file +} diff --git a/samples/SocialWeather/FormatterResolver.cs b/samples/SocialWeather/FormatterResolver.cs index d867a2cced..08cc1f6860 100644 --- a/samples/SocialWeather/FormatterResolver.cs +++ b/samples/SocialWeather/FormatterResolver.cs @@ -1,4 +1,6 @@ - +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; diff --git a/samples/SocialWeather/IStreamFormatter.cs b/samples/SocialWeather/IStreamFormatter.cs index 4d6f0e63ac..84be0cad06 100644 --- a/samples/SocialWeather/IStreamFormatter.cs +++ b/samples/SocialWeather/IStreamFormatter.cs @@ -1,4 +1,7 @@ -using System.IO; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; using System.Threading.Tasks; namespace SocialWeather diff --git a/samples/SocialWeather/Json/JSonStreamFormatter.cs b/samples/SocialWeather/Json/JSonStreamFormatter.cs index 67de693282..dbd590eca7 100644 --- a/samples/SocialWeather/Json/JSonStreamFormatter.cs +++ b/samples/SocialWeather/Json/JSonStreamFormatter.cs @@ -1,4 +1,7 @@ -using System.IO; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; using System.Threading.Tasks; using Newtonsoft.Json; diff --git a/samples/SocialWeather/PersistentConnectionLifeTimeManager.cs b/samples/SocialWeather/PersistentConnectionLifeTimeManager.cs index 73c7b8b9ba..e48fa16229 100644 --- a/samples/SocialWeather/PersistentConnectionLifeTimeManager.cs +++ b/samples/SocialWeather/PersistentConnectionLifeTimeManager.cs @@ -1,6 +1,10 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.Collections.Generic; using System.IO.Pipelines; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Sockets; @@ -9,19 +13,19 @@ namespace SocialWeather public class PersistentConnectionLifeTimeManager { private readonly FormatterResolver _formatterResolver; - private readonly ConnectionList _connectionList = new ConnectionList(); + private readonly ConnectionList _connectionList = new ConnectionList(); public PersistentConnectionLifeTimeManager(FormatterResolver formatterResolver) { _formatterResolver = formatterResolver; } - public void OnConnectedAsync(Connection connection) + public void OnConnectedAsync(StreamingConnection connection) { _connectionList.Add(connection); } - public void OnDisconnectedAsync(Connection connection) + public void OnDisconnectedAsync(StreamingConnection connection) { _connectionList.Remove(connection); } @@ -31,7 +35,7 @@ namespace SocialWeather foreach (var connection in _connectionList) { var formatter = _formatterResolver.GetFormatter(connection.Metadata.Get("formatType")); - await formatter.WriteAsync(data, connection.Channel.GetStream()); + await formatter.WriteAsync(data, connection.Transport.GetStream()); } } @@ -50,7 +54,7 @@ namespace SocialWeather throw new NotImplementedException(); } - public void AddGroupAsync(Connection connection, string groupName) + public void AddGroupAsync(StreamingConnection connection, string groupName) { var groups = connection.Metadata.GetOrAdd("groups", _ => new HashSet()); lock (groups) @@ -59,7 +63,7 @@ namespace SocialWeather } } - public void RemoveGroupAsync(Connection connection, string groupName) + public void RemoveGroupAsync(StreamingConnection connection, string groupName) { var groups = connection.Metadata.Get>("groups"); if (groups != null) diff --git a/samples/SocialWeather/Pipe/PipeWeatherStreamFormatter.cs b/samples/SocialWeather/Pipe/PipeWeatherStreamFormatter.cs index 72c9733a7d..274cccf310 100644 --- a/samples/SocialWeather/Pipe/PipeWeatherStreamFormatter.cs +++ b/samples/SocialWeather/Pipe/PipeWeatherStreamFormatter.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.IO; using System.Text; using System.Threading.Tasks; diff --git a/samples/SocialWeather/Program.cs b/samples/SocialWeather/Program.cs index b82ba17d02..e55cc6444c 100644 --- a/samples/SocialWeather/Program.cs +++ b/samples/SocialWeather/Program.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/samples/SocialWeather/Protobuf/ProtobufWeatherStreamFormatter.cs b/samples/SocialWeather/Protobuf/ProtobufWeatherStreamFormatter.cs index bbc224e5f1..4f1876a246 100644 --- a/samples/SocialWeather/Protobuf/ProtobufWeatherStreamFormatter.cs +++ b/samples/SocialWeather/Protobuf/ProtobufWeatherStreamFormatter.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.IO; using System.Threading.Tasks; using Google.Protobuf; diff --git a/samples/SocialWeather/SocialWeatherEndPoint.cs b/samples/SocialWeather/SocialWeatherEndPoint.cs index 019215e0a8..d838e66d66 100644 --- a/samples/SocialWeather/SocialWeatherEndPoint.cs +++ b/samples/SocialWeather/SocialWeatherEndPoint.cs @@ -1,11 +1,14 @@ -using System.IO.Pipelines; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO.Pipelines; using System.Threading.Tasks; using Microsoft.AspNetCore.Sockets; using Microsoft.Extensions.Logging; namespace SocialWeather { - public class SocialWeatherEndPoint : EndPoint + public class SocialWeatherEndPoint : StreamingEndPoint { private readonly PersistentConnectionLifeTimeManager _lifetimeManager; private readonly FormatterResolver _formatterResolver; @@ -19,16 +22,16 @@ namespace SocialWeather _logger = logger; } - public async override Task OnConnectedAsync(Connection connection) + public async override Task OnConnectedAsync(StreamingConnection connection) { _lifetimeManager.OnConnectedAsync(connection); await ProcessRequests(connection); _lifetimeManager.OnDisconnectedAsync(connection); } - public async Task ProcessRequests(Connection connection) + public async Task ProcessRequests(StreamingConnection connection) { - var stream = connection.Channel.GetStream(); + var stream = connection.Transport.GetStream(); var formatter = _formatterResolver.GetFormatter( connection.Metadata.Get("formatType")); diff --git a/samples/SocialWeather/Startup.cs b/samples/SocialWeather/Startup.cs index ee89f038e8..494b89bdcb 100644 --- a/samples/SocialWeather/Startup.cs +++ b/samples/SocialWeather/Startup.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Builder; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/samples/SocialWeather/WeatherReport.cs b/samples/SocialWeather/WeatherReport.cs index 0963465183..9a31502262 100644 --- a/samples/SocialWeather/WeatherReport.cs +++ b/samples/SocialWeather/WeatherReport.cs @@ -1,4 +1,7 @@ -using Newtonsoft.Json; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace SocialWeather diff --git a/samples/SocialWeather/project.json b/samples/SocialWeather/project.json index d8c9070831..0489a1a09f 100644 --- a/samples/SocialWeather/project.json +++ b/samples/SocialWeather/project.json @@ -39,4 +39,4 @@ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] } -} \ No newline at end of file +} diff --git a/samples/SocketsSample/EndPoints/ChatEndPoint.cs b/samples/SocketsSample/EndPoints/ChatEndPoint.cs index 39853a309e..39117504f0 100644 --- a/samples/SocketsSample/EndPoints/ChatEndPoint.cs +++ b/samples/SocketsSample/EndPoints/ChatEndPoint.cs @@ -1,19 +1,21 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.IO.Pipelines; +using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Sockets; namespace SocketsSample { - public class ChatEndPoint : EndPoint + public class ChatEndPoint : StreamingEndPoint { - public ConnectionList Connections { get; } = new ConnectionList(); + public ConnectionList Connections { get; } = new ConnectionList(); - public override async Task OnConnectedAsync(Connection connection) + public override async Task OnConnectedAsync(StreamingConnection connection) { Connections.Add(connection); @@ -21,7 +23,7 @@ namespace SocketsSample while (true) { - var result = await connection.Channel.Input.ReadAsync(); + var result = await connection.Transport.Input.ReadAsync(); var input = result.Buffer; try { @@ -35,7 +37,7 @@ namespace SocketsSample } finally { - connection.Channel.Input.Advance(input.End); + connection.Transport.Input.Advance(input.End); } } @@ -55,7 +57,7 @@ namespace SocketsSample foreach (var c in Connections) { - tasks.Add(c.Channel.Output.WriteAsync(payload)); + tasks.Add(c.Transport.Output.WriteAsync(payload)); } return Task.WhenAll(tasks); diff --git a/samples/SocketsSample/EndPoints/MessagesEndPoint.cs b/samples/SocketsSample/EndPoints/MessagesEndPoint.cs new file mode 100644 index 0000000000..d0afa43d54 --- /dev/null +++ b/samples/SocketsSample/EndPoints/MessagesEndPoint.cs @@ -0,0 +1,68 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO.Pipelines; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading.Tasks.Channels; +using Microsoft.AspNetCore.Sockets; + +namespace SocketsSample.EndPoints +{ + public class MessagesEndPoint : MessagingEndPoint + { + public ConnectionList Connections { get; } = new ConnectionList(); + + public override async Task OnConnectedAsync(MessagingConnection connection) + { + Connections.Add(connection); + + await Broadcast($"{connection.ConnectionId} connected ({connection.Metadata["transport"]})"); + + try + { + while (true) + { + using (var message = await connection.Transport.Input.ReadAsync()) + { + // We can avoid the copy here but we'll deal with that later + await Broadcast(message.Payload.Buffer, message.MessageFormat, message.EndOfMessage); + } + } + } + catch (Exception ex) when (ex.GetType().IsNested && ex.GetType().DeclaringType == typeof(Channel)) + { + // Gross that we have to catch this this way. See https://github.com/dotnet/corefxlab/issues/1068 + } + finally + { + Connections.Remove(connection); + + await Broadcast($"{connection.ConnectionId} disconnected ({connection.Metadata["transport"]})"); + } + } + + private Task Broadcast(string text) + { + return Broadcast(ReadableBuffer.Create(Encoding.UTF8.GetBytes(text)), Format.Text, endOfMessage: true); + } + + private Task Broadcast(ReadableBuffer payload, Format format, bool endOfMessage) + { + var tasks = new List(Connections.Count); + + foreach (var c in Connections) + { + tasks.Add(c.Transport.Output.WriteAsync(new Message( + payload.Preserve(), + format, + endOfMessage))); + } + + return Task.WhenAll(tasks); + } + } +} diff --git a/samples/SocketsSample/Startup.cs b/samples/SocketsSample/Startup.cs index e93d81f04c..a71b54d8bd 100644 --- a/samples/SocketsSample/Startup.cs +++ b/samples/SocketsSample/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using SocketsSample.EndPoints; using SocketsSample.Hubs; using SocketsSample.Protobuf; @@ -29,6 +30,7 @@ namespace SocketsSample // .AddRedis(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); } @@ -52,6 +54,7 @@ namespace SocketsSample app.UseSockets(routes => { routes.MapEndpoint("/chat"); + routes.MapEndpoint("/msgs"); }); } } diff --git a/samples/SocketsSample/project.json b/samples/SocketsSample/project.json index a085ec8a72..0f3b14570b 100644 --- a/samples/SocketsSample/project.json +++ b/samples/SocketsSample/project.json @@ -1,10 +1,6 @@ { "dependencies": { "Microsoft.AspNetCore.SignalR.Redis": "1.0.0-*", - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - }, "Newtonsoft.Json": "9.0.1", "Microsoft.AspNetCore.Diagnostics": "1.2.0-*", "Microsoft.AspNetCore.StaticFiles": "1.2.0-*", @@ -18,8 +14,15 @@ }, "frameworks": { "netcoreapp1.1": { - "imports": "portable-net45+win8+wp8+wpa81" - } + "imports": "portable-net45+win8+wp8+wpa81", + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.2.0-*", + "type": "platform" + } + } + }, + "net46": {} }, "buildOptions": { "emitEntryPoint": true, @@ -45,4 +48,4 @@ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] } -} \ No newline at end of file +} diff --git a/samples/SocketsSample/wwwroot/index.html b/samples/SocketsSample/wwwroot/index.html index dc7f4b4460..bf8ed6f0cc 100644 --- a/samples/SocketsSample/wwwroot/index.html +++ b/samples/SocketsSample/wwwroot/index.html @@ -6,14 +6,21 @@

ASP.NET Sockets

+

Streaming

+

Messaging

+

ASP.NET SignalR

- \ No newline at end of file + diff --git a/samples/SocketsSample/wwwroot/polling.html b/samples/SocketsSample/wwwroot/polling.html index 797b28e120..eb3b83e65f 100644 --- a/samples/SocketsSample/wwwroot/polling.html +++ b/samples/SocketsSample/wwwroot/polling.html @@ -75,7 +75,8 @@ } document.addEventListener('DOMContentLoaded', () => { - var sock = new socket('/chat'); + var url = location.hash || '#/chat'; + var sock = new socket(url.substring(1)); sock.onopen = function () { console.log('Opened!'); @@ -105,4 +106,4 @@
    - \ No newline at end of file + diff --git a/samples/SocketsSample/wwwroot/sse.html b/samples/SocketsSample/wwwroot/sse.html index 0d2a97c767..4c983e19b8 100644 --- a/samples/SocketsSample/wwwroot/sse.html +++ b/samples/SocketsSample/wwwroot/sse.html @@ -74,7 +74,8 @@ document.addEventListener('DOMContentLoaded', () => { - var sock = new socket('/chat'); + var url = location.hash || '#/chat'; + var sock = new socket(url.substring(1)); sock.onopen = function () { console.log('Opened!'); @@ -105,4 +106,4 @@
      - \ No newline at end of file + diff --git a/samples/SocketsSample/wwwroot/ws.html b/samples/SocketsSample/wwwroot/ws.html index 77ce4c0bf1..0a534b6469 100644 --- a/samples/SocketsSample/wwwroot/ws.html +++ b/samples/SocketsSample/wwwroot/ws.html @@ -5,7 +5,8 @@