diff --git a/.nuget/nuget.exe b/.nuget/nuget.exe new file mode 100644 index 00000000..94aada9c Binary files /dev/null and b/.nuget/nuget.exe differ diff --git a/src/Lime.Client.Windows/Lime.Client.Windows.csproj b/src/Lime.Client.Windows/Lime.Client.Windows.csproj index cdff6105..371979e9 100644 --- a/src/Lime.Client.Windows/Lime.Client.Windows.csproj +++ b/src/Lime.Client.Windows/Lime.Client.Windows.csproj @@ -111,8 +111,8 @@ ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll True - - ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll True diff --git a/src/Lime.Client.Windows/packages.config b/src/Lime.Client.Windows/packages.config index 74108f74..2f6cdb99 100644 --- a/src/Lime.Client.Windows/packages.config +++ b/src/Lime.Client.Windows/packages.config @@ -10,7 +10,7 @@ - + diff --git a/src/Lime.Protocol/Listeners/BufferedChannelListener.cs b/src/Lime.Protocol/Listeners/BufferedChannelListener.cs index 42625091..b1bdf7d7 100644 --- a/src/Lime.Protocol/Listeners/BufferedChannelListener.cs +++ b/src/Lime.Protocol/Listeners/BufferedChannelListener.cs @@ -50,6 +50,8 @@ public void Start(IEstablishedReceiverChannel channel) { throw new InvalidOperationException("The listener is already active"); } + // Dispose the previous cancelled CTS before creating a new one. + _cts?.Dispose(); _cts = new CancellationTokenSource(); MessageListenerTask = CreateListenerTask( @@ -81,7 +83,7 @@ public void Stop() throw new InvalidOperationException("The listener is not active"); } - _cts.Cancel(); + _cts.Cancel(); MessageBuffer.Writer.TryComplete(); NotificationBuffer.Writer.TryComplete(); CommandBuffer.Writer.TryComplete(); diff --git a/src/Lime.Protocol/Network/ChannelBase.cs b/src/Lime.Protocol/Network/ChannelBase.cs index 44e2bfba..11b6edaa 100644 --- a/src/Lime.Protocol/Network/ChannelBase.cs +++ b/src/Lime.Protocol/Network/ChannelBase.cs @@ -378,6 +378,7 @@ protected virtual void Dispose(bool disposing) { if (disposing) { + Transport.Closing -= Transport_Closing; _receiverChannel.Dispose(); _senderChannel.Dispose(); Transport.DisposeIfDisposable(); diff --git a/src/Lime.Protocol/Network/EnvelopePipe.cs b/src/Lime.Protocol/Network/EnvelopePipe.cs index fd6c32a1..e0034076 100644 --- a/src/Lime.Protocol/Network/EnvelopePipe.cs +++ b/src/Lime.Protocol/Network/EnvelopePipe.cs @@ -193,6 +193,7 @@ public async Task ReceiveAsync(CancellationToken cancellationToken) public void Dispose() { _pipeCts.Dispose(); + _semaphore.Dispose(); } private Task TraceAsync(string data, DataOperation operation) diff --git a/src/Lime.Protocol/Network/SynchronizedTransportDecorator.cs b/src/Lime.Protocol/Network/SynchronizedTransportDecorator.cs index 4819189d..48418b22 100644 --- a/src/Lime.Protocol/Network/SynchronizedTransportDecorator.cs +++ b/src/Lime.Protocol/Network/SynchronizedTransportDecorator.cs @@ -8,7 +8,7 @@ namespace Lime.Protocol.Network /// /// Defines a decorator for that synchronizes concurrent and calls. /// - public sealed class SynchronizedTransportDecorator : ITransport + public sealed class SynchronizedTransportDecorator : ITransport, IDisposable { private readonly ITransport _transport; private readonly SemaphoreSlim _sendSemaphore; @@ -105,5 +105,11 @@ public event EventHandler Closed add => _transport.Closed += value; remove => _transport.Closed -= value; } + + public void Dispose() + { + _sendSemaphore.Dispose(); + _receiveSemaphore.Dispose(); + } } } \ No newline at end of file diff --git a/src/Lime.Protocol/Network/TransportBase.cs b/src/Lime.Protocol/Network/TransportBase.cs index 960dd3bf..65f8c1d2 100644 --- a/src/Lime.Protocol/Network/TransportBase.cs +++ b/src/Lime.Protocol/Network/TransportBase.cs @@ -9,7 +9,7 @@ namespace Lime.Protocol.Network /// /// Base class for transport implementation. /// - public abstract class TransportBase : ITransport + public abstract class TransportBase : ITransport, IDisposable { private bool _isOpen; // TODO: Merge this logic with IsConnected private bool _closingInvoked; @@ -239,5 +239,26 @@ protected virtual void OnClosed() Closed.RaiseEvent(this, EventArgs.Empty); } } + + /// + /// Releases resources used by this transport instance. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases managed and - optionally - unmanaged resources. + /// + /// true to release managed resources. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _openCloseSemaphore.Dispose(); + } + } } } diff --git a/src/Lime.Transport.AspNetCore/Transport/HttpContextChannel.cs b/src/Lime.Transport.AspNetCore/Transport/HttpContextChannel.cs index d3d52117..a3620e73 100644 --- a/src/Lime.Transport.AspNetCore/Transport/HttpContextChannel.cs +++ b/src/Lime.Transport.AspNetCore/Transport/HttpContextChannel.cs @@ -14,7 +14,7 @@ namespace Lime.Transport.AspNetCore.Transport /// /// Emulates a channel using the HttpContext to allow the application sending a envelope in the HTTP response. /// - internal sealed class HttpContextChannel : ISenderChannel + internal sealed class HttpContextChannel : ISenderChannel, IDisposable { private readonly HttpContext _context; private readonly IEnvelopeSerializer _envelopeSerializer; @@ -98,5 +98,10 @@ private void EnsureNotSent() throw new NotSupportedException("Only one envelope can be sent per request on HTTP transport"); } } + + public void Dispose() + { + _sendSemaphore.Dispose(); + } } } \ No newline at end of file diff --git a/src/Lime.Transport.Redis/RedisTransport.cs b/src/Lime.Transport.Redis/RedisTransport.cs index f45f0522..ad155c35 100644 --- a/src/Lime.Transport.Redis/RedisTransport.cs +++ b/src/Lime.Transport.Redis/RedisTransport.cs @@ -268,6 +268,8 @@ protected virtual void Dispose(bool disposing) { _connectionMultiplexer.Dispose(); } + _semaphore.Dispose(); + base.Dispose(disposing); } } diff --git a/src/Lime.Transport.Redis/RedisTransportListener.cs b/src/Lime.Transport.Redis/RedisTransportListener.cs index 0bb6273e..00b040dc 100644 --- a/src/Lime.Transport.Redis/RedisTransportListener.cs +++ b/src/Lime.Transport.Redis/RedisTransportListener.cs @@ -158,6 +158,7 @@ private void HandleReceivedData(RedisChannel channel, RedisValue value) public void Dispose() { _connectionMultiplexer?.Dispose(); + _semaphore.Dispose(); } } } diff --git a/src/Lime.Transport.Tcp/PipeTcpTransport.cs b/src/Lime.Transport.Tcp/PipeTcpTransport.cs index c0342de4..62edb263 100644 --- a/src/Lime.Transport.Tcp/PipeTcpTransport.cs +++ b/src/Lime.Transport.Tcp/PipeTcpTransport.cs @@ -467,6 +467,7 @@ protected override Task PerformCloseAsync(CancellationToken cancellationToken) public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) @@ -478,6 +479,7 @@ protected virtual void Dispose(bool disposing) _optionsSemaphore.Dispose(); _stream?.Dispose(); _envelopePipe.Dispose(); + base.Dispose(disposing); } _disposed = true; @@ -566,11 +568,11 @@ private bool ValidateClientCertificate( return sslPolicyErrors == SslPolicyErrors.None; } - private Task CloseWithTimeoutAsync() + private async Task CloseWithTimeoutAsync() { using (var cts = new CancellationTokenSource(CloseTimeout)) { - return CloseAsync(cts.Token); + await CloseAsync(cts.Token).ConfigureAwait(false); } } } diff --git a/src/Lime.Transport.Tcp/PipeTcpTransportListener.cs b/src/Lime.Transport.Tcp/PipeTcpTransportListener.cs index 77ec9ce1..b519f46f 100644 --- a/src/Lime.Transport.Tcp/PipeTcpTransportListener.cs +++ b/src/Lime.Transport.Tcp/PipeTcpTransportListener.cs @@ -14,7 +14,7 @@ namespace Lime.Transport.Tcp { - public class PipeTcpTransportListener : ITransportListener + public class PipeTcpTransportListener : ITransportListener, IDisposable { private readonly X509Certificate2 _serverCertificate; private readonly IEnvelopeSerializer _envelopeSerializer; @@ -181,5 +181,10 @@ public async Task StopAsync(CancellationToken cancellationToken) _semaphore.Release(); } } + + public void Dispose() + { + _semaphore.Dispose(); + } } } diff --git a/src/Lime.Transport.Tcp/TcpTransport.cs b/src/Lime.Transport.Tcp/TcpTransport.cs index b5ca6a2a..b227e33f 100644 --- a/src/Lime.Transport.Tcp/TcpTransport.cs +++ b/src/Lime.Transport.Tcp/TcpTransport.cs @@ -581,6 +581,7 @@ protected override Task PerformCloseAsync(CancellationToken cancellationToken) public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) @@ -592,6 +593,7 @@ protected virtual void Dispose(bool disposing) _optionsSemaphore.Dispose(); _stream?.Dispose(); _jsonBuffer.Dispose(); + base.Dispose(disposing); } _disposed = true; @@ -640,11 +642,11 @@ private bool ValidateClientCertificate( private bool CanRead => _stream != null && _stream.CanRead && _tcpClient.Connected; - private Task CloseWithTimeoutAsync() + private async Task CloseWithTimeoutAsync() { using (var cts = new CancellationTokenSource(CloseTimeout)) { - return CloseAsync(cts.Token); + await CloseAsync(cts.Token).ConfigureAwait(false); } } diff --git a/src/Lime.Transport.Tcp/TcpTransportListener.cs b/src/Lime.Transport.Tcp/TcpTransportListener.cs index 0c5989b8..de3f9ca1 100644 --- a/src/Lime.Transport.Tcp/TcpTransportListener.cs +++ b/src/Lime.Transport.Tcp/TcpTransportListener.cs @@ -14,7 +14,7 @@ namespace Lime.Transport.Tcp { - public class TcpTransportListener : ITransportListener + public class TcpTransportListener : ITransportListener, IDisposable { private readonly X509Certificate2 _serverCertificate; private readonly IEnvelopeSerializer _envelopeSerializer; @@ -189,5 +189,10 @@ public async Task StopAsync(CancellationToken cancellationToken) _semaphore.Release(); } } + + public void Dispose() + { + _semaphore.Dispose(); + } } } diff --git a/src/Lime.Transport.WebSocket/PipeWebSocketTransport.cs b/src/Lime.Transport.WebSocket/PipeWebSocketTransport.cs index aef7bf43..01798179 100644 --- a/src/Lime.Transport.WebSocket/PipeWebSocketTransport.cs +++ b/src/Lime.Transport.WebSocket/PipeWebSocketTransport.cs @@ -191,6 +191,7 @@ protected virtual void Dispose(bool disposing) WebSocket.Dispose(); _envelopePipe.Dispose(); _closeSemaphore.Dispose(); + base.Dispose(disposing); } } @@ -241,11 +242,11 @@ private void HandleCloseMessage(ValueWebSocketReceiveResult receiveResult) _closeStatus = WebSocketCloseStatus.NormalClosure; } - private Task CloseWithTimeoutAsync() + private async Task CloseWithTimeoutAsync() { using (var cts = new CancellationTokenSource(CloseTimeout)) { - return CloseAsync(cts.Token); + await CloseAsync(cts.Token).ConfigureAwait(false); } } } diff --git a/src/Lime.Transport.WebSocket/WebSocketTransport.cs b/src/Lime.Transport.WebSocket/WebSocketTransport.cs index 763242b3..10e681c2 100644 --- a/src/Lime.Transport.WebSocket/WebSocketTransport.cs +++ b/src/Lime.Transport.WebSocket/WebSocketTransport.cs @@ -327,6 +327,7 @@ protected virtual void Dispose(bool disposing) WebSocket.Dispose(); _closeSemaphore.Dispose(); _sendReceiveCts.Dispose(); + base.Dispose(disposing); } } @@ -343,11 +344,11 @@ private void HandleCloseMessage(WebSocketReceiveResult receiveResult) CloseStatus = WebSocketCloseStatus.NormalClosure; } - private Task CloseWithTimeoutAsync() + private async Task CloseWithTimeoutAsync() { using (var cts = new CancellationTokenSource(CloseTimeout)) { - return CloseAsync(cts.Token); + await CloseAsync(cts.Token).ConfigureAwait(false); } }