diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 08e8c3e75f..28ccd8602d 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -504,8 +504,8 @@ namespace MediaBrowser.Common.Kernel /// The container. protected virtual void RegisterExportedValues() { - ApplicationHost.Register(this); - ApplicationHost.Register(TaskManager); + ApplicationHost.RegisterSingleInstance(this); + ApplicationHost.RegisterSingleInstance(TaskManager); } /// diff --git a/MediaBrowser.Common/Kernel/IApplicationHost.cs b/MediaBrowser.Common/Kernel/IApplicationHost.cs index dccb65b2aa..fe2f00a126 100644 --- a/MediaBrowser.Common/Kernel/IApplicationHost.cs +++ b/MediaBrowser.Common/Kernel/IApplicationHost.cs @@ -56,8 +56,22 @@ namespace MediaBrowser.Common.Kernel /// /// /// The obj. - void Register(T obj) where T : class; + void RegisterSingleInstance(T obj) where T : class; + /// + /// Registers the single instance. + /// + /// + /// The func. + void RegisterSingleInstance(Func func) where T : class; + + /// + /// Registers the specified func. + /// + /// + /// The func. + void Register(Func func) where T : class; + /// /// Registers the specified service type. /// diff --git a/MediaBrowser.Common/Kernel/TcpManager.cs b/MediaBrowser.Common/Kernel/TcpManager.cs index 0b171c4929..9a998823f4 100644 --- a/MediaBrowser.Common/Kernel/TcpManager.cs +++ b/MediaBrowser.Common/Kernel/TcpManager.cs @@ -1,6 +1,4 @@ -using Alchemy; -using Alchemy.Classes; -using MediaBrowser.Common.Net; +using MediaBrowser.Common.Net; using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; @@ -28,20 +26,14 @@ namespace MediaBrowser.Common.Kernel /// This is the udp server used for server discovery by clients /// /// The UDP server. - private UdpServer UdpServer { get; set; } - - /// - /// Gets or sets the UDP listener. - /// - /// The UDP listener. - private IDisposable UdpListener { get; set; } + private IUdpServer UdpServer { get; set; } /// /// Both the Ui and server will have a built-in HttpServer. /// People will inevitably want remote control apps so it's needed in the Ui too. /// /// The HTTP server. - public HttpServer HttpServer { get; private set; } + private IHttpServer HttpServer { get; set; } /// /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it @@ -58,7 +50,7 @@ namespace MediaBrowser.Common.Kernel /// Gets or sets the external web socket server. /// /// The external web socket server. - private WebSocketServer ExternalWebSocketServer { get; set; } + private IWebSocketServer ExternalWebSocketServer { get; set; } /// /// The _logger @@ -69,46 +61,24 @@ namespace MediaBrowser.Common.Kernel /// The _network manager /// private readonly INetworkManager _networkManager; - + /// /// The _application host /// private readonly IApplicationHost _applicationHost; - - /// - /// The _supports native web socket - /// - private bool? _supportsNativeWebSocket; /// /// The _kernel /// private readonly IKernel _kernel; - + /// /// Gets a value indicating whether [supports web socket]. /// /// true if [supports web socket]; otherwise, false. internal bool SupportsNativeWebSocket { - get - { - if (!_supportsNativeWebSocket.HasValue) - { - try - { - new ClientWebSocket(); - - _supportsNativeWebSocket = true; - } - catch (PlatformNotSupportedException) - { - _supportsNativeWebSocket = false; - } - } - - return _supportsNativeWebSocket.Value; - } + get { return HttpServer != null && HttpServer.SupportsWebSockets; } } /// @@ -145,7 +115,7 @@ namespace MediaBrowser.Common.Kernel { throw new ArgumentNullException("logger"); } - + _logger = logger; _kernel = kernel; _applicationHost = applicationHost; @@ -178,26 +148,10 @@ namespace MediaBrowser.Common.Kernel DisposeExternalWebSocketServer(); - ExternalWebSocketServer = new WebSocketServer(_kernel.Configuration.LegacyWebSocketPortNumber, IPAddress.Any) - { - OnConnected = OnAlchemyWebSocketClientConnected, - TimeOut = TimeSpan.FromMinutes(60) - }; + ExternalWebSocketServer = _applicationHost.Resolve(); - ExternalWebSocketServer.Start(); - - _logger.Info("Alchemy Web Socket Server started"); - } - - /// - /// Called when [alchemy web socket client connected]. - /// - /// The context. - private void OnAlchemyWebSocketClientConnected(UserContext context) - { - var connection = new WebSocketConnection(new AlchemyWebSocket(context, _logger), context.ClientAddress, ProcessWebSocketMessageReceived, _logger); - - _webSocketConnections.Add(connection); + ExternalWebSocketServer.Start(_kernel.Configuration.LegacyWebSocketPortNumber); + ExternalWebSocketServer.WebSocketConnected += HttpServer_WebSocketConnected; } /// @@ -218,7 +172,9 @@ namespace MediaBrowser.Common.Kernel try { - HttpServer = new HttpServer(_kernel.HttpServerUrlPrefix, "Media Browser", _applicationHost, _kernel, _logger); + HttpServer = _applicationHost.Resolve(); + HttpServer.EnableHttpRequestLogging = _kernel.Configuration.EnableHttpLevelLogging; + HttpServer.Start(_kernel.HttpServerUrlPrefix); } catch (HttpListenerException ex) { @@ -295,7 +251,8 @@ namespace MediaBrowser.Common.Kernel try { // The port number can't be in configuration because we don't want it to ever change - UdpServer = new UdpServer(new IPEndPoint(IPAddress.Any, _kernel.UdpServerPortNumber)); + UdpServer = _applicationHost.Resolve(); + UdpServer.Start(_kernel.UdpServerPortNumber); } catch (SocketException ex) { @@ -303,21 +260,28 @@ namespace MediaBrowser.Common.Kernel return; } - UdpListener = UdpServer.Subscribe(async res => + UdpServer.MessageReceived += UdpServer_MessageReceived; + } + + /// + /// Handles the MessageReceived event of the UdpServer control. + /// + /// The source of the event. + /// The instance containing the event data. + async void UdpServer_MessageReceived(object sender, UdpMessageReceivedEventArgs e) + { + var expectedMessage = String.Format("who is MediaBrowser{0}?", _kernel.KernelContext); + var expectedMessageBytes = Encoding.UTF8.GetBytes(expectedMessage); + + if (expectedMessageBytes.SequenceEqual(e.Bytes)) { - var expectedMessage = String.Format("who is MediaBrowser{0}?", _kernel.KernelContext); - var expectedMessageBytes = Encoding.UTF8.GetBytes(expectedMessage); + _logger.Info("Received UDP server request from " + e.RemoteEndPoint); - if (expectedMessageBytes.SequenceEqual(res.Buffer)) - { - _logger.Info("Received UDP server request from " + res.RemoteEndPoint.ToString()); + // Send a response back with our ip address and port + var response = String.Format("MediaBrowser{0}|{1}:{2}", _kernel.KernelContext, _networkManager.GetLocalIpAddress(), _kernel.UdpServerPortNumber); - // Send a response back with our ip address and port - var response = String.Format("MediaBrowser{0}|{1}:{2}", _kernel.KernelContext, _networkManager.GetLocalIpAddress(), _kernel.UdpServerPortNumber); - - await UdpServer.SendAsync(response, res.RemoteEndPoint); - } - }); + await UdpServer.SendAsync(Encoding.UTF8.GetBytes(response), e.RemoteEndPoint); + } } /// @@ -407,13 +371,9 @@ namespace MediaBrowser.Common.Kernel { if (UdpServer != null) { + UdpServer.MessageReceived -= UdpServer_MessageReceived; UdpServer.Dispose(); } - - if (UdpListener != null) - { - UdpListener.Dispose(); - } } /// @@ -523,6 +483,8 @@ namespace MediaBrowser.Common.Kernel /// The new config. public void OnApplicationConfigurationChanged(BaseApplicationConfiguration oldConfig, BaseApplicationConfiguration newConfig) { + HttpServer.EnableHttpRequestLogging = newConfig.EnableHttpLevelLogging; + if (oldConfig.HttpServerPortNumber != newConfig.HttpServerPortNumber) { ReloadHttpServer(); diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 57b30eedce..28789a816c 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -38,13 +38,6 @@ - - ..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll - - - ..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll - - False ..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll @@ -53,9 +46,6 @@ False ..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll - - ..\packages\ServiceStack.Api.Swagger.3.9.35\lib\net35\ServiceStack.Api.Swagger.dll - False ..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll @@ -64,9 +54,6 @@ False ..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll - - ..\packages\ServiceStack.Logging.NLog.1.0.6.0\lib\net35\ServiceStack.Logging.NLog.dll - False ..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll @@ -93,18 +80,6 @@ - - False - ..\packages\Rx-Core.2.0.21114\lib\Net45\System.Reactive.Core.dll - - - False - ..\packages\Rx-Interfaces.2.0.21114\lib\Net45\System.Reactive.Interfaces.dll - - - False - ..\packages\Rx-Linq.2.0.21114\lib\Net45\System.Reactive.Linq.dll - @@ -129,19 +104,21 @@ - + + - + + @@ -165,7 +142,6 @@ - @@ -196,23 +172,6 @@ Designer - - - - - - - - - - - - - - - - - diff --git a/MediaBrowser.Common/Net/IHttpServer.cs b/MediaBrowser.Common/Net/IHttpServer.cs new file mode 100644 index 0000000000..a640fb2626 --- /dev/null +++ b/MediaBrowser.Common/Net/IHttpServer.cs @@ -0,0 +1,44 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// + /// Interface IHttpServer + /// + public interface IHttpServer : IDisposable + { + /// + /// Gets the URL prefix. + /// + /// The URL prefix. + string UrlPrefix { get; } + + /// + /// Starts the specified server name. + /// + /// The URL. + void Start(string urlPrefix); + + /// + /// Gets a value indicating whether [supports web sockets]. + /// + /// true if [supports web sockets]; otherwise, false. + bool SupportsWebSockets { get; } + + /// + /// Stops this instance. + /// + void Stop(); + + /// + /// Gets or sets a value indicating whether [enable HTTP request logging]. + /// + /// true if [enable HTTP request logging]; otherwise, false. + bool EnableHttpRequestLogging { get; set; } + + /// + /// Occurs when [web socket connected]. + /// + event EventHandler WebSocketConnected; + } +} \ No newline at end of file diff --git a/MediaBrowser.Common/Net/IUdpServer.cs b/MediaBrowser.Common/Net/IUdpServer.cs index 01a8ef0218..036977eab5 100644 --- a/MediaBrowser.Common/Net/IUdpServer.cs +++ b/MediaBrowser.Common/Net/IUdpServer.cs @@ -1,7 +1,46 @@ - +using System; +using System.Threading.Tasks; + namespace MediaBrowser.Common.Net { - public interface IUdpServer + /// + /// Interface IUdpServer + /// + public interface IUdpServer : IDisposable { + /// + /// Occurs when [message received]. + /// + event EventHandler MessageReceived; + + /// + /// Starts the specified port. + /// + /// The port. + void Start(int port); + + /// + /// Stops this instance. + /// + void Stop(); + + /// + /// Sends the async. + /// + /// The bytes. + /// The remote end point. + /// Task. + /// data + Task SendAsync(byte[] bytes, string remoteEndPoint); + + /// + /// Sends the async. + /// + /// The bytes. + /// The ip address. + /// The port. + /// Task. + /// bytes + Task SendAsync(byte[] bytes, string ipAddress, int port); } } diff --git a/MediaBrowser.Common/Net/IWebSocketServer.cs b/MediaBrowser.Common/Net/IWebSocketServer.cs new file mode 100644 index 0000000000..5ce571fbb8 --- /dev/null +++ b/MediaBrowser.Common/Net/IWebSocketServer.cs @@ -0,0 +1,26 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// + /// Interface IWebSocketServer + /// + public interface IWebSocketServer : IDisposable + { + /// + /// Starts the specified port number. + /// + /// The port number. + void Start(int portNumber); + + /// + /// Stops this instance. + /// + void Stop(); + + /// + /// Occurs when [web socket connected]. + /// + event EventHandler WebSocketConnected; + } +} diff --git a/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs b/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs new file mode 100644 index 0000000000..bd5034c47d --- /dev/null +++ b/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs @@ -0,0 +1,21 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// + /// Class UdpMessageReceivedEventArgs + /// + public class UdpMessageReceivedEventArgs : EventArgs + { + /// + /// Gets or sets the bytes. + /// + /// The bytes. + public byte[] Bytes { get; set; } + /// + /// Gets or sets the remote end point. + /// + /// The remote end point. + public string RemoteEndPoint { get; set; } + } +} diff --git a/MediaBrowser.Common/Net/UdpServer.cs b/MediaBrowser.Common/Net/UdpServer.cs deleted file mode 100644 index a3c6a8a78c..0000000000 --- a/MediaBrowser.Common/Net/UdpServer.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Reactive.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net -{ - /// - /// Provides a Udp Server - /// - public class UdpServer : IObservable, IDisposable - { - /// - /// The _udp client - /// - private readonly UdpClient _udpClient; - /// - /// The _stream - /// - private readonly IObservable _stream; - - /// - /// Initializes a new instance of the class. - /// - /// The end point. - /// endPoint - public UdpServer(IPEndPoint endPoint) - { - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - _udpClient = new UdpClient(endPoint); - - _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - //_udpClient.ExclusiveAddressUse = false; - - _stream = CreateObservable(); - } - - /// - /// Creates the observable. - /// - /// IObservable{UdpReceiveResult}. - private IObservable CreateObservable() - { - return Observable.Create(obs => - Observable.FromAsync(() => _udpClient.ReceiveAsync()) - .Subscribe(obs)) - .Repeat() - .Retry() - .Publish() - .RefCount(); - } - - /// - /// Subscribes the specified observer. - /// - /// The observer. - /// IDisposable. - /// observer - public IDisposable Subscribe(IObserver observer) - { - if (observer == null) - { - throw new ArgumentNullException("observer"); - } - - return _stream.Subscribe(observer); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - _udpClient.Close(); - } - } - - /// - /// Sends the async. - /// - /// The data. - /// The end point. - /// Task{System.Int32}. - /// data - public async Task SendAsync(string data, IPEndPoint endPoint) - { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - var bytes = Encoding.UTF8.GetBytes(data); - - return await _udpClient.SendAsync(bytes, bytes.Length, endPoint).ConfigureAwait(false); - } - - /// - /// Sends the async. - /// - /// The bytes. - /// The end point. - /// Task{System.Int32}. - /// bytes - public async Task SendAsync(byte[] bytes, IPEndPoint endPoint) - { - if (bytes == null) - { - throw new ArgumentNullException("bytes"); - } - - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - return await _udpClient.SendAsync(bytes, bytes.Length, endPoint).ConfigureAwait(false); - } - } -} diff --git a/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs b/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs new file mode 100644 index 0000000000..711da7a503 --- /dev/null +++ b/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs @@ -0,0 +1,22 @@ +using System; +using System.Net; + +namespace MediaBrowser.Common.Net +{ + /// + /// Class WebSocketConnectEventArgs + /// + public class WebSocketConnectEventArgs : EventArgs + { + /// + /// Gets or sets the web socket. + /// + /// The web socket. + public IWebSocket WebSocket { get; set; } + /// + /// Gets or sets the endpoint. + /// + /// The endpoint. + public string Endpoint { get; set; } + } +} diff --git a/MediaBrowser.Common/Net/WebSocketConnection.cs b/MediaBrowser.Common/Net/WebSocketConnection.cs index d274d390d0..ab691c823a 100644 --- a/MediaBrowser.Common/Net/WebSocketConnection.cs +++ b/MediaBrowser.Common/Net/WebSocketConnection.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Common.Net /// /// The _remote end point /// - public readonly EndPoint RemoteEndPoint; + public readonly string RemoteEndPoint; /// /// The _cancellation token source @@ -45,13 +45,13 @@ namespace MediaBrowser.Common.Net /// The remote end point. /// The receive action. /// socket - public WebSocketConnection(IWebSocket socket, EndPoint remoteEndPoint, Action receiveAction, ILogger logger) + public WebSocketConnection(IWebSocket socket, string remoteEndPoint, Action receiveAction, ILogger logger) { if (socket == null) { throw new ArgumentNullException("socket"); } - if (remoteEndPoint == null) + if (string.IsNullOrEmpty(remoteEndPoint)) { throw new ArgumentNullException("remoteEndPoint"); } diff --git a/MediaBrowser.Common/packages.config b/MediaBrowser.Common/packages.config index 536640094c..0ebaf62975 100644 --- a/MediaBrowser.Common/packages.config +++ b/MediaBrowser.Common/packages.config @@ -1,15 +1,8 @@  - - - - - - - diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index 21cfb5ddb2..5ee590bdec 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -315,7 +315,7 @@ namespace MediaBrowser.Controller /// protected override void RegisterExportedValues() { - ApplicationHost.Register(this); + ApplicationHost.RegisterSingleInstance(this); base.RegisterExportedValues(); } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 0701205631..35540020e6 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -69,7 +69,6 @@ - diff --git a/MediaBrowser.Networking/Management/NetworkManager.cs b/MediaBrowser.Networking/Management/NetworkManager.cs index fcead43d3d..208c64a6ed 100644 --- a/MediaBrowser.Networking/Management/NetworkManager.cs +++ b/MediaBrowser.Networking/Management/NetworkManager.cs @@ -260,6 +260,118 @@ namespace MediaBrowser.Networking.Management throw new ArgumentException("Unknown share type"); } } + + /// + /// Parses the specified endpointstring. + /// + /// The endpointstring. + /// IPEndPoint. + public IPEndPoint Parse(string endpointstring) + { + return Parse(endpointstring, -1); + } + + /// + /// Parses the specified endpointstring. + /// + /// The endpointstring. + /// The defaultport. + /// IPEndPoint. + /// Endpoint descriptor may not be empty. + /// + private static IPEndPoint Parse(string endpointstring, int defaultport) + { + if (string.IsNullOrEmpty(endpointstring) + || endpointstring.Trim().Length == 0) + { + throw new ArgumentException("Endpoint descriptor may not be empty."); + } + + if (defaultport != -1 && + (defaultport < IPEndPoint.MinPort + || defaultport > IPEndPoint.MaxPort)) + { + throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultport)); + } + + string[] values = endpointstring.Split(new char[] { ':' }); + IPAddress ipaddy; + int port = -1; + + //check if we have an IPv6 or ports + if (values.Length <= 2) // ipv4 or hostname + { + if (values.Length == 1) + //no port is specified, default + port = defaultport; + else + port = GetPort(values[1]); + + //try to use the address as IPv4, otherwise get hostname + if (!IPAddress.TryParse(values[0], out ipaddy)) + ipaddy = GetIPfromHost(values[0]); + } + else if (values.Length > 2) //ipv6 + { + //could [a:b:c]:d + if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]")) + { + string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray()); + ipaddy = IPAddress.Parse(ipaddressstring); + port = GetPort(values[values.Length - 1]); + } + else //[a:b:c] or a:b:c + { + ipaddy = IPAddress.Parse(endpointstring); + port = defaultport; + } + } + else + { + throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring)); + } + + if (port == -1) + throw new ArgumentException(string.Format("No port specified: '{0}'", endpointstring)); + + return new IPEndPoint(ipaddy, port); + } + + /// + /// Gets the port. + /// + /// The p. + /// System.Int32. + /// + private static int GetPort(string p) + { + int port; + + if (!int.TryParse(p, out port) + || port < IPEndPoint.MinPort + || port > IPEndPoint.MaxPort) + { + throw new FormatException(string.Format("Invalid end point port '{0}'", p)); + } + + return port; + } + + /// + /// Gets the I pfrom host. + /// + /// The p. + /// IPAddress. + /// + private static IPAddress GetIPfromHost(string p) + { + var hosts = Dns.GetHostAddresses(p); + + if (hosts == null || hosts.Length == 0) + throw new ArgumentException(string.Format("Host not found: {0}", p)); + + return hosts[0]; + } } } diff --git a/MediaBrowser.Networking/MediaBrowser.Networking.csproj b/MediaBrowser.Networking/MediaBrowser.Networking.csproj index 194f9e400d..7e4a0b1608 100644 --- a/MediaBrowser.Networking/MediaBrowser.Networking.csproj +++ b/MediaBrowser.Networking/MediaBrowser.Networking.csproj @@ -11,6 +11,8 @@ MediaBrowser.Networking v4.5 512 + ..\ + true true @@ -30,9 +32,68 @@ 4 + + False + ..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll + + + False + ..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll + + + False + ..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll + + + False + ..\packages\ServiceStack.Api.Swagger.3.9.35\lib\net35\ServiceStack.Api.Swagger.dll + + + False + ..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll + + + False + ..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll + + + False + ..\packages\ServiceStack.Logging.NLog.1.0.6.0\lib\net35\ServiceStack.Logging.NLog.dll + + + False + ..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll + + + ..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.SqlServer.dll + + + ..\packages\ServiceStack.Redis.3.9.37\lib\net35\ServiceStack.Redis.dll + + + False + ..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.ServiceInterface.dll + + + False + ..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll + + + False + ..\packages\Rx-Core.2.0.21114\lib\Net45\System.Reactive.Core.dll + + + False + ..\packages\Rx-Interfaces.2.0.21114\lib\Net45\System.Reactive.Interfaces.dll + + + False + ..\packages\Rx-Linq.2.0.21114\lib\Net45\System.Reactive.Linq.dll + + @@ -43,6 +104,10 @@ Properties\SharedVersion.cs + + + + @@ -58,10 +123,31 @@ MediaBrowser.Model + + + + + + + + + + + + + + + + + + + + xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i +