Sfoglia il codice sorgente

plugin security fixes and other abstractions

LukePulverenti 12 anni fa
parent
commit
2d06095447
79 ha cambiato i file con 1271 aggiunte e 1388 eliminazioni
  1. 1 0
      MediaBrowser.Api/EnvironmentService.cs
  2. 4 3
      MediaBrowser.Api/Images/ImageService.cs
  3. 1 0
      MediaBrowser.Api/Javascript/JavascriptApiClientService.cs
  4. 1 2
      MediaBrowser.Api/Library/LibraryService.cs
  5. 2 2
      MediaBrowser.Api/Library/LibraryStructureService.cs
  6. 2 2
      MediaBrowser.Api/LocalizationService.cs
  7. 4 0
      MediaBrowser.Api/MediaBrowser.Api.csproj
  8. 3 3
      MediaBrowser.Api/PackageService.cs
  9. 2 2
      MediaBrowser.Api/PluginService.cs
  10. 2 2
      MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
  11. 1 1
      MediaBrowser.Api/SystemService.cs
  12. 2 3
      MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
  13. 2 2
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  14. 3 3
      MediaBrowser.Api/UserLibrary/UserLibraryService.cs
  15. 1 1
      MediaBrowser.Api/UserService.cs
  16. 2 2
      MediaBrowser.Api/WeatherService.cs
  17. 0 76
      MediaBrowser.ApiInteraction.Portable/DataSerializer.cs
  18. 6 7
      MediaBrowser.ApiInteraction.Portable/MediaBrowser.ApiInteraction.Portable.csproj
  19. 0 1
      MediaBrowser.ApiInteraction.Portable/packages.config
  20. 14 5
      MediaBrowser.ApiInteraction/ApiClient.cs
  21. 1 1
      MediaBrowser.ApiInteraction/AsyncHttpClient.cs
  22. 50 15
      MediaBrowser.ApiInteraction/BaseApiClient.cs
  23. 0 66
      MediaBrowser.ApiInteraction/DataSerializer.cs
  24. 1 1
      MediaBrowser.ApiInteraction/IAsyncHttpClient.cs
  25. 3 10
      MediaBrowser.ApiInteraction/MediaBrowser.ApiInteraction.csproj
  26. 141 0
      MediaBrowser.ApiInteraction/NewtonsoftJsonSerializer.cs
  27. 0 63
      MediaBrowser.ApiInteraction/ServerDiscovery.cs
  28. 1 2
      MediaBrowser.ApiInteraction/packages.config
  29. 295 0
      MediaBrowser.Common.Implementations/BaseApplicationHost.cs
  30. 5 0
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  31. 191 77
      MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
  32. 32 170
      MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
  33. 20 9
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
  34. 20 9
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
  35. 28 8
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs
  36. 28 8
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs
  37. 4 12
      MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
  38. 1 0
      MediaBrowser.Common.Implementations/packages.config
  39. 5 55
      MediaBrowser.Common/Kernel/BaseKernel.cs
  40. 13 29
      MediaBrowser.Common/Kernel/IApplicationHost.cs
  41. 0 18
      MediaBrowser.Common/Kernel/IKernel.cs
  42. 3 3
      MediaBrowser.Common/Kernel/TcpManager.cs
  43. 2 5
      MediaBrowser.Common/MediaBrowser.Common.csproj
  44. 0 31
      MediaBrowser.Common/Net/Handlers/BaseActionHandler.cs
  45. 0 133
      MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs
  46. 3 5
      MediaBrowser.Common/Net/IHttpClient.cs
  47. 6 0
      MediaBrowser.Common/Net/IHttpServer.cs
  48. 0 2
      MediaBrowser.Common/Net/IRestfulService.cs
  49. 16 12
      MediaBrowser.Common/Net/WebSocketConnection.cs
  50. 1 4
      MediaBrowser.Common/Plugins/BasePlugin.cs
  51. 8 48
      MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs
  52. 86 0
      MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs
  53. 2 33
      MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
  54. 1 1
      MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs
  55. 0 4
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  56. 11 11
      MediaBrowser.Controller/Plugins/PluginSecurityManager.cs
  57. 11 11
      MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs
  58. 14 11
      MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs
  59. 11 2
      MediaBrowser.Controller/Updates/InstallationManager.cs
  60. 4 12
      MediaBrowser.Model/Serialization/IJsonSerializer.cs
  61. 4 9
      MediaBrowser.Networking/HttpServer/BaseRestService.cs
  62. 20 23
      MediaBrowser.Networking/HttpServer/HttpServer.cs
  63. 2 3
      MediaBrowser.Networking/HttpServer/ServerFactory.cs
  64. 1 0
      MediaBrowser.Networking/MediaBrowser.Networking.csproj
  65. 4 0
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  66. 1 1
      MediaBrowser.Server.Implementations/Reflection/TypeMapper.cs
  67. 24 13
      MediaBrowser.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
  68. 28 18
      MediaBrowser.Server.Implementations/ScheduledTasks/Tasks/ImageCleanupTask.cs
  69. 27 12
      MediaBrowser.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
  70. 1 0
      MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs
  71. 7 8
      MediaBrowser.ServerApplication/App.xaml.cs
  72. 40 278
      MediaBrowser.ServerApplication/ApplicationHost.cs
  73. 4 3
      MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
  74. 13 4
      MediaBrowser.ServerApplication/MainWindow.xaml.cs
  75. 12 0
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  76. 2 0
      MediaBrowser.ServerApplication/packages.config
  77. 5 15
      MediaBrowser.WebDashboard/Api/DashboardService.cs
  78. 4 0
      MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
  79. 1 3
      Nuget/MediaBrowser.ApiClient.nuspec

+ 1 - 0
MediaBrowser.Api/EnvironmentService.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;

+ 4 - 3
MediaBrowser.Api/Images/ImageService.cs

@@ -1,17 +1,18 @@
-using System.Threading;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
+using ServiceStack.Text.Controller;
 using System;
 using System.IO;
 using System.Linq;
+using System.Threading;
 using System.Threading.Tasks;
-using ServiceStack.Text.Controller;
 
 namespace MediaBrowser.Api.Images
 {

+ 1 - 0
MediaBrowser.Api/Javascript/JavascriptApiClientService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System;
 using System.IO;

+ 1 - 2
MediaBrowser.Api/Library/LibraryService.cs

@@ -1,10 +1,9 @@
 using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;

+ 2 - 2
MediaBrowser.Api/Library/LibraryStructureService.cs

@@ -1,6 +1,6 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;

+ 2 - 2
MediaBrowser.Api/LocalizationService.cs

@@ -1,7 +1,7 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Localization;
+using MediaBrowser.Controller.Localization;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Globalization;
+using MediaBrowser.Networking.HttpServer;
 using MoreLinq;
 using ServiceStack.ServiceHost;
 using System.Collections.Generic;

+ 4 - 0
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -123,6 +123,10 @@
       <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.Networking\MediaBrowser.Networking.csproj">
+      <Project>{7c11010e-179a-49b7-bfb2-f1656f5e71ad}</Project>
+      <Name>MediaBrowser.Networking</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />

+ 3 - 3
MediaBrowser.Api/PackageService.cs

@@ -1,8 +1,8 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.Updates;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;
@@ -142,7 +142,7 @@ namespace MediaBrowser.Api
         {
             var kernel = (Kernel)Kernel;
 
-            var packages = kernel.InstallationManager.GetAvailablePackages(CancellationToken.None, applicationVersion: kernel.ApplicationVersion).Result;
+            var packages = kernel.InstallationManager.GetAvailablePackages(CancellationToken.None, applicationVersion: ApplicationHost.ApplicationVersion).Result;
 
             var result = packages.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
 
@@ -158,7 +158,7 @@ namespace MediaBrowser.Api
         {
             var kernel = (Kernel)Kernel;
 
-            var packages = kernel.InstallationManager.GetAvailablePackages(CancellationToken.None, request.PackageType, kernel.ApplicationVersion).Result;
+            var packages = kernel.InstallationManager.GetAvailablePackages(CancellationToken.None, request.PackageType, ApplicationHost.ApplicationVersion).Result;
 
             return ToOptimizedResult(packages.ToList());
         }

+ 2 - 2
MediaBrowser.Api/PluginService.cs

@@ -1,9 +1,9 @@
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Plugins;
 using MediaBrowser.Model.Serialization;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using ServiceStack.Text.Controller;
 using System;
@@ -148,7 +148,7 @@ namespace MediaBrowser.Api
         public object Get(GetPlugins request)
         {
             var result = Kernel.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToList();
-
+            
             return ToOptimizedResult(result);
         }
 

+ 2 - 2
MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs

@@ -1,14 +1,14 @@
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Tasks;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
+using ServiceStack.Text.Controller;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using ServiceStack.Text.Controller;
 
 namespace MediaBrowser.Api.ScheduledTasks
 {

+ 1 - 1
MediaBrowser.Api/SystemService.cs

@@ -1,9 +1,9 @@
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System;
 using System.IO;

+ 2 - 3
MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs

@@ -1,10 +1,9 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;

+ 2 - 2
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -1,10 +1,10 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;

+ 3 - 3
MediaBrowser.Api/UserLibrary/UserLibraryService.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
@@ -7,13 +6,14 @@ using MediaBrowser.Model.Connectivity;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Serialization;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
+using ServiceStack.Text.Controller;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
-using ServiceStack.Text.Controller;
 
 namespace MediaBrowser.Api.UserLibrary
 {

+ 1 - 1
MediaBrowser.Api/UserService.cs

@@ -1,9 +1,9 @@
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Serialization;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using ServiceStack.Text.Controller;
 using System;

+ 2 - 2
MediaBrowser.Api/WeatherService.cs

@@ -1,6 +1,6 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.Weather;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
 using System.Linq;
 using System.Threading;

+ 0 - 76
MediaBrowser.ApiInteraction.Portable/DataSerializer.cs

@@ -1,76 +0,0 @@
-using Newtonsoft.Json;
-using ProtoBuf;
-using ProtoBuf.Meta;
-using System;
-using System.IO;
-
-namespace MediaBrowser.ApiInteraction
-{
-    /// <summary>
-    /// Class DataSerializer
-    /// </summary>
-    public static class DataSerializer
-    {
-        /// <summary>
-        /// Gets or sets the dynamically created serializer.
-        /// </summary>
-        /// <value>The dynamic serializer.</value>
-        public static TypeModel DynamicSerializer { get; set; }
-
-        /// <summary>
-        /// Deserializes an object
-        /// </summary>
-        /// <param name="stream">The stream.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="type">The type.</param>
-        /// <returns>System.Object.</returns>
-        /// <exception cref="System.NotImplementedException"></exception>
-        public static object DeserializeFromStream(Stream stream, SerializationFormats format, Type type)
-        {
-            if (format == SerializationFormats.Protobuf)
-            {
-                if (DynamicSerializer != null)
-                {
-                    return DynamicSerializer.Deserialize(stream, null, type);
-                }
-                return Serializer.NonGeneric.Deserialize(type, stream);
-            }
-            if (format == SerializationFormats.Json)
-            {
-                using (var streamReader = new StreamReader(stream))
-                {
-                    using (var jsonReader = new JsonTextReader(streamReader))
-                    {
-                        return JsonSerializer.Create(new JsonSerializerSettings()).Deserialize(jsonReader, type);
-                    }
-                }
-            }
-
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Serializes to json.
-        /// </summary>
-        /// <param name="obj">The obj.</param>
-        /// <returns>System.String.</returns>
-        public static string SerializeToJsonString(object obj)
-        {
-            using (var streamWriter = new StringWriter())
-            {
-                using (var jsonWriter = new JsonTextWriter((streamWriter)))
-                {
-                    JsonSerializer.Create(new JsonSerializerSettings()).Serialize(jsonWriter, obj);
-                }
-                return streamWriter.ToString();
-            }
-        }
-
-        /// <summary>
-        /// Configures this instance.
-        /// </summary>
-        public static void Configure()
-        {
-        }
-    }
-}

+ 6 - 7
MediaBrowser.ApiInteraction.Portable/MediaBrowser.ApiInteraction.Portable.csproj

@@ -38,10 +38,15 @@
     <Compile Include="..\MediaBrowser.ApiInteraction\AsyncHttpClient.cs">
       <Link>AsyncHttpClient.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.ApiInteraction\NewtonsoftJsonSerializer.cs">
+      <Link>NewtonsoftJsonSerializer.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.ApiInteraction\SerializationFormats.cs">
+      <Link>SerializationFormats.cs</Link>
+    </Compile>
     <Compile Include="..\SharedVersion.cs">
       <Link>Properties\SharedVersion.cs</Link>
     </Compile>
-    <Compile Include="DataSerializer.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="..\MediaBrowser.ApiInteraction\BaseApiClient.cs">
       <Link>BaseApiClient.cs</Link>
@@ -52,9 +57,6 @@
     <Compile Include="..\MediaBrowser.ApiInteraction\IAsyncHttpClient.cs">
       <Link>IAsyncHttpClient.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.ApiInteraction\SerializationFormats.cs">
-      <Link>SerializationFormats.cs</Link>
-    </Compile>
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Microsoft.Threading.Tasks">
@@ -66,9 +68,6 @@
     <Reference Include="Newtonsoft.Json">
       <HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\portable-net40+sl4+wp7+win8\Newtonsoft.Json.dll</HintPath>
     </Reference>
-    <Reference Include="protobuf-net">
-      <HintPath>..\packages\protobuf-net.2.0.0.621\lib\portable-sl4+net40+wp7+windows8\protobuf-net.dll</HintPath>
-    </Reference>
     <Reference Include="System.Net.Http">
       <HintPath>..\packages\Microsoft.Net.Http.2.1.3-beta\lib\portable-net40+sl4+win8+wp71\System.Net.Http.dll</HintPath>
     </Reference>

+ 0 - 1
MediaBrowser.ApiInteraction.Portable/packages.config

@@ -5,5 +5,4 @@
   <package id="Microsoft.Bcl.Build" version="1.0.0-rc" targetFramework="portable-win+net45+sl40+wp71" />
   <package id="Microsoft.Net.Http" version="2.1.3-beta" targetFramework="portable-win+net45+sl40+wp71" />
   <package id="Newtonsoft.Json" version="4.5.11" targetFramework="portable-win+net45+sl40+wp71" />
-  <package id="protobuf-net" version="2.0.0.621" targetFramework="portable-win+net45+sl40+wp71" />
 </packages>

+ 14 - 5
MediaBrowser.ApiInteraction/ApiClient.cs

@@ -45,6 +45,15 @@ namespace MediaBrowser.ApiInteraction
             HttpClient = httpClient;
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ApiClient" /> class.
+        /// </summary>
+        /// <param name="logger">The logger.</param>
+        public ApiClient(ILogger logger)
+            : this(logger, new AsyncHttpClient())
+        {
+        }
+
         /// <summary>
         /// Sets the authorization header.
         /// </summary>
@@ -67,7 +76,7 @@ namespace MediaBrowser.ApiInteraction
                 throw new ArgumentNullException("url");
             }
 
-            return HttpClient.GetStreamAsync(url, Logger, CancellationToken.None);
+            return HttpClient.GetAsync(url, Logger, CancellationToken.None);
         }
 
         /// <summary>
@@ -364,7 +373,7 @@ namespace MediaBrowser.ApiInteraction
 
             var url = GetApiUrl("Plugins/" + plugin.Id + "/Assembly");
 
-            return HttpClient.GetStreamAsync(url, Logger, CancellationToken.None);
+            return HttpClient.GetAsync(url, Logger, CancellationToken.None);
         }
 
         /// <summary>
@@ -431,7 +440,7 @@ namespace MediaBrowser.ApiInteraction
 
             var url = GetApiUrl("Plugins/" + pluginId + "/ConfigurationFile");
 
-            return await HttpClient.GetStreamAsync(url, Logger, CancellationToken.None).ConfigureAwait(false);
+            return await HttpClient.GetAsync(url, Logger, CancellationToken.None).ConfigureAwait(false);
         }
 
         /// <summary>
@@ -963,7 +972,7 @@ namespace MediaBrowser.ApiInteraction
 
             const string contentType = "application/x-www-form-urlencoded";
 
-            var postContent = DataSerializer.SerializeToJsonString(obj);
+            var postContent = SerializeToJson(obj);
 
             using (var stream = await HttpClient.PostAsync(url, contentType, postContent, Logger, CancellationToken.None).ConfigureAwait(false))
             {
@@ -991,7 +1000,7 @@ namespace MediaBrowser.ApiInteraction
         {
             url = AddDataFormat(url, serializationFormat);
 
-            return HttpClient.GetStreamAsync(url, Logger, CancellationToken.None);
+            return HttpClient.GetAsync(url, Logger, CancellationToken.None);
         }
 
 

+ 1 - 1
MediaBrowser.ApiInteraction/AsyncHttpClient.cs

@@ -45,7 +45,7 @@ namespace MediaBrowser.ApiInteraction
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{Stream}.</returns>
         /// <exception cref="MediaBrowser.Model.Net.HttpException"></exception>
-        public async Task<Stream> GetStreamAsync(string url, ILogger logger, CancellationToken cancellationToken)
+        public async Task<Stream> GetAsync(string url, ILogger logger, CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
 

+ 50 - 15
MediaBrowser.ApiInteraction/BaseApiClient.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Web;
 using System;
 using System.Collections.Generic;
@@ -21,10 +22,23 @@ namespace MediaBrowser.ApiInteraction
         /// <value>The logger.</value>
         protected ILogger Logger { get; private set; }
 
+        /// <summary>
+        /// Gets the protobuf serializer.
+        /// </summary>
+        /// <value>The protobuf serializer.</value>
+        public IProtobufSerializer ProtobufSerializer { get; private set; }
+
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        public IJsonSerializer JsonSerializer { get; private set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseApiClient" /> class.
         /// </summary>
         /// <param name="logger">The logger.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
         /// <exception cref="System.ArgumentNullException">logger</exception>
         protected BaseApiClient(ILogger logger)
         {
@@ -33,9 +47,9 @@ namespace MediaBrowser.ApiInteraction
                 throw new ArgumentNullException("logger");
             }
 
+            JsonSerializer = new NewtonsoftJsonSerializer();
             Logger = logger;
-
-            DataSerializer.Configure();
+            SerializationFormat = SerializationFormats.Json;
         }
 
         /// <summary>
@@ -90,22 +104,11 @@ namespace MediaBrowser.ApiInteraction
             }
         }
 
-        private SerializationFormats _serializationFormat = SerializationFormats.Protobuf;
         /// <summary>
         /// Gets the default data format to request from the server
         /// </summary>
         /// <value>The serialization format.</value>
-        public SerializationFormats SerializationFormat
-        {
-            get
-            {
-                return _serializationFormat;
-            }
-            set
-            {
-                _serializationFormat = value;
-            }
-        }
+        public SerializationFormats SerializationFormat { get; set; }
 
         /// <summary>
         /// Resets the authorization header.
@@ -790,7 +793,39 @@ namespace MediaBrowser.ApiInteraction
         protected T DeserializeFromStream<T>(Stream stream)
             where T : class
         {
-            return (T)DataSerializer.DeserializeFromStream(stream, SerializationFormat, typeof(T));
+            return (T)DeserializeFromStream(stream, typeof(T), SerializationFormat);
+        }
+
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <param name="stream">The stream.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="format">The format.</param>
+        /// <returns>System.Object.</returns>
+        /// <exception cref="System.NotImplementedException"></exception>
+        protected object DeserializeFromStream(Stream stream, Type type, SerializationFormats format)
+        {
+            if (format == SerializationFormats.Protobuf)
+            {
+                return ProtobufSerializer.DeserializeFromStream(stream, type);
+            }
+            if (format == SerializationFormats.Json)
+            {
+                return JsonSerializer.DeserializeFromStream(stream, type);
+            }
+
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Serializers to json.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <returns>System.String.</returns>
+        protected string SerializeToJson(object obj)
+        {
+            return JsonSerializer.SerializeToString(obj);
         }
 
         /// <summary>

+ 0 - 66
MediaBrowser.ApiInteraction/DataSerializer.cs

@@ -1,66 +0,0 @@
-using ProtoBuf;
-using ProtoBuf.Meta;
-using ServiceStack.Text;
-using System;
-using System.IO;
-
-namespace MediaBrowser.ApiInteraction
-{
-    /// <summary>
-    /// Class DataSerializer
-    /// </summary>
-    public static class DataSerializer
-    {
-        /// <summary>
-        /// Gets or sets the dynamically created serializer.
-        /// </summary>
-        /// <value>The dynamic serializer.</value>
-        public static TypeModel DynamicSerializer { get; set; }
-
-        /// <summary>
-        /// Deserializes an object
-        /// </summary>
-        /// <param name="stream">The stream.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="type">The type.</param>
-        /// <returns>System.Object.</returns>
-        /// <exception cref="System.NotImplementedException"></exception>
-        public static object DeserializeFromStream(Stream stream, SerializationFormats format, Type type)
-        {
-            if (format == SerializationFormats.Protobuf)
-            {
-                if (DynamicSerializer != null)
-                {
-                    return DynamicSerializer.Deserialize(stream, null, type);
-                }
-                return Serializer.NonGeneric.Deserialize(type, stream);
-            }
-            if (format == SerializationFormats.Json)
-            {
-                return JsonSerializer.DeserializeFromStream(type, stream);
-            }
-
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Serializes to json.
-        /// </summary>
-        /// <param name="obj">The obj.</param>
-        /// <returns>System.String.</returns>
-        public static string SerializeToJsonString(object obj)
-        {
-            return JsonSerializer.SerializeToString(obj, obj.GetType());
-        }
-
-        /// <summary>
-        /// Configures this instance.
-        /// </summary>
-        public static void Configure()
-        {
-            JsConfig.DateHandler = JsonDateHandler.ISO8601;
-            JsConfig.ExcludeTypeInfo = true;
-            JsConfig.IncludeNullValues = false;
-        }
-    }
-}

+ 1 - 1
MediaBrowser.ApiInteraction/IAsyncHttpClient.cs

@@ -24,7 +24,7 @@ namespace MediaBrowser.ApiInteraction
         /// <param name="logger">The logger.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{Stream}.</returns>
-        Task<Stream> GetStreamAsync(string url, ILogger logger, CancellationToken cancellationToken);
+        Task<Stream> GetAsync(string url, ILogger logger, CancellationToken cancellationToken);
 
         /// <summary>
         /// Deletes the async.

+ 3 - 10
MediaBrowser.ApiInteraction/MediaBrowser.ApiInteraction.csproj

@@ -32,19 +32,13 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="protobuf-net, Version=2.0.0.621, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Text, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.WebRequest" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
@@ -58,11 +52,10 @@
     <Compile Include="AsyncHttpClient.cs" />
     <Compile Include="BaseApiClient.cs" />
     <Compile Include="ApiClient.cs" />
-    <Compile Include="DataSerializer.cs" />
     <Compile Include="IAsyncHttpClient.cs" />
+    <Compile Include="NewtonsoftJsonSerializer.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SerializationFormats.cs" />
-    <Compile Include="ServerDiscovery.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">

+ 141 - 0
MediaBrowser.ApiInteraction/NewtonsoftJsonSerializer.cs

@@ -0,0 +1,141 @@
+using MediaBrowser.Model.Serialization;
+using Newtonsoft.Json;
+using System;
+using System.IO;
+
+namespace MediaBrowser.ApiInteraction
+{
+    /// <summary>
+    /// Class NewtonsoftJsonSerializer
+    /// </summary>
+    public class NewtonsoftJsonSerializer : IJsonSerializer
+    {
+        /// <summary>
+        /// Serializes to stream.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <param name="stream">The stream.</param>
+        /// <exception cref="System.NotImplementedException"></exception>
+        /// <exception cref="System.ArgumentNullException">obj</exception>
+        public void SerializeToStream(object obj, Stream stream)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <param name="stream">The stream.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>System.Object.</returns>
+        public object DeserializeFromStream(Stream stream, Type type)
+        {
+            using (var streamReader = new StreamReader(stream))
+            {
+                using (var jsonReader = new JsonTextReader(streamReader))
+                {
+                    return JsonSerializer.Create(new JsonSerializerSettings()).Deserialize(jsonReader, type);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="stream">The stream.</param>
+        /// <returns>``0.</returns>
+        public T DeserializeFromStream<T>(Stream stream)
+        {
+            return (T)DeserializeFromStream(stream, typeof(T));
+        }
+
+        /// <summary>
+        /// Deserializes from string.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="text">The text.</param>
+        /// <returns>``0.</returns>
+        /// <exception cref="System.NotImplementedException"></exception>
+        public T DeserializeFromString<T>(string text)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Deserializes from string.
+        /// </summary>
+        /// <param name="json">The json.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>System.Object.</returns>
+        /// <exception cref="System.NotImplementedException"></exception>
+        public object DeserializeFromString(string json, Type type)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Serializes to string.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <returns>System.String.</returns>
+        public string SerializeToString(object obj)
+        {
+            using (var streamWriter = new StringWriter())
+            {
+                using (var jsonWriter = new JsonTextWriter((streamWriter)))
+                {
+                    JsonSerializer.Create(new JsonSerializerSettings()).Serialize(jsonWriter, obj);
+                }
+                return streamWriter.ToString();
+            }
+        }
+
+        /// <summary>
+        /// Serializes to bytes.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <returns>System.Byte[][].</returns>
+        /// <exception cref="System.NotImplementedException"></exception>
+        public byte[] SerializeToBytes(object obj)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Serializes to file.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <param name="file">The file.</param>
+        /// <exception cref="System.NotImplementedException"></exception>
+        /// <exception cref="System.ArgumentNullException">obj</exception>
+        public void SerializeToFile(object obj, string file)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Deserializes from file.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="file">The file.</param>
+        /// <returns>System.Object.</returns>
+        /// <exception cref="System.NotImplementedException"></exception>
+        public object DeserializeFromFile(Type type, string file)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Deserializes from file.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="file">The file.</param>
+        /// <returns>``0.</returns>
+        /// <exception cref="System.NotImplementedException"></exception>
+        public T DeserializeFromFile<T>(string file) where T : class
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

+ 0 - 63
MediaBrowser.ApiInteraction/ServerDiscovery.cs

@@ -1,63 +0,0 @@
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.ApiInteraction
-{
-    public static class ServerDiscovery
-    {
-        /// <summary>
-        /// Attemps to discover the server within a local network
-        /// </summary>
-        public static async Task<IPEndPoint> DiscoverServer()
-        {
-            // Create a udp client
-            var client = new UdpClient(new IPEndPoint(IPAddress.Any, GetRandomUnusedPort()));
-
-            // Construct the message the server is expecting
-            var bytes = Encoding.UTF8.GetBytes("who is MediaBrowserServer?");
-
-            // Send it - must be IPAddress.Broadcast, 7359
-            var targetEndPoint = new IPEndPoint(IPAddress.Broadcast, 7359);
-
-            // Send it
-            await client.SendAsync(bytes, bytes.Length, targetEndPoint).ConfigureAwait(false);
-
-            // Get a result back
-            var result = await client.ReceiveAsync().ConfigureAwait(false);
-
-            if (result.RemoteEndPoint.Port == targetEndPoint.Port)
-            {
-                // Convert bytes to text
-                var text = Encoding.UTF8.GetString(result.Buffer);
-
-                // Expected response : MediaBrowserServer|192.168.1.1:1234
-                // If the response is what we're expecting, proceed
-                if (text.StartsWith("mediabrowserserver", StringComparison.OrdinalIgnoreCase))
-                {
-                    text = text.Split('|')[1];
-
-                    var vals = text.Split(':');
-
-                    return new IPEndPoint(IPAddress.Parse(vals[0]), int.Parse(vals[1]));
-                }
-            }
-
-            return null;
-        }
-
-        /// <summary>
-        /// Gets a random port number that is currently available
-        /// </summary>
-        private static int GetRandomUnusedPort()
-        {
-            var listener = new TcpListener(IPAddress.Any, 0);
-            listener.Start();
-            var port = ((IPEndPoint)listener.LocalEndpoint).Port;
-            listener.Stop();
-            return port;
-        }
-    }
-}

+ 1 - 2
MediaBrowser.ApiInteraction/packages.config

@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" />
-  <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
 </packages>

+ 295 - 0
MediaBrowser.Common.Implementations/BaseApplicationHost.cs

@@ -0,0 +1,295 @@
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using SimpleInjector;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace MediaBrowser.Common.Implementations
+{
+    public abstract class BaseApplicationHost : IDisposable
+    {
+        /// <summary>
+        /// Gets or sets the logger.
+        /// </summary>
+        /// <value>The logger.</value>
+        public ILogger Logger { get; protected set; }
+
+        /// <summary>
+        /// The container
+        /// </summary>
+        protected readonly Container Container = new Container();
+      
+        /// <summary>
+        /// Gets assemblies that failed to load
+        /// </summary>
+        public List<string> FailedAssemblies { get; protected set; }
+
+        /// <summary>
+        /// Gets all types within all running assemblies
+        /// </summary>
+        /// <value>All types.</value>
+        public Type[] AllTypes { get; protected set; }
+
+        /// <summary>
+        /// Gets all concrete types.
+        /// </summary>
+        /// <value>All concrete types.</value>
+        public Type[] AllConcreteTypes { get; protected set; }
+
+        /// <summary>
+        /// The disposable parts
+        /// </summary>
+        protected readonly List<IDisposable> DisposableParts = new List<IDisposable>();
+
+        /// <summary>
+        /// The _protobuf serializer initialized
+        /// </summary>
+        private bool _protobufSerializerInitialized;
+        /// <summary>
+        /// The _protobuf serializer sync lock
+        /// </summary>
+        private object _protobufSerializerSyncLock = new object();
+        /// <summary>
+        /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection
+        /// </summary>
+        private IProtobufSerializer _protobufSerializer;
+        /// <summary>
+        /// Gets the protobuf serializer.
+        /// </summary>
+        /// <value>The protobuf serializer.</value>
+        protected IProtobufSerializer ProtobufSerializer
+        {
+            get
+            {
+                // Lazy load
+                LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => Serialization.ProtobufSerializer.Create(AllTypes));
+                return _protobufSerializer;
+            }
+            private set
+            {
+                _protobufSerializer = value;
+                _protobufSerializerInitialized = value != null;
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BaseApplicationHost" /> class.
+        /// </summary>
+        protected BaseApplicationHost()
+        {
+            FailedAssemblies = new List<string>();
+        }
+
+        /// <summary>
+        /// Gets the composable part assemblies.
+        /// </summary>
+        /// <returns>IEnumerable{Assembly}.</returns>
+        protected abstract IEnumerable<Assembly> GetComposablePartAssemblies();
+
+        /// <summary>
+        /// Discovers the types.
+        /// </summary>
+        protected void DiscoverTypes()
+        {
+            FailedAssemblies.Clear();
+
+            AllTypes = GetComposablePartAssemblies().SelectMany(GetTypes).ToArray();
+
+            AllConcreteTypes = AllTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray();
+        }
+
+        /// <summary>
+        /// Gets a list of types within an assembly
+        /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
+        /// </summary>
+        /// <param name="assembly">The assembly.</param>
+        /// <returns>IEnumerable{Type}.</returns>
+        /// <exception cref="System.ArgumentNullException">assembly</exception>
+        protected IEnumerable<Type> GetTypes(Assembly assembly)
+        {
+            if (assembly == null)
+            {
+                throw new ArgumentNullException("assembly");
+            }
+
+            try
+            {
+                return assembly.GetTypes();
+            }
+            catch (ReflectionTypeLoadException ex)
+            {
+                // If it fails we can still get a list of the Types it was able to resolve
+                return ex.Types.Where(t => t != null);
+            }
+        }
+
+        /// <summary>
+        /// Creates an instance of type and resolves all constructor dependancies
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>System.Object.</returns>
+        public object CreateInstance(Type type)
+        {
+            try
+            {
+                return Container.GetInstance(type);
+            }
+            catch
+            {
+                Logger.Error("Error creating {0}", type.Name);
+
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Registers the specified obj.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj">The obj.</param>
+        protected void RegisterSingleInstance<T>(T obj)
+            where T : class
+        {
+            Container.RegisterSingle(obj);
+        }
+
+        /// <summary>
+        /// Registers the specified func.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="func">The func.</param>
+        protected void Register<T>(Func<T> func)
+            where T : class
+        {
+            Container.Register(func);
+        }
+
+        /// <summary>
+        /// Registers the single instance.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="func">The func.</param>
+        protected void RegisterSingleInstance<T>(Func<T> func)
+            where T : class
+        {
+            Container.RegisterSingle(func);
+        }
+
+        /// <summary>
+        /// Resolves this instance.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <returns>``0.</returns>
+        public T Resolve<T>()
+        {
+            return (T)Container.GetRegistration(typeof(T), true).GetInstance();
+        }
+
+        /// <summary>
+        /// Resolves this instance.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <returns>``0.</returns>
+        public T TryResolve<T>()
+        {
+            var result = Container.GetRegistration(typeof(T), false);
+
+            if (result == null)
+            {
+                return default(T);
+            }
+            return (T)result.GetInstance();
+        }
+
+        /// <summary>
+        /// Registers the specified service type.
+        /// </summary>
+        /// <param name="serviceType">Type of the service.</param>
+        /// <param name="implementation">Type of the concrete.</param>
+        protected void Register(Type serviceType, Type implementation)
+        {
+            Container.Register(serviceType, implementation);
+        }
+
+        /// <summary>
+        /// Loads the assembly.
+        /// </summary>
+        /// <param name="file">The file.</param>
+        /// <returns>Assembly.</returns>
+        protected Assembly LoadAssembly(string file)
+        {
+            try
+            {
+                return Assembly.Load(File.ReadAllBytes((file)));
+            }
+            catch (Exception ex)
+            {
+                FailedAssemblies.Add(file);
+                Logger.ErrorException("Error loading assembly {0}", ex, file);
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Gets the exports.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
+        /// <returns>IEnumerable{``0}.</returns>
+        public IEnumerable<T> GetExports<T>(bool manageLiftime = true)
+        {
+            var currentType = typeof(T);
+
+            Logger.Info("Composing instances of " + currentType.Name);
+
+            var parts = AllConcreteTypes.Where(currentType.IsAssignableFrom).Select(CreateInstance).Cast<T>().ToArray();
+
+            if (manageLiftime)
+            {
+                DisposableParts.AddRange(parts.OfType<IDisposable>());
+            }
+
+            return parts;
+        }
+
+        /// <summary>
+        /// Gets the current application version
+        /// </summary>
+        /// <value>The application version.</value>
+        public Version ApplicationVersion
+        {
+            get
+            {
+                return GetType().Assembly.GetName().Version;
+            }
+        }
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources.
+        /// </summary>
+        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+        protected virtual void Dispose(bool dispose)
+        {
+            foreach (var part in DisposableParts)
+            {
+                part.Dispose();
+            }
+
+            var b = Container.GetCurrentRegistrations();
+
+            DisposableParts.Clear();
+        }
+    }
+}

+ 5 - 0
MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -41,6 +41,9 @@
     <Reference Include="ServiceStack.Text">
       <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath>
     </Reference>
+    <Reference Include="SimpleInjector">
+      <HintPath>..\packages\SimpleInjector.2.0.0-beta5\lib\net40-client\SimpleInjector.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Configuration" />
     <Reference Include="System.Core" />
@@ -54,8 +57,10 @@
     <Compile Include="..\SharedVersion.cs">
       <Link>Properties\SharedVersion.cs</Link>
     </Compile>
+    <Compile Include="BaseApplicationHost.cs" />
     <Compile Include="BaseApplicationPaths.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ScheduledTasks\ScheduledTaskWorker.cs" />
     <Compile Include="ScheduledTasks\TaskManager.cs" />
     <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" />
     <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" />

+ 191 - 77
MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs → MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs

@@ -1,6 +1,8 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Tasks;
 using System;
 using System.Collections.Generic;
@@ -9,60 +11,58 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Common.ScheduledTasks
+namespace MediaBrowser.Common.Implementations.ScheduledTasks
 {
     /// <summary>
-    /// Represents a task that can be executed at a scheduled time
+    /// Class ScheduledTaskWorker
     /// </summary>
-    /// <typeparam name="TKernelType">The type of the T kernel type.</typeparam>
-    public abstract class BaseScheduledTask<TKernelType> : IScheduledTask
-        where TKernelType : class, IKernel
+    public class ScheduledTaskWorker : IScheduledTaskWorker
     {
         /// <summary>
-        /// Gets the kernel.
+        /// Gets or sets the scheduled task.
         /// </summary>
-        /// <value>The kernel.</value>
-        protected TKernelType Kernel { get; private set; }
+        /// <value>The scheduled task.</value>
+        public IScheduledTask ScheduledTask { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        private IJsonSerializer JsonSerializer { get; set; }
+
+        /// <summary>
+        /// Gets or sets the application paths.
+        /// </summary>
+        /// <value>The application paths.</value>
+        private IApplicationPaths ApplicationPaths { get; set; }
 
         /// <summary>
         /// Gets the logger.
         /// </summary>
         /// <value>The logger.</value>
-        protected ILogger Logger { get; private set; }
+        private ILogger Logger { get; set; }
 
         /// <summary>
         /// Gets the task manager.
         /// </summary>
         /// <value>The task manager.</value>
-        protected ITaskManager TaskManager { get; private set; }
+        private ITaskManager TaskManager { get; set; }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="BaseScheduledTask{TKernelType}" /> class.
+        /// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class.
         /// </summary>
-        /// <param name="kernel">The kernel.</param>
+        /// <param name="scheduledTask">The scheduled task.</param>
+        /// <param name="applicationPaths">The application paths.</param>
         /// <param name="taskManager">The task manager.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logger">The logger.</param>
-        /// <exception cref="System.ArgumentNullException">kernel</exception>
-        protected BaseScheduledTask(TKernelType kernel, ITaskManager taskManager, ILogger logger)
+        public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger)
         {
-            if (kernel == null)
-            {
-                throw new ArgumentNullException("kernel");
-            }
-            if (taskManager == null)
-            {
-                throw new ArgumentNullException("taskManager");
-            }
-            if (logger == null)
-            {
-                throw new ArgumentNullException("logger");
-            }
-
-            Kernel = kernel;
+            ScheduledTask = scheduledTask;
+            ApplicationPaths = applicationPaths;
             TaskManager = taskManager;
+            JsonSerializer = jsonSerializer;
             Logger = logger;
-
-            ReloadTriggerEvents(true);
         }
 
         /// <summary>
@@ -89,7 +89,7 @@ namespace MediaBrowser.Common.ScheduledTasks
                 {
                     try
                     {
-                        return TaskManager.GetLastExecutionResult(this);
+                        return JsonSerializer.DeserializeFromFile<TaskResult>(GetHistoryFilePath());
                     }
                     catch (IOException)
                     {
@@ -108,6 +108,33 @@ namespace MediaBrowser.Common.ScheduledTasks
             }
         }
 
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ScheduledTask.Name; }
+        }
+
+        /// <summary>
+        /// Gets the description.
+        /// </summary>
+        /// <value>The description.</value>
+        public string Description
+        {
+            get { return ScheduledTask.Description; }
+        }
+
+        /// <summary>
+        /// Gets the category.
+        /// </summary>
+        /// <value>The category.</value>
+        public string Category
+        {
+            get { return ScheduledTask.Category; }
+        }
+
         /// <summary>
         /// Gets the current cancellation token
         /// </summary>
@@ -166,7 +193,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         {
             get
             {
-                LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, () => TaskManager.LoadTriggers(this));
+                LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, () => LoadTriggers());
 
                 return _triggers;
             }
@@ -189,45 +216,10 @@ namespace MediaBrowser.Common.ScheduledTasks
 
                 ReloadTriggerEvents(false);
 
-                TaskManager.SaveTriggers(this, _triggers);
+                SaveTriggers(_triggers);
             }
         }
 
-        /// <summary>
-        /// Creates the triggers that define when the task will run
-        /// </summary>
-        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public abstract IEnumerable<ITaskTrigger> GetDefaultTriggers();
-
-        /// <summary>
-        /// Returns the task to be executed
-        /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <param name="progress">The progress.</param>
-        /// <returns>Task.</returns>
-        protected abstract Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress);
-
-        /// <summary>
-        /// Gets the name of the task
-        /// </summary>
-        /// <value>The name.</value>
-        public abstract string Name { get; }
-
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
-        public abstract string Description { get; }
-
-        /// <summary>
-        /// Gets the category.
-        /// </summary>
-        /// <value>The category.</value>
-        public virtual string Category
-        {
-            get { return "Application"; }
-        }
-
         /// <summary>
         /// The _id
         /// </summary>
@@ -243,7 +235,7 @@ namespace MediaBrowser.Common.ScheduledTasks
             {
                 if (!_id.HasValue)
                 {
-                    _id = GetType().FullName.GetMD5();
+                    _id = ScheduledTask.GetType().FullName.GetMD5();
                 }
 
                 return _id.Value;
@@ -279,10 +271,10 @@ namespace MediaBrowser.Common.ScheduledTasks
 
             trigger.Stop();
 
-            TaskManager.QueueScheduledTask(this);
+            TaskManager.QueueScheduledTask(ScheduledTask);
+
+            await Task.Delay(1000).ConfigureAwait(false);
 
-            await Task.Delay(1000).ConfigureAwait(false); 
-            
             trigger.Start(false);
         }
 
@@ -310,11 +302,11 @@ namespace MediaBrowser.Common.ScheduledTasks
             TaskCompletionStatus status;
             CurrentExecutionStartTime = DateTime.UtcNow;
 
-            Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskBeginExecute", Name);
+            //Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskBeginExecute", Name);
 
             try
             {
-                await Task.Run(async () => await ExecuteInternal(CurrentCancellationTokenSource.Token, progress).ConfigureAwait(false)).ConfigureAwait(false);
+                await System.Threading.Tasks.Task.Run(async () => await ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress).ConfigureAwait(false)).ConfigureAwait(false);
 
                 status = TaskCompletionStatus.Completed;
             }
@@ -332,14 +324,14 @@ namespace MediaBrowser.Common.ScheduledTasks
             var startTime = CurrentExecutionStartTime;
             var endTime = DateTime.UtcNow;
 
-            Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskEndExecute", LastExecutionResult);
+            //Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskEndExecute", LastExecutionResult);
 
             progress.ProgressChanged -= progress_ProgressChanged;
             CurrentCancellationTokenSource.Dispose();
             CurrentCancellationTokenSource = null;
             CurrentProgress = null;
 
-            TaskManager.OnTaskCompleted(this, startTime, endTime, status);
+            OnTaskCompleted(startTime, endTime, status);
         }
 
         /// <summary>
@@ -378,6 +370,128 @@ namespace MediaBrowser.Common.ScheduledTasks
             }
         }
 
+        /// <summary>
+        /// The _scheduled tasks configuration directory
+        /// </summary>
+        private string _scheduledTasksConfigurationDirectory;
+        /// <summary>
+        /// Gets the scheduled tasks configuration directory.
+        /// </summary>
+        /// <value>The scheduled tasks configuration directory.</value>
+        private string ScheduledTasksConfigurationDirectory
+        {
+            get
+            {
+                if (_scheduledTasksConfigurationDirectory == null)
+                {
+                    _scheduledTasksConfigurationDirectory = Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
+
+                    if (!Directory.Exists(_scheduledTasksConfigurationDirectory))
+                    {
+                        Directory.CreateDirectory(_scheduledTasksConfigurationDirectory);
+                    }
+                }
+                return _scheduledTasksConfigurationDirectory;
+            }
+        }
+
+        /// <summary>
+        /// The _scheduled tasks data directory
+        /// </summary>
+        private string _scheduledTasksDataDirectory;
+        /// <summary>
+        /// Gets the scheduled tasks data directory.
+        /// </summary>
+        /// <value>The scheduled tasks data directory.</value>
+        private string ScheduledTasksDataDirectory
+        {
+            get
+            {
+                if (_scheduledTasksDataDirectory == null)
+                {
+                    _scheduledTasksDataDirectory = Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks");
+
+                    if (!Directory.Exists(_scheduledTasksDataDirectory))
+                    {
+                        Directory.CreateDirectory(_scheduledTasksDataDirectory);
+                    }
+                }
+                return _scheduledTasksDataDirectory;
+            }
+        }
+
+        /// <summary>
+        /// Gets the history file path.
+        /// </summary>
+        /// <value>The history file path.</value>
+        private string GetHistoryFilePath()
+        {
+            return Path.Combine(ScheduledTasksDataDirectory, Id + ".js");
+        }
+
+        /// <summary>
+        /// Gets the configuration file path.
+        /// </summary>
+        /// <returns>System.String.</returns>
+        private string GetConfigurationFilePath()
+        {
+            return Path.Combine(ScheduledTasksConfigurationDirectory, Id + ".js");
+        }
+
+        /// <summary>
+        /// Loads the triggers.
+        /// </summary>
+        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+        private IEnumerable<ITaskTrigger> LoadTriggers()
+        {
+            try
+            {
+                return JsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath())
+                .Select(ScheduledTaskHelpers.GetTrigger)
+                .ToList();
+            }
+            catch (IOException)
+            {
+                // File doesn't exist. No biggie. Return defaults.
+                return ScheduledTask.GetDefaultTriggers();
+            }
+        }
+
+        /// <summary>
+        /// Saves the triggers.
+        /// </summary>
+        /// <param name="triggers">The triggers.</param>
+        private void SaveTriggers(IEnumerable<ITaskTrigger> triggers)
+        {
+            JsonSerializer.SerializeToFile(triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), GetConfigurationFilePath());
+        }
+
+        /// <summary>
+        /// Called when [task completed].
+        /// </summary>
+        /// <param name="startTime">The start time.</param>
+        /// <param name="endTime">The end time.</param>
+        /// <param name="status">The status.</param>
+        private void OnTaskCompleted(DateTime startTime, DateTime endTime, TaskCompletionStatus status)
+        {
+            var elapsedTime = endTime - startTime;
+
+            Logger.Info("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds);
+
+            var result = new TaskResult
+            {
+                StartTimeUtc = startTime,
+                EndTimeUtc = endTime,
+                Status = status,
+                Name = Name,
+                Id = Id
+            };
+
+            JsonSerializer.SerializeToFile(result, GetHistoryFilePath());
+
+            LastExecutionResult = result;
+        }
+
         /// <summary>
         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
         /// </summary>
@@ -399,7 +513,7 @@ namespace MediaBrowser.Common.ScheduledTasks
 
                 if (State == TaskState.Running)
                 {
-                    TaskManager.OnTaskCompleted(this, CurrentExecutionStartTime, DateTime.UtcNow, TaskCompletionStatus.Aborted);
+                    OnTaskCompleted(CurrentExecutionStartTime, DateTime.UtcNow, TaskCompletionStatus.Aborted);
                 }
 
                 if (CurrentCancellationTokenSource != null)

+ 32 - 170
MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs

@@ -5,7 +5,6 @@ using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Tasks;
 using System;
 using System.Collections.Generic;
-using System.IO;
 using System.Linq;
 
 namespace MediaBrowser.Common.Implementations.ScheduledTasks
@@ -19,7 +18,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         /// Gets the list of Scheduled Tasks
         /// </summary>
         /// <value>The scheduled tasks.</value>
-        public IScheduledTask[] ScheduledTasks { get; private set; }
+        public IScheduledTaskWorker[] ScheduledTasks { get; private set; }
 
         /// <summary>
         /// The _task queue
@@ -27,19 +26,22 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         private readonly List<Type> _taskQueue = new List<Type>();
 
         /// <summary>
-        /// The _logger
+        /// Gets or sets the json serializer.
         /// </summary>
-        private readonly ILogger _logger;
+        /// <value>The json serializer.</value>
+        private IJsonSerializer JsonSerializer { get; set; }
 
         /// <summary>
-        /// The _application paths
+        /// Gets or sets the application paths.
         /// </summary>
-        private readonly IApplicationPaths _applicationPaths;
+        /// <value>The application paths.</value>
+        private IApplicationPaths ApplicationPaths { get; set; }
 
         /// <summary>
-        /// The _json serializer
+        /// Gets the logger.
         /// </summary>
-        private readonly IJsonSerializer _jsonSerializer;
+        /// <value>The logger.</value>
+        private ILogger Logger { get; set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="TaskManager" /> class.
@@ -50,24 +52,11 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         /// <exception cref="System.ArgumentException">kernel</exception>
         public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger)
         {
-            if (applicationPaths == null)
-            {
-                throw new ArgumentException("applicationPaths");
-            }
-            if (jsonSerializer == null)
-            {
-                throw new ArgumentException("jsonSerializer");
-            }
-            if (logger == null)
-            {
-                throw new ArgumentException("logger");
-            }
+            ApplicationPaths = applicationPaths;
+            JsonSerializer = jsonSerializer;
+            Logger = logger;
 
-            _applicationPaths = applicationPaths;
-            _jsonSerializer = jsonSerializer;
-            _logger = logger;
-
-            ScheduledTasks = new IScheduledTask[] {};
+            ScheduledTasks = new IScheduledTaskWorker[] { };
         }
 
         /// <summary>
@@ -77,7 +66,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         public void CancelIfRunningAndQueue<T>()
                  where T : IScheduledTask
         {
-            ScheduledTasks.OfType<T>().First().CancelIfRunning();
+            ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)).CancelIfRunning();
             QueueScheduledTask<T>();
         }
 
@@ -88,7 +77,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         public void QueueScheduledTask<T>()
             where T : IScheduledTask
         {
-            var scheduledTask = ScheduledTasks.OfType<T>().First();
+            var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
 
             QueueScheduledTask(scheduledTask);
         }
@@ -99,27 +88,36 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         /// <param name="task">The task.</param>
         public void QueueScheduledTask(IScheduledTask task)
         {
-            var type = task.GetType();
+            var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == task.GetType());
 
-            var scheduledTask = ScheduledTasks.First(t => t.GetType() == type);
+            QueueScheduledTask(scheduledTask);
+        }
+
+        /// <summary>
+        /// Queues the scheduled task.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        private void QueueScheduledTask(IScheduledTaskWorker task)
+        {
+            var type = task.GetType();
 
             lock (_taskQueue)
             {
                 // If it's idle just execute immediately
-                if (scheduledTask.State == TaskState.Idle)
+                if (task.State == TaskState.Idle)
                 {
-                    scheduledTask.Execute();
+                    task.Execute();
                     return;
                 }
 
                 if (!_taskQueue.Contains(type))
                 {
-                    _logger.Info("Queueing task {0}", type.Name);
+                    Logger.Info("Queueing task {0}", type.Name);
                     _taskQueue.Add(type);
                 }
                 else
                 {
-                    _logger.Info("Task already queued: {0}", type.Name);
+                    Logger.Info("Task already queued: {0}", type.Name);
                 }
             }
         }
@@ -157,147 +155,11 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         {
             var myTasks = ScheduledTasks.ToList();
 
-            myTasks.AddRange(tasks);
+            myTasks.AddRange(tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger)));
 
             ScheduledTasks = myTasks.ToArray();
         }
 
-        /// <summary>
-        /// The _scheduled tasks configuration directory
-        /// </summary>
-        private string _scheduledTasksConfigurationDirectory;
-        /// <summary>
-        /// Gets the scheduled tasks configuration directory.
-        /// </summary>
-        /// <value>The scheduled tasks configuration directory.</value>
-        private string ScheduledTasksConfigurationDirectory
-        {
-            get
-            {
-                if (_scheduledTasksConfigurationDirectory == null)
-                {
-                    _scheduledTasksConfigurationDirectory = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
-
-                    if (!Directory.Exists(_scheduledTasksConfigurationDirectory))
-                    {
-                        Directory.CreateDirectory(_scheduledTasksConfigurationDirectory);
-                    }
-                }
-                return _scheduledTasksConfigurationDirectory;
-            }
-        }
-
-        /// <summary>
-        /// The _scheduled tasks data directory
-        /// </summary>
-        private string _scheduledTasksDataDirectory;
-        /// <summary>
-        /// Gets the scheduled tasks data directory.
-        /// </summary>
-        /// <value>The scheduled tasks data directory.</value>
-        private string ScheduledTasksDataDirectory
-        {
-            get
-            {
-                if (_scheduledTasksDataDirectory == null)
-                {
-                    _scheduledTasksDataDirectory = Path.Combine(_applicationPaths.DataPath, "ScheduledTasks");
-
-                    if (!Directory.Exists(_scheduledTasksDataDirectory))
-                    {
-                        Directory.CreateDirectory(_scheduledTasksDataDirectory);
-                    }
-                }
-                return _scheduledTasksDataDirectory;
-            }
-        }
-
-        /// <summary>
-        /// Gets the history file path.
-        /// </summary>
-        /// <value>The history file path.</value>
-        private string GetHistoryFilePath(IScheduledTask task)
-        {
-            return Path.Combine(ScheduledTasksDataDirectory, task.Id + ".js");
-        }
-
-        /// <summary>
-        /// Gets the configuration file path.
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <returns>System.String.</returns>
-        private string GetConfigurationFilePath(IScheduledTask task)
-        {
-            return Path.Combine(ScheduledTasksConfigurationDirectory, task.Id + ".js");
-        }
-
-        /// <summary>
-        /// Called when [task completed].
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <param name="startTime">The start time.</param>
-        /// <param name="endTime">The end time.</param>
-        /// <param name="status">The status.</param>
-        public void OnTaskCompleted(IScheduledTask task, DateTime startTime, DateTime endTime, TaskCompletionStatus status)
-        {
-            var elapsedTime = endTime - startTime;
-
-            _logger.Info("{0} {1} after {2} minute(s) and {3} seconds", task.Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds);
-
-            var result = new TaskResult
-            {
-                StartTimeUtc = startTime,
-                EndTimeUtc = endTime,
-                Status = status,
-                Name = task.Name,
-                Id = task.Id
-            };
-
-            _jsonSerializer.SerializeToFile(result, GetHistoryFilePath(task));
-
-            //task.LastExecutionResult = result;
-        }
-
-        /// <summary>
-        /// Gets the last execution result.
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <returns>TaskResult.</returns>
-        public TaskResult GetLastExecutionResult(IScheduledTask task)
-        {
-            return _jsonSerializer.DeserializeFromFile<TaskResult>(GetHistoryFilePath(task));
-        }
-
-        /// <summary>
-        /// Loads the triggers.
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public IEnumerable<ITaskTrigger> LoadTriggers(IScheduledTask task)
-        {
-            try
-            {
-                return _jsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath(task))
-                .Select(ScheduledTaskHelpers.GetTrigger)
-                .ToList();
-            }
-            catch (IOException)
-            {
-                // File doesn't exist. No biggie. Return defaults.
-                return task.GetDefaultTriggers();
-            }
-        }
-
-        /// <summary>
-        /// Saves the triggers.
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <param name="triggers">The triggers.</param>
-        public void SaveTriggers(IScheduledTask task, IEnumerable<ITaskTrigger> triggers)
-        {
-            _jsonSerializer.SerializeToFile(triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), GetConfigurationFilePath(task));
-        }
-
         /// <summary>
         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
         /// </summary>

+ 20 - 9
MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs

@@ -13,24 +13,35 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
     /// <summary>
     /// Deletes old cache files
     /// </summary>
-    public class DeleteCacheFileTask : BaseScheduledTask<IKernel>
+    public class DeleteCacheFileTask : IScheduledTask
     {
+        /// <summary>
+        /// Gets or sets the kernel.
+        /// </summary>
+        /// <value>The kernel.</value>
+        private IKernel Kernel { get; set; }
+        /// <summary>
+        /// Gets or sets the logger.
+        /// </summary>
+        /// <value>The logger.</value>
+        private ILogger Logger { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="taskManager">The task manager.</param>
         /// <param name="logger">The logger.</param>
-        public DeleteCacheFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger)
-            : base(kernel, taskManager, logger)
+        public DeleteCacheFileTask(IKernel kernel, ILogger logger)
         {
+            Kernel = kernel;
+            Logger = logger;
         }
 
         /// <summary>
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am
 
@@ -43,7 +54,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
             return Task.Run(() =>
             {
@@ -90,7 +101,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the name of the task
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Cache file cleanup"; }
         }
@@ -99,7 +110,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return "Deletes cache files no longer needed by the system"; }
         }
@@ -108,7 +119,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the category.
         /// </summary>
         /// <value>The category.</value>
-        public override string Category
+        public string Category
         {
             get
             {

+ 20 - 9
MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs

@@ -13,24 +13,35 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
     /// <summary>
     /// Deletes old log files
     /// </summary>
-    public class DeleteLogFileTask : BaseScheduledTask<IKernel>
+    public class DeleteLogFileTask : IScheduledTask
     {
+        /// <summary>
+        /// Gets or sets the kernel.
+        /// </summary>
+        /// <value>The kernel.</value>
+        private IKernel Kernel { get; set; }
+        /// <summary>
+        /// Gets or sets the logger.
+        /// </summary>
+        /// <value>The logger.</value>
+        private ILogger Logger { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="DeleteLogFileTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="taskManager">The task manager.</param>
         /// <param name="logger">The logger.</param>
-        public DeleteLogFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger)
-            : base(kernel, taskManager, logger)
+        public DeleteLogFileTask(IKernel kernel, ILogger logger)
         {
+            Kernel = kernel;
+            Logger = logger;
         }
 
         /// <summary>
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am
 
@@ -43,7 +54,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
             return Task.Run(() =>
             {
@@ -78,7 +89,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the name of the task
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Log file cleanup"; }
         }
@@ -87,7 +98,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return string.Format("Deletes log files that are more than {0} days old.", Kernel.Configuration.LogFileRetentionDays); }
         }
@@ -96,7 +107,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the category.
         /// </summary>
         /// <value>The category.</value>
-        public override string Category
+        public string Category
         {
             get
             {

+ 28 - 8
MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs

@@ -11,24 +11,35 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
     /// <summary>
     /// Class ReloadLoggerFileTask
     /// </summary>
-    public class ReloadLoggerFileTask : BaseScheduledTask<IKernel>
+    public class ReloadLoggerFileTask : IScheduledTask
     {
+        /// <summary>
+        /// Gets or sets the kernel.
+        /// </summary>
+        /// <value>The kernel.</value>
+        private IKernel Kernel { get; set; }
+        /// <summary>
+        /// Gets or sets the logger.
+        /// </summary>
+        /// <value>The logger.</value>
+        private ILogger Logger { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ReloadLoggerFileTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="taskManager">The task manager.</param>
         /// <param name="logger">The logger.</param>
-        public ReloadLoggerFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger)
-            : base(kernel, taskManager, logger)
+        public ReloadLoggerFileTask(IKernel kernel, ILogger logger)
         {
+            Kernel = kernel;
+            Logger = logger;
         }
 
         /// <summary>
         /// Gets the default triggers.
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(0) }; //12am
 
@@ -41,7 +52,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
             cancellationToken.ThrowIfCancellationRequested();
 
@@ -54,7 +65,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the name.
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Start new log file"; }
         }
@@ -63,9 +74,18 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return "Moves logging to a new file to help reduce log file sizes."; }
         }
+
+        /// <summary>
+        /// Gets the category.
+        /// </summary>
+        /// <value>The category.</value>
+        public string Category
+        {
+            get { return "Application"; }
+        }
     }
 }

+ 28 - 8
MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs

@@ -11,31 +11,42 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
     /// <summary>
     /// Plugin Update Task
     /// </summary>
-    public class SystemUpdateTask : BaseScheduledTask<IKernel>
+    public class SystemUpdateTask : IScheduledTask
     {
         /// <summary>
         /// The _app host
         /// </summary>
         private readonly IApplicationHost _appHost;
 
+        /// <summary>
+        /// Gets or sets the kernel.
+        /// </summary>
+        /// <value>The kernel.</value>
+        private IKernel Kernel { get; set; }
+        /// <summary>
+        /// Gets or sets the logger.
+        /// </summary>
+        /// <value>The logger.</value>
+        private ILogger Logger { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SystemUpdateTask" /> class.
         /// </summary>
         /// <param name="appHost">The app host.</param>
-        /// <param name="taskManager">The task manager.</param>
         /// <param name="kernel">The kernel.</param>
         /// <param name="logger">The logger.</param>
-        public SystemUpdateTask(IApplicationHost appHost, ITaskManager taskManager, IKernel kernel, ILogger logger)
-            : base(kernel, taskManager, logger)
+        public SystemUpdateTask(IApplicationHost appHost, IKernel kernel, ILogger logger)
         {
             _appHost = appHost;
+            Kernel = kernel;
+            Logger = logger;
         }
 
         /// <summary>
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             return new ITaskTrigger[] { 
             
@@ -52,7 +63,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
             if (!_appHost.CanSelfUpdate) return;
 
@@ -105,7 +116,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the name of the task
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Check for application updates"; }
         }
@@ -114,9 +125,18 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return "Downloads and installs application updates."; }
         }
+
+        /// <summary>
+        /// Gets the category.
+        /// </summary>
+        /// <value>The category.</value>
+        public string Category
+        {
+            get { return "Application"; }
+        }
     }
 }

+ 4 - 12
MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs

@@ -17,12 +17,10 @@ namespace MediaBrowser.Common.Implementations.Serialization
         /// <summary>
         /// Serializes to stream.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="obj">The obj.</param>
         /// <param name="stream">The stream.</param>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        public void SerializeToStream<T>(T obj, Stream stream)
-            where T : class
+        public void SerializeToStream(object obj, Stream stream)
         {
             if (obj == null)
             {
@@ -40,12 +38,10 @@ namespace MediaBrowser.Common.Implementations.Serialization
         /// <summary>
         /// Serializes to file.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="obj">The obj.</param>
         /// <param name="file">The file.</param>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        public void SerializeToFile<T>(T obj, string file)
-            where T : class
+        public void SerializeToFile(object obj, string file)
         {
             if (obj == null)
             {
@@ -200,12 +196,10 @@ namespace MediaBrowser.Common.Implementations.Serialization
         /// <summary>
         /// Serializes to string.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="obj">The obj.</param>
         /// <returns>System.String.</returns>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        public string SerializeToString<T>(T obj)
-            where T : class
+        public string SerializeToString(object obj)
         {
             if (obj == null)
             {
@@ -218,12 +212,10 @@ namespace MediaBrowser.Common.Implementations.Serialization
         /// <summary>
         /// Serializes to bytes.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="obj">The obj.</param>
         /// <returns>System.Byte[][].</returns>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        public byte[] SerializeToBytes<T>(T obj)
-            where T : class
+        public byte[] SerializeToBytes(object obj)
         {
             if (obj == null)
             {

+ 1 - 0
MediaBrowser.Common.Implementations/packages.config

@@ -2,4 +2,5 @@
 <packages>
   <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" />
   <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" />
+  <package id="SimpleInjector" version="2.0.0-beta5" targetFramework="net45" />
 </packages>

+ 5 - 55
MediaBrowser.Common/Kernel/BaseKernel.cs

@@ -40,9 +40,6 @@ namespace MediaBrowser.Common.Kernel
         internal void OnConfigurationUpdated()
         {
             EventHelper.QueueEventIfNotNull(ConfigurationUpdated, this, EventArgs.Empty, Logger);
-
-            // Notify connected clients
-            TcpManager.SendWebSocketMessage("ConfigurationUpdated", Configuration);
         }
         #endregion
 
@@ -140,12 +137,6 @@ namespace MediaBrowser.Common.Kernel
             }
         }
 
-        /// <summary>
-        /// Gets a value indicating whether this instance is first run.
-        /// </summary>
-        /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
-        public bool IsFirstRun { get; private set; }
-
         /// <summary>
         /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
         /// </summary>
@@ -176,12 +167,6 @@ namespace MediaBrowser.Common.Kernel
         /// <value>The TCP manager.</value>
         public TcpManager TcpManager { get; private set; }
 
-        /// <summary>
-        /// Gets the rest services.
-        /// </summary>
-        /// <value>The rest services.</value>
-        public IEnumerable<IRestfulService> RestServices { get; private set; }
-
         /// <summary>
         /// Gets the UDP server port number.
         /// This can't be configurable because then the user would have to configure their client to discover the server.
@@ -280,19 +265,7 @@ namespace MediaBrowser.Common.Kernel
         /// Initializes the Kernel
         /// </summary>
         /// <returns>Task.</returns>
-        public Task Init()
-        {
-            IsFirstRun = !File.Exists(ApplicationPaths.SystemConfigurationFilePath);
-
-            // Performs initializations that can be reloaded at anytime
-            return Reload();
-        }
-
-        /// <summary>
-        /// Performs initializations that can be reloaded at anytime
-        /// </summary>
-        /// <returns>Task.</returns>
-        public async Task Reload()
+        public async Task Init()
         {
             OnReloadBeginning();
 
@@ -312,8 +285,6 @@ namespace MediaBrowser.Common.Kernel
             // Set these to null so that they can be lazy loaded again
             Configuration = null;
 
-            Logger.Info("Version {0} initializing", ApplicationVersion);
-
             await OnConfigurationLoaded().ConfigureAwait(false);
 
             FindParts();
@@ -348,7 +319,6 @@ namespace MediaBrowser.Common.Kernel
         /// </summary>
         protected virtual void FindParts()
         {
-            RestServices = ApplicationHost.GetExports<IRestfulService>();
             WebSocketListeners = ApplicationHost.GetExports<IWebSocketListener>();
             Plugins = ApplicationHost.GetExports<IPlugin>();
         }
@@ -425,18 +395,6 @@ namespace MediaBrowser.Common.Kernel
             }
         }
 
-        /// <summary>
-        /// Gets the current application version
-        /// </summary>
-        /// <value>The application version.</value>
-        public Version ApplicationVersion
-        {
-            get
-            {
-                return GetType().Assembly.GetName().Version;
-            }
-        }
-
         /// <summary>
         /// Performs the pending restart.
         /// </summary>
@@ -445,7 +403,9 @@ namespace MediaBrowser.Common.Kernel
         {
             if (HasPendingRestart)
             {
-                RestartApplication();
+                Logger.Info("Restarting the application");
+
+                ApplicationHost.Restart();
             }
             else
             {
@@ -453,16 +413,6 @@ namespace MediaBrowser.Common.Kernel
             }
         }
 
-        /// <summary>
-        /// Restarts the application.
-        /// </summary>
-        protected void RestartApplication()
-        {
-            Logger.Info("Restarting the application");
-
-            ApplicationHost.Restart();
-        }
-
         /// <summary>
         /// Gets the system status.
         /// </summary>
@@ -472,7 +422,7 @@ namespace MediaBrowser.Common.Kernel
             return new SystemInfo
             {
                 HasPendingRestart = HasPendingRestart,
-                Version = ApplicationVersion.ToString(),
+                Version = ApplicationHost.ApplicationVersion.ToString(),
                 IsNetworkDeployed = ApplicationHost.CanSelfUpdate,
                 WebSocketPortNumber = TcpManager.WebSocketPortNumber,
                 SupportsNativeWebSocket = TcpManager.SupportsNativeWebSocket,

+ 13 - 29
MediaBrowser.Common/Kernel/IApplicationHost.cs

@@ -21,6 +21,12 @@ namespace MediaBrowser.Common.Kernel
         /// </summary>
         void ReloadLogger();
 
+        /// <summary>
+        /// Gets the application version.
+        /// </summary>
+        /// <value>The application version.</value>
+        Version ApplicationVersion { get; }
+
         /// <summary>
         /// Gets the log file path.
         /// </summary>
@@ -33,11 +39,17 @@ namespace MediaBrowser.Common.Kernel
         /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
         bool CanSelfUpdate { get; }
 
+        /// <summary>
+        /// Gets a value indicating whether this instance is first run.
+        /// </summary>
+        /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
+        bool IsFirstRun { get; }
+
         /// <summary>
         /// Gets the failed assemblies.
         /// </summary>
         /// <value>The failed assemblies.</value>
-        IEnumerable<string> FailedAssemblies { get; }
+        List<string> FailedAssemblies { get; }
 
         /// <summary>
         /// Gets all concrete types.
@@ -72,34 +84,6 @@ namespace MediaBrowser.Common.Kernel
         /// <returns>System.Object.</returns>
         object CreateInstance(Type type);
 
-        /// <summary>
-        /// Registers a service that other classes can use as a dependancy.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="obj">The obj.</param>
-        void RegisterSingleInstance<T>(T obj) where T : class;
-
-        /// <summary>
-        /// Registers the single instance.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="func">The func.</param>
-        void RegisterSingleInstance<T>(Func<T> func) where T : class;
-        
-        /// <summary>
-        /// Registers the specified func.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="func">The func.</param>
-        void Register<T>(Func<T> func) where T : class;
-        
-        /// <summary>
-        /// Registers the specified service type.
-        /// </summary>
-        /// <param name="serviceType">Type of the service.</param>
-        /// <param name="implementation">Type of the implementation.</param>
-        void Register(Type serviceType, Type implementation);
-
         /// <summary>
         /// Resolves this instance.
         /// </summary>

+ 0 - 18
MediaBrowser.Common/Kernel/IKernel.cs

@@ -37,12 +37,6 @@ namespace MediaBrowser.Common.Kernel
         /// <returns>Task.</returns>
         Task Init();
 
-        /// <summary>
-        /// Reloads this instance.
-        /// </summary>
-        /// <returns>Task.</returns>
-        Task Reload();
-
         /// <summary>
         /// Gets or sets a value indicating whether this instance has pending kernel reload.
         /// </summary>
@@ -106,12 +100,6 @@ namespace MediaBrowser.Common.Kernel
         /// <value>The HTTP server URL prefix.</value>
         string HttpServerUrlPrefix { get; }
 
-        /// <summary>
-        /// Gets a value indicating whether this instance is first run.
-        /// </summary>
-        /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
-        bool IsFirstRun { get; }
-
         /// <summary>
         /// Gets the TCP manager.
         /// </summary>
@@ -139,12 +127,6 @@ namespace MediaBrowser.Common.Kernel
         /// </summary>
         event EventHandler<EventArgs> ConfigurationUpdated;
 
-        /// <summary>
-        /// Gets the rest services.
-        /// </summary>
-        /// <value>The rest services.</value>
-        IEnumerable<IRestfulService> RestServices { get; }
-
         /// <summary>
         /// Notifies the pending restart.
         /// </summary>

+ 3 - 3
MediaBrowser.Common/Kernel/TcpManager.cs

@@ -39,7 +39,7 @@ namespace MediaBrowser.Common.Kernel
         /// </summary>
         /// <value>The json serializer.</value>
         private readonly IJsonSerializer _jsonSerializer;
-        
+
         /// <summary>
         /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it
         /// </summary>
@@ -133,7 +133,7 @@ namespace MediaBrowser.Common.Kernel
             _applicationHost = applicationHost;
             _networkManager = networkManager;
 
-            if (kernel.IsFirstRun)
+            if (applicationHost.IsFirstRun)
             {
                 RegisterServerWithAdministratorAccess();
             }
@@ -215,7 +215,7 @@ namespace MediaBrowser.Common.Kernel
         /// <param name="e">The <see cref="WebSocketConnectEventArgs" /> instance containing the event data.</param>
         void HttpServer_WebSocketConnected(object sender, WebSocketConnectEventArgs e)
         {
-            var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, ProcessWebSocketMessageReceived, _jsonSerializer, _logger);
+            var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger) { OnReceive = ProcessWebSocketMessageReceived };
 
             _webSocketConnections.Add(connection);
         }

+ 2 - 5
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -95,8 +95,6 @@
     <Compile Include="Kernel\IApplicationHost.cs" />
     <Compile Include="Kernel\IKernel.cs" />
     <Compile Include="Kernel\TcpManager.cs" />
-    <Compile Include="Net\BaseRestService.cs" />
-    <Compile Include="Net\Handlers\BaseActionHandler.cs" />
     <Compile Include="Net\Handlers\IHttpServerHandler.cs" />
     <Compile Include="Net\Handlers\StaticFileHandler.cs" />
     <Compile Include="Net\IHttpClient.cs" />
@@ -122,6 +120,8 @@
       <DesignTime>True</DesignTime>
       <DependentUpon>Resources.resx</DependentUpon>
     </Compile>
+    <Compile Include="ScheduledTasks\IScheduledTask.cs" />
+    <Compile Include="ScheduledTasks\IScheduledTaskWorker.cs" />
     <Compile Include="ScheduledTasks\ITaskManager.cs" />
     <Compile Include="ScheduledTasks\ITaskTrigger.cs" />
     <Compile Include="ScheduledTasks\ScheduledTaskHelpers.cs" />
@@ -130,13 +130,10 @@
     <Compile Include="Kernel\BaseKernel.cs" />
     <Compile Include="Kernel\KernelContext.cs" />
     <Compile Include="Net\Handlers\BaseHandler.cs" />
-    <Compile Include="Net\Handlers\BaseSerializationHandler.cs" />
     <Compile Include="Plugins\BasePlugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="ScheduledTasks\BaseScheduledTask.cs" />
     <Compile Include="ScheduledTasks\DailyTrigger.cs" />
     <Compile Include="ScheduledTasks\IntervalTrigger.cs" />
-    <Compile Include="ScheduledTasks\IScheduledTask.cs" />
     <Compile Include="ScheduledTasks\WeeklyTrigger.cs" />
   </ItemGroup>
   <ItemGroup>

+ 0 - 31
MediaBrowser.Common/Net/Handlers/BaseActionHandler.cs

@@ -1,31 +0,0 @@
-using MediaBrowser.Common.Kernel;
-using MediaBrowser.Model.Entities;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Common.Net.Handlers
-{
-    /// <summary>
-    /// Class BaseActionHandler
-    /// </summary>
-    /// <typeparam name="TKernelType">The type of the T kernel type.</typeparam>
-    public abstract class BaseActionHandler<TKernelType> : BaseSerializationHandler<TKernelType, EmptyRequestResult>
-        where TKernelType : IKernel
-    {
-        /// <summary>
-        /// Gets the object to serialize.
-        /// </summary>
-        /// <returns>Task{EmptyRequestResult}.</returns>
-        protected override async Task<EmptyRequestResult> GetObjectToSerialize()
-        {
-            await ExecuteAction();
-
-            return new EmptyRequestResult();
-        }
-
-        /// <summary>
-        /// Performs the action.
-        /// </summary>
-        /// <returns>Task.</returns>
-        protected abstract Task ExecuteAction();
-    }
-}

+ 0 - 133
MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs

@@ -1,133 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Kernel;
-using System;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Common.Net.Handlers
-{
-    /// <summary>
-    /// Class BaseSerializationHandler
-    /// </summary>
-    /// <typeparam name="TKernelType">The type of the T kernel type.</typeparam>
-    /// <typeparam name="T"></typeparam>
-    public abstract class BaseSerializationHandler<TKernelType, T> : BaseHandler<TKernelType>
-        where TKernelType : IKernel
-        where T : class
-    {
-        /// <summary>
-        /// Gets the serialization format.
-        /// </summary>
-        /// <value>The serialization format.</value>
-        public SerializationFormat SerializationFormat
-        {
-            get
-            {
-                var format = QueryString["dataformat"];
-
-                if (string.IsNullOrEmpty(format))
-                {
-                    return SerializationFormat.Json;
-                }
-
-                return (SerializationFormat)Enum.Parse(typeof(SerializationFormat), format, true);
-            }
-        }
-
-        /// <summary>
-        /// Gets the type of the content.
-        /// </summary>
-        /// <value>The type of the content.</value>
-        protected string ContentType
-        {
-            get
-            {
-                switch (SerializationFormat)
-                {
-                    case SerializationFormat.Protobuf:
-                        return "application/x-protobuf";
-                    default:
-                        return MimeTypes.JsonMimeType;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets the response info.
-        /// </summary>
-        /// <returns>Task{ResponseInfo}.</returns>
-        protected override Task<ResponseInfo> GetResponseInfo()
-        {
-            return Task.FromResult(new ResponseInfo
-            {
-                ContentType = ContentType
-            });
-        }
-
-        /// <summary>
-        /// Called when [processing request].
-        /// </summary>
-        /// <param name="responseInfo">The response info.</param>
-        /// <returns>Task.</returns>
-        protected override async Task OnProcessingRequest(ResponseInfo responseInfo)
-        {
-            _objectToSerialize = await GetObjectToSerialize().ConfigureAwait(false);
-
-            if (_objectToSerialize == null)
-            {
-                throw new ResourceNotFoundException();
-            }
-
-            await base.OnProcessingRequest(responseInfo).ConfigureAwait(false);
-        }
-
-        /// <summary>
-        /// The _object to serialize
-        /// </summary>
-        private T _objectToSerialize;
-
-        /// <summary>
-        /// Gets the object to serialize.
-        /// </summary>
-        /// <returns>Task{`0}.</returns>
-        protected abstract Task<T> GetObjectToSerialize();
-
-        /// <summary>
-        /// Writes the response to output stream.
-        /// </summary>
-        /// <param name="stream">The stream.</param>
-        /// <param name="responseInfo">The response info.</param>
-        /// <param name="contentLength">Length of the content.</param>
-        /// <returns>Task.</returns>
-        protected override Task WriteResponseToOutputStream(Stream stream, ResponseInfo responseInfo, long? contentLength)
-        {
-            return Task.Run(() =>
-            {
-                //switch (SerializationFormat)
-                //{
-                //    case SerializationFormat.Protobuf:
-                //        Kernel.ProtobufSerializer.SerializeToStream(_objectToSerialize, stream);
-                //        break;
-                //    default:
-                //        JsonSerializer.SerializeToStream(_objectToSerialize, stream);
-                //        break;
-                //}
-            });
-        }
-    }
-
-    /// <summary>
-    /// Enum SerializationFormat
-    /// </summary>
-    public enum SerializationFormat
-    {
-        /// <summary>
-        /// The json
-        /// </summary>
-        Json,
-        /// <summary>
-        /// The protobuf
-        /// </summary>
-        Protobuf
-    }
-}

+ 3 - 5
MediaBrowser.Common/Net/IHttpClient.cs

@@ -6,6 +6,9 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Common.Net
 {
+    /// <summary>
+    /// Interface IHttpClient
+    /// </summary>
     public interface IHttpClient : IDisposable
     {
         /// <summary>
@@ -52,10 +55,5 @@ namespace MediaBrowser.Common.Net
         /// <returns>Task{MemoryStream}.</returns>
         /// <exception cref="MediaBrowser.Model.Net.HttpException"></exception>
         Task<MemoryStream> GetMemoryStream(string url, SemaphoreSlim resourcePool, CancellationToken cancellationToken);
-
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        void Dispose();
     }
 }

+ 6 - 0
MediaBrowser.Common/Net/IHttpServer.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 
 namespace MediaBrowser.Common.Net
 {
@@ -40,5 +41,10 @@ namespace MediaBrowser.Common.Net
         /// Occurs when [web socket connected].
         /// </summary>
         event EventHandler<WebSocketConnectEventArgs> WebSocketConnected;
+
+        /// <summary>
+        /// Inits this instance.
+        /// </summary>
+        void Init(IEnumerable<IRestfulService> services);
     }
 }

+ 0 - 2
MediaBrowser.Common/Net/IRestfulService.cs

@@ -1,5 +1,4 @@
 using ServiceStack.ServiceHost;
-using ServiceStack.WebHost.Endpoints;
 using System;
 
 namespace MediaBrowser.Common.Net
@@ -9,6 +8,5 @@ namespace MediaBrowser.Common.Net
     /// </summary>
     public interface IRestfulService : IService, IRequiresRequestContext, IDisposable
     {
-        void Configure(IAppHost appHost);
     }
 }

+ 16 - 12
MediaBrowser.Common/Net/WebSocketConnection.cs

@@ -41,17 +41,22 @@ namespace MediaBrowser.Common.Net
         /// The _json serializer
         /// </summary>
         private readonly IJsonSerializer _jsonSerializer;
-        
+
+        /// <summary>
+        /// Gets or sets the receive action.
+        /// </summary>
+        /// <value>The receive action.</value>
+        public Action<WebSocketMessageInfo> OnReceive { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
         /// </summary>
         /// <param name="socket">The socket.</param>
         /// <param name="remoteEndPoint">The remote end point.</param>
-        /// <param name="receiveAction">The receive action.</param>
         /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">socket</exception>
-        public WebSocketConnection(IWebSocket socket, string remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, IJsonSerializer jsonSerializer, ILogger logger)
+        public WebSocketConnection(IWebSocket socket, string remoteEndPoint, IJsonSerializer jsonSerializer, ILogger logger)
         {
             if (socket == null)
             {
@@ -61,10 +66,6 @@ namespace MediaBrowser.Common.Net
             {
                 throw new ArgumentNullException("remoteEndPoint");
             }
-            if (receiveAction == null)
-            {
-                throw new ArgumentNullException("receiveAction");
-            }
             if (jsonSerializer == null)
             {
                 throw new ArgumentNullException("jsonSerializer");
@@ -76,7 +77,7 @@ namespace MediaBrowser.Common.Net
 
             _jsonSerializer = jsonSerializer;
             _socket = socket;
-            _socket.OnReceiveDelegate = info => OnReceive(info, receiveAction);
+            _socket.OnReceiveDelegate = OnReceiveInternal;
             RemoteEndPoint = remoteEndPoint;
             _logger = logger;
         }
@@ -85,21 +86,24 @@ namespace MediaBrowser.Common.Net
         /// Called when [receive].
         /// </summary>
         /// <param name="bytes">The bytes.</param>
-        /// <param name="callback">The callback.</param>
-        private void OnReceive(byte[] bytes, Action<WebSocketMessageInfo> callback)
+        private void OnReceiveInternal(byte[] bytes)
         {
+            if (OnReceive == null)
+            {
+                return;
+            }
             try
             {
                 WebSocketMessageInfo info;
 
                 using (var memoryStream = new MemoryStream(bytes))
                 {
-                    info = _jsonSerializer.DeserializeFromStream<WebSocketMessageInfo>(memoryStream);
+                    info = (WebSocketMessageInfo)_jsonSerializer.DeserializeFromStream(memoryStream, typeof(WebSocketMessageInfo));
                 }
 
                 info.Connection = this;
 
-                callback(info);
+                OnReceive(info);
             }
             catch (Exception ex)
             {

+ 1 - 4
MediaBrowser.Common/Plugins/BasePlugin.cs

@@ -1,12 +1,12 @@
 using MediaBrowser.Common.Kernel;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.IO;
 using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Threading;
-using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Common.Plugins
 {
@@ -393,9 +393,6 @@ namespace MediaBrowser.Common.Plugins
             {
                 XmlSerializer.SerializeToFile(Configuration, ConfigurationFilePath);
             }
-
-            // Notify connected UI's
-            Kernel.TcpManager.SendWebSocketMessage("PluginConfigurationUpdated-" + Name, Configuration);
         }
 
         /// <summary>

+ 8 - 48
MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs

@@ -1,39 +1,15 @@
-using MediaBrowser.Model.Tasks;
-using System;
+using System;
 using System.Collections.Generic;
+using System.Threading;
 using System.Threading.Tasks;
 
 namespace MediaBrowser.Common.ScheduledTasks
 {
     /// <summary>
-    /// Interface IScheduledTask
+    /// Interface IScheduledTaskWorker
     /// </summary>
-    public interface IScheduledTask : IDisposable
+    public interface IScheduledTask
     {
-        /// <summary>
-        /// Gets the triggers.
-        /// </summary>
-        /// <value>The triggers.</value>
-        IEnumerable<ITaskTrigger> Triggers { get; set; }
-
-        /// <summary>
-        /// Gets the last execution result.
-        /// </summary>
-        /// <value>The last execution result.</value>
-        TaskResult LastExecutionResult { get; }
-
-        /// <summary>
-        /// Gets the state.
-        /// </summary>
-        /// <value>The state.</value>
-        TaskState State { get; }
-
-        /// <summary>
-        /// Gets the current progress.
-        /// </summary>
-        /// <value>The current progress.</value>
-        double? CurrentProgress { get; }
-
         /// <summary>
         /// Gets the name of the task
         /// </summary>
@@ -52,29 +28,13 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <value>The category.</value>
         string Category { get; }
 
-        /// <summary>
-        /// Gets the unique id.
-        /// </summary>
-        /// <value>The unique id.</value>
-        Guid Id { get; }
-
         /// <summary>
         /// Executes the task
         /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        /// <exception cref="System.InvalidOperationException">Cannot execute a Task that is already running</exception>
-        Task Execute();
-
-        /// <summary>
-        /// Stops the task if it is currently executing
-        /// </summary>
-        /// <exception cref="System.InvalidOperationException">Cannot cancel a Task unless it is in the Running state.</exception>
-        void Cancel();
-
-        /// <summary>
-        /// Cancels if running.
-        /// </summary>
-        void CancelIfRunning();
+        Task Execute(CancellationToken cancellationToken, IProgress<double> progress);
 
         /// <summary>
         /// Gets the default triggers.
@@ -82,4 +42,4 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
         IEnumerable<ITaskTrigger> GetDefaultTriggers();
     }
-}
+}

+ 86 - 0
MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs

@@ -0,0 +1,86 @@
+using MediaBrowser.Model.Tasks;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Common.ScheduledTasks
+{
+    /// <summary>
+    /// Interface IScheduledTaskWorker
+    /// </summary>
+    public interface IScheduledTaskWorker : IDisposable
+    {
+        /// <summary>
+        /// Gets or sets the scheduled task.
+        /// </summary>
+        /// <value>The scheduled task.</value>
+        IScheduledTask ScheduledTask { get; }
+
+        /// <summary>
+        /// Gets the last execution result.
+        /// </summary>
+        /// <value>The last execution result.</value>
+        TaskResult LastExecutionResult { get; }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        string Name { get; }
+
+        /// <summary>
+        /// Gets the description.
+        /// </summary>
+        /// <value>The description.</value>
+        string Description { get; }
+
+        /// <summary>
+        /// Gets the category.
+        /// </summary>
+        /// <value>The category.</value>
+        string Category { get; }
+
+        /// <summary>
+        /// Gets the state.
+        /// </summary>
+        /// <value>The state.</value>
+        TaskState State { get; }
+
+        /// <summary>
+        /// Gets the current progress.
+        /// </summary>
+        /// <value>The current progress.</value>
+        double? CurrentProgress { get; }
+
+        /// <summary>
+        /// Gets the triggers that define when the task will run
+        /// </summary>
+        /// <value>The triggers.</value>
+        /// <exception cref="System.ArgumentNullException">value</exception>
+        IEnumerable<ITaskTrigger> Triggers { get; set; }
+
+        /// <summary>
+        /// Gets the unique id.
+        /// </summary>
+        /// <value>The unique id.</value>
+        Guid Id { get; }
+
+        /// <summary>
+        /// Executes the task
+        /// </summary>
+        /// <returns>Task.</returns>
+        /// <exception cref="System.InvalidOperationException">Cannot execute a Task that is already running</exception>
+        Task Execute();
+
+        /// <summary>
+        /// Stops the task if it is currently executing
+        /// </summary>
+        /// <exception cref="System.InvalidOperationException">Cannot cancel a Task unless it is in the Running state.</exception>
+        void Cancel();
+
+        /// <summary>
+        /// Cancels if running.
+        /// </summary>
+        void CancelIfRunning();
+    }
+}

+ 2 - 33
MediaBrowser.Common/ScheduledTasks/ITaskManager.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Model.Tasks;
-using System;
+using System;
 using System.Collections.Generic;
 
 namespace MediaBrowser.Common.ScheduledTasks
@@ -10,7 +9,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Gets the list of Scheduled Tasks
         /// </summary>
         /// <value>The scheduled tasks.</value>
-        IScheduledTask[] ScheduledTasks { get; }
+        IScheduledTaskWorker[] ScheduledTasks { get; }
 
         /// <summary>
         /// Cancels if running and queue.
@@ -37,35 +36,5 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// </summary>
         /// <param name="tasks">The tasks.</param>
         void AddTasks(IEnumerable<IScheduledTask> tasks);
-
-        /// <summary>
-        /// Called when [task completed].
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <param name="startTime">The start time.</param>
-        /// <param name="endTime">The end time.</param>
-        /// <param name="status">The status.</param>
-        void OnTaskCompleted(IScheduledTask task, DateTime startTime, DateTime endTime, TaskCompletionStatus status);
-
-        /// <summary>
-        /// Gets the last execution result.
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <returns>TaskResult.</returns>
-        TaskResult GetLastExecutionResult(IScheduledTask task);
-
-        /// <summary>
-        /// Loads the triggers.
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        IEnumerable<ITaskTrigger> LoadTriggers(IScheduledTask task);
-
-        /// <summary>
-        /// Saves the triggers.
-        /// </summary>
-        /// <param name="task">The task.</param>
-        /// <param name="triggers">The triggers.</param>
-        void SaveTriggers(IScheduledTask task, IEnumerable<ITaskTrigger> triggers);
     }
 }

+ 1 - 1
MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs

@@ -14,7 +14,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// </summary>
         /// <param name="task">The task.</param>
         /// <returns>TaskInfo.</returns>
-        public static TaskInfo GetTaskInfo(IScheduledTask task)
+        public static TaskInfo GetTaskInfo(IScheduledTaskWorker task)
         {
             return new TaskInfo
             {

+ 0 - 4
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -132,7 +132,6 @@
     <Compile Include="Persistence\IRepository.cs" />
     <Compile Include="Persistence\IUserDataRepository.cs" />
     <Compile Include="Persistence\IUserRepository.cs" />
-    <Compile Include="Persistence\TypeMapper.cs" />
     <Compile Include="Playback\IIntroProvider.cs" />
     <Compile Include="Plugins\IPluginConfigurationPage.cs" />
     <Compile Include="Plugins\PluginSecurityManager.cs" />
@@ -179,10 +178,7 @@
     <Compile Include="Resolvers\TV\SeriesResolver.cs" />
     <Compile Include="Resolvers\TV\TVUtils.cs" />
     <Compile Include="Library\ResourcePool.cs" />
-    <Compile Include="ScheduledTasks\ChapterImagesTask.cs" />
-    <Compile Include="ScheduledTasks\ImageCleanupTask.cs" />
     <Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
-    <Compile Include="ScheduledTasks\PluginUpdateTask.cs" />
     <Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" />
     <Compile Include="Library\ItemResolveArgs.cs" />
     <Compile Include="IO\DirectoryWatchers.cs" />

+ 11 - 11
MediaBrowser.Controller/Plugins/PluginSecurityManager.cs

@@ -1,4 +1,5 @@
-using Mediabrowser.Model.Entities;
+using MediaBrowser.Model.Serialization;
+using Mediabrowser.Model.Entities;
 using Mediabrowser.PluginSecurity;
 using MediaBrowser.Common.Kernel;
 using MediaBrowser.Common.Net;
@@ -39,10 +40,8 @@ namespace MediaBrowser.Controller.Plugins
             }
         }
 
-        /// <summary>
-        /// The _network manager
-        /// </summary>
-        private INetworkManager _networkManager;
+        private IHttpClient _httpClient;
+        private IJsonSerializer _jsonSerializer;
 
         /// <summary>
         /// The _kernel
@@ -53,21 +52,22 @@ namespace MediaBrowser.Controller.Plugins
         /// Initializes a new instance of the <see cref="PluginSecurityManager" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="networkManager">The network manager.</param>
-        public PluginSecurityManager(IKernel kernel, INetworkManager networkManager)
+        public PluginSecurityManager(IKernel kernel, IHttpClient httpClient, IJsonSerializer jsonSerializer, IApplicationPaths appPaths)
         {
             if (kernel == null)
             {
                 throw new ArgumentNullException("kernel");
             }
 
-            if (networkManager == null)
+            if (httpClient == null)
             {
-                throw new ArgumentNullException("networkManager");
+                throw new ArgumentNullException("httpClient");
             }
             
             _kernel = kernel;
-            _networkManager = networkManager;
+            _httpClient = httpClient;
+            _jsonSerializer = jsonSerializer;
+            MBRegistration.Init(appPaths);
         }
 
         /// <summary>
@@ -78,7 +78,7 @@ namespace MediaBrowser.Controller.Plugins
         /// <returns>Task{MBRegistrationRecord}.</returns>
         public async Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent = null)
         {
-            return await MBRegistration.GetRegistrationStatus(feature, mb2Equivalent).ConfigureAwait(false);
+            return await MBRegistration.GetRegistrationStatus(_httpClient, _jsonSerializer, feature, mb2Equivalent).ConfigureAwait(false);
         }
 
         /// <summary>

+ 11 - 11
MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
 using System.Threading;
@@ -10,23 +9,24 @@ namespace MediaBrowser.Controller.ScheduledTasks
     /// <summary>
     /// Class PeopleValidationTask
     /// </summary>
-    public class PeopleValidationTask : BaseScheduledTask<Kernel>
+    public class PeopleValidationTask : IScheduledTask
     {
+        private readonly Kernel _kernel;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="PeopleValidationTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="logger"></param>
-        public PeopleValidationTask(Kernel kernel, ITaskManager taskManager, ILogger logger)
-            : base(kernel, taskManager, logger)
+        public PeopleValidationTask(Kernel kernel)
         {
+            _kernel = kernel;
         }
 
         /// <summary>
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             return new ITaskTrigger[]
                 {
@@ -42,16 +42,16 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
-            return Kernel.LibraryManager.ValidatePeople(cancellationToken, progress);
+            return _kernel.LibraryManager.ValidatePeople(cancellationToken, progress);
         }
 
         /// <summary>
         /// Gets the name of the task
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Refresh people"; }
         }
@@ -60,7 +60,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return "Updates metadata for actors, artists and directors in your media library."; }
         }
@@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the category.
         /// </summary>
         /// <value>The category.</value>
-        public override string Category
+        public string Category
         {
             get
             {

+ 14 - 11
MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Tasks;
 using System;
 using System.Collections.Generic;
@@ -11,23 +10,27 @@ namespace MediaBrowser.Controller.ScheduledTasks
     /// <summary>
     /// Class RefreshMediaLibraryTask
     /// </summary>
-    public class RefreshMediaLibraryTask : BaseScheduledTask<Kernel>
+    public class RefreshMediaLibraryTask : IScheduledTask
     {
+        /// <summary>
+        /// The _kernel
+        /// </summary>
+        private readonly Kernel _kernel;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="RefreshMediaLibraryTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="logger"></param>
-        public RefreshMediaLibraryTask(Kernel kernel, ITaskManager taskManager, ILogger logger)
-            : base(kernel, taskManager, logger)
+        public RefreshMediaLibraryTask(Kernel kernel)
         {
+            _kernel = kernel;
         }
 
         /// <summary>
         /// Gets the default triggers.
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             return new ITaskTrigger[] { 
 
@@ -45,20 +48,20 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
             cancellationToken.ThrowIfCancellationRequested();
 
             progress.Report(0);
 
-            return Kernel.LibraryManager.ValidateMediaLibrary(progress, cancellationToken);
+            return _kernel.LibraryManager.ValidateMediaLibrary(progress, cancellationToken);
         }
 
         /// <summary>
         /// Gets the name.
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Scan media library"; }
         }
@@ -67,7 +70,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return "Scans your media library and refreshes metatata based on configuration."; }
         }
@@ -76,7 +79,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the category.
         /// </summary>
         /// <value>The category.</value>
-        public override string Category
+        public string Category
         {
             get
             {

+ 11 - 2
MediaBrowser.Controller/Updates/InstallationManager.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Kernel;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Progress;
@@ -119,6 +120,12 @@ namespace MediaBrowser.Controller.Updates
         /// <value>The HTTP client.</value>
         protected IHttpClient HttpClient { get; private set; }
 
+        /// <summary>
+        /// Gets the application host.
+        /// </summary>
+        /// <value>The application host.</value>
+        protected IApplicationHost ApplicationHost { get; private set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="InstallationManager" /> class.
         /// </summary>
@@ -128,8 +135,9 @@ namespace MediaBrowser.Controller.Updates
         /// <param name="networkManager">The network manager.</param>
         /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logger">The logger.</param>
+        /// <param name="appHost">The app host.</param>
         /// <exception cref="System.ArgumentNullException">zipClient</exception>
-        public InstallationManager(Kernel kernel, IHttpClient httpClient, IZipClient zipClient, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger)
+        public InstallationManager(Kernel kernel, IHttpClient httpClient, IZipClient zipClient, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost)
             : base(kernel)
         {
             if (zipClient == null)
@@ -155,6 +163,7 @@ namespace MediaBrowser.Controller.Updates
 
             JsonSerializer = jsonSerializer;
             HttpClient = httpClient;
+            ApplicationHost = appHost;
             _networkManager = networkManager;
             _logger = logger;
             ZipClient = zipClient;
@@ -276,7 +285,7 @@ namespace MediaBrowser.Controller.Updates
 
             return package.versions
                 .OrderByDescending(v => v.version)
-                .FirstOrDefault(v => v.classification <= classification && IsPackageVersionUpToDate(v, Kernel.ApplicationVersion));
+                .FirstOrDefault(v => v.classification <= classification && IsPackageVersionUpToDate(v, ApplicationHost.ApplicationVersion));
         }
 
         /// <summary>

+ 4 - 12
MediaBrowser.Model/Serialization/IJsonSerializer.cs

@@ -8,22 +8,18 @@ namespace MediaBrowser.Model.Serialization
         /// <summary>
         /// Serializes to stream.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="obj">The obj.</param>
         /// <param name="stream">The stream.</param>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        void SerializeToStream<T>(T obj, Stream stream)
-            where T : class;
+        void SerializeToStream(object obj, Stream stream);
 
         /// <summary>
         /// Serializes to file.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="obj">The obj.</param>
         /// <param name="file">The file.</param>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        void SerializeToFile<T>(T obj, string file)
-            where T : class;
+        void SerializeToFile(object obj, string file);
 
         /// <summary>
         /// Deserializes from file.
@@ -83,21 +79,17 @@ namespace MediaBrowser.Model.Serialization
         /// <summary>
         /// Serializes to string.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="obj">The obj.</param>
         /// <returns>System.String.</returns>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        string SerializeToString<T>(T obj)
-            where T : class;
+        string SerializeToString(object obj);
 
         /// <summary>
         /// Serializes to bytes.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="obj">The obj.</param>
         /// <returns>System.Byte[][].</returns>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        byte[] SerializeToBytes<T>(T obj)
-            where T : class;
+        byte[] SerializeToBytes(object obj);
     }
 }

+ 4 - 9
MediaBrowser.Common/Net/BaseRestService.cs → MediaBrowser.Networking/HttpServer/BaseRestService.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Model.Logging;
 using ServiceStack.Common;
 using ServiceStack.Common.Web;
@@ -13,8 +14,10 @@ using System.IO;
 using System.Linq;
 using System.Net;
 using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Common.Net.MimeTypes;
+using StreamWriter = MediaBrowser.Common.Net.StreamWriter;
 
-namespace MediaBrowser.Common.Net
+namespace MediaBrowser.Networking.HttpServer
 {
     /// <summary>
     /// Class BaseRestService
@@ -45,14 +48,6 @@ namespace MediaBrowser.Common.Net
             }
         }
 
-        /// <summary>
-        /// Adds the routes.
-        /// </summary>
-        /// <param name="appHost">The app host.</param>
-        public virtual void Configure(IAppHost appHost)
-        {
-        }
-
         /// <summary>
         /// To the optimized result.
         /// </summary>

+ 20 - 23
MediaBrowser.Networking/HttpServer/HttpServer.cs

@@ -1,4 +1,3 @@
-using System.Net.WebSockets;
 using Funq;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Kernel;
@@ -16,10 +15,12 @@ using ServiceStack.WebHost.Endpoints;
 using ServiceStack.WebHost.Endpoints.Extensions;
 using ServiceStack.WebHost.Endpoints.Support;
 using System;
+using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Net;
+using System.Net.WebSockets;
 using System.Reactive.Linq;
 using System.Reflection;
 using System.Text;
@@ -44,10 +45,9 @@ namespace MediaBrowser.Networking.HttpServer
         public string UrlPrefix { get; private set; }
 
         /// <summary>
-        /// Gets or sets the kernel.
+        /// The _rest services
         /// </summary>
-        /// <value>The kernel.</value>
-        private IKernel Kernel { get; set; }
+        private readonly List<IRestfulService> _restServices = new List<IRestfulService>(); 
 
         /// <summary>
         /// Gets or sets the application host.
@@ -88,19 +88,14 @@ namespace MediaBrowser.Networking.HttpServer
         /// Initializes a new instance of the <see cref="HttpServer" /> class.
         /// </summary>
         /// <param name="applicationHost">The application host.</param>
-        /// <param name="kernel">The kernel.</param>
         /// <param name="protobufSerializer">The protobuf serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="serverName">Name of the server.</param>
         /// <param name="defaultRedirectpath">The default redirectpath.</param>
         /// <exception cref="System.ArgumentNullException">urlPrefix</exception>
-        public HttpServer(IApplicationHost applicationHost, IKernel kernel, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath)
+        public HttpServer(IApplicationHost applicationHost, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath)
             : base()
         {
-            if (kernel == null)
-            {
-                throw new ArgumentNullException("kernel");
-            }
             if (protobufSerializer == null)
             {
                 throw new ArgumentNullException("protobufSerializer");
@@ -130,13 +125,6 @@ namespace MediaBrowser.Networking.HttpServer
 
             EndpointHostConfig.Instance.ServiceStackHandlerFactoryPath = null;
             EndpointHostConfig.Instance.MetadataRedirectPath = "metadata";
-
-            Kernel = kernel;
-
-            EndpointHost.ConfigureHost(this, ServerName, CreateServiceManager());
-            ContentTypeFilters.Register(ContentType.ProtoBuf, (reqCtx, res, stream) => ProtobufSerializer.SerializeToStream(res, stream), (type, stream) => ProtobufSerializer.DeserializeFromStream(stream, type));
-
-            Init();
         }
 
         /// <summary>
@@ -161,11 +149,6 @@ namespace MediaBrowser.Networking.HttpServer
 
             container.Adapter = new ContainerAdapter(ApplicationHost);
 
-            foreach (var service in Kernel.RestServices)
-            {
-                service.Configure(this);
-            }
-
             Plugins.Add(new SwaggerFeature());
             Plugins.Add(new CorsFeature());
 
@@ -450,7 +433,7 @@ namespace MediaBrowser.Networking.HttpServer
         /// <returns>ServiceManager.</returns>
         protected override ServiceManager CreateServiceManager(params Assembly[] assembliesWithServices)
         {
-            var types = Kernel.RestServices.Select(r => r.GetType()).ToArray();
+            var types = _restServices.Select(r => r.GetType()).ToArray();
 
             return new ServiceManager(new Container(), new ServiceController(() => types));
         }
@@ -511,6 +494,20 @@ namespace MediaBrowser.Networking.HttpServer
         /// </summary>
         /// <value><c>true</c> if [enable HTTP request logging]; otherwise, <c>false</c>.</value>
         public bool EnableHttpRequestLogging { get; set; }
+
+        /// <summary>
+        /// Adds the rest handlers.
+        /// </summary>
+        /// <param name="services">The services.</param>
+        public void Init(IEnumerable<IRestfulService> services)
+        {
+            _restServices.AddRange(services);
+
+            EndpointHost.ConfigureHost(this, ServerName, CreateServiceManager());
+            ContentTypeFilters.Register(ContentType.ProtoBuf, (reqCtx, res, stream) => ProtobufSerializer.SerializeToStream(res, stream), (type, stream) => ProtobufSerializer.DeserializeFromStream(stream, type));
+            
+            Init();
+        }
     }
 
     /// <summary>

+ 2 - 3
MediaBrowser.Networking/HttpServer/ServerFactory.cs

@@ -14,15 +14,14 @@ namespace MediaBrowser.Networking.HttpServer
         /// Creates the server.
         /// </summary>
         /// <param name="applicationHost">The application host.</param>
-        /// <param name="kernel">The kernel.</param>
         /// <param name="protobufSerializer">The protobuf serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="serverName">Name of the server.</param>
         /// <param name="defaultRedirectpath">The default redirectpath.</param>
         /// <returns>IHttpServer.</returns>
-        public static IHttpServer CreateServer(IApplicationHost applicationHost, IKernel kernel, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath)
+        public static IHttpServer CreateServer(IApplicationHost applicationHost, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath)
         {
-            return new HttpServer(applicationHost, kernel, protobufSerializer, logger, serverName, defaultRedirectpath);
+            return new HttpServer(applicationHost, protobufSerializer, logger, serverName, defaultRedirectpath);
         }
     }
 }

+ 1 - 0
MediaBrowser.Networking/MediaBrowser.Networking.csproj

@@ -107,6 +107,7 @@
       <Link>Properties\SharedVersion.cs</Link>
     </Compile>
     <Compile Include="HttpManager\HttpManager.cs" />
+    <Compile Include="HttpServer\BaseRestService.cs" />
     <Compile Include="Udp\UdpServer.cs" />
     <Compile Include="WebSocket\AlchemyServer.cs" />
     <Compile Include="WebSocket\AlchemyWebSocket.cs" />

+ 4 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -51,6 +51,10 @@
       <Link>Properties\SharedVersion.cs</Link>
     </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Reflection\TypeMapper.cs" />
+    <Compile Include="ScheduledTasks\Tasks\ChapterImagesTask.cs" />
+    <Compile Include="ScheduledTasks\Tasks\ImageCleanupTask.cs" />
+    <Compile Include="ScheduledTasks\Tasks\PluginUpdateTask.cs" />
     <Compile Include="ServerApplicationPaths.cs" />
     <Compile Include="Sqlite\SQLiteDisplayPreferencesRepository.cs" />
     <Compile Include="Sqlite\SQLiteExtensions.cs" />

+ 1 - 1
MediaBrowser.Controller/Persistence/TypeMapper.cs → MediaBrowser.Server.Implementations/Reflection/TypeMapper.cs

@@ -2,7 +2,7 @@
 using System.Collections.Concurrent;
 using System.Linq;
 
-namespace MediaBrowser.Controller.Persistence
+namespace MediaBrowser.Server.Implementations.Reflection
 {
     /// <summary>
     /// Class TypeMapper

+ 24 - 13
MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs → MediaBrowser.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Logging;
 using System;
@@ -7,28 +8,38 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Controller.ScheduledTasks
+namespace MediaBrowser.Server.Implementations.ScheduledTasks.Tasks
 {
     /// <summary>
     /// Class ChapterImagesTask
     /// </summary>
-    class ChapterImagesTask : BaseScheduledTask<Kernel>
+    class ChapterImagesTask : IScheduledTask
     {
+        /// <summary>
+        /// The _kernel
+        /// </summary>
+        private readonly Kernel _kernel;
+        /// <summary>
+        /// The _logger
+        /// </summary>
+        private readonly ILogger _logger;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ChapterImagesTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="logger"></param>
-        public ChapterImagesTask(Kernel kernel, ITaskManager taskManager, ILogger logger)
-            : base(kernel, taskManager, logger)
+        /// <param name="logger">The logger.</param>
+        public ChapterImagesTask(Kernel kernel, ILogger logger)
         {
+            _kernel = kernel;
+            _logger = logger;
         }
 
         /// <summary>
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             return new ITaskTrigger[]
                 {
@@ -42,9 +53,9 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
-            var videos = Kernel.RootFolder.RecursiveChildren.OfType<Video>().Where(v => v.Chapters != null).ToList();
+            var videos = _kernel.RootFolder.RecursiveChildren.OfType<Video>().Where(v => v.Chapters != null).ToList();
 
             var numComplete = 0;
 
@@ -52,7 +63,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
             {
                 try
                 {
-                    await Kernel.FFMpegManager.PopulateChapterImages(v, cancellationToken, true, true);
+                    await _kernel.FFMpegManager.PopulateChapterImages(v, cancellationToken, true, true);
                 }
                 catch (OperationCanceledException)
                 {
@@ -60,7 +71,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
                 }
                 catch (Exception ex)
                 {
-                    Logger.ErrorException("Error creating chapter images for {0}", ex, v.Name);
+                    _logger.ErrorException("Error creating chapter images for {0}", ex, v.Name);
                 }
                 finally
                 {
@@ -82,7 +93,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the name of the task
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Create video chapter thumbnails"; }
         }
@@ -91,7 +102,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return "Creates thumbnails for videos that have chapters."; }
         }
@@ -100,7 +111,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the category.
         /// </summary>
         /// <value>The category.</value>
-        public override string Category
+        public string Category
         {
             get
             {

+ 28 - 18
MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs → MediaBrowser.Server.Implementations/ScheduledTasks/Tasks/ImageCleanupTask.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Model.Logging;
@@ -9,29 +10,38 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Controller.ScheduledTasks
+namespace MediaBrowser.Server.Implementations.ScheduledTasks.Tasks
 {
     /// <summary>
     /// Class ImageCleanupTask
     /// </summary>
-    public class ImageCleanupTask : BaseScheduledTask<Kernel>
+    public class ImageCleanupTask : IScheduledTask
     {
+        /// <summary>
+        /// The _kernel
+        /// </summary>
+        private readonly Kernel _kernel;
+        /// <summary>
+        /// The _logger
+        /// </summary>
+        private readonly ILogger _logger;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageCleanupTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="taskManager">The task manager.</param>
         /// <param name="logger">The logger.</param>
-        public ImageCleanupTask(Kernel kernel, ITaskManager taskManager, ILogger logger)
-            : base(kernel, taskManager, logger)
+        public ImageCleanupTask(Kernel kernel, ILogger logger)
         {
+            _kernel = kernel;
+            _logger = logger;
         }
 
         /// <summary>
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             return new ITaskTrigger[]
                 {
@@ -45,19 +55,19 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
             await EnsureChapterImages(cancellationToken).ConfigureAwait(false);
 
             // First gather all image files
-            var files = GetFiles(Kernel.FFMpegManager.AudioImagesDataPath)
-                .Concat(GetFiles(Kernel.FFMpegManager.VideoImagesDataPath))
-                .Concat(GetFiles(Kernel.ProviderManager.ImagesDataPath))
+            var files = GetFiles(_kernel.FFMpegManager.AudioImagesDataPath)
+                .Concat(GetFiles(_kernel.FFMpegManager.VideoImagesDataPath))
+                .Concat(GetFiles(_kernel.ProviderManager.ImagesDataPath))
                 .ToList();
 
             // Now gather all items
-            var items = Kernel.RootFolder.RecursiveChildren.ToList();
-            items.Add(Kernel.RootFolder);
+            var items = _kernel.RootFolder.RecursiveChildren.ToList();
+            items.Add(_kernel.RootFolder);
 
             // Determine all possible image paths
             var pathsInUse = items.SelectMany(GetPathsInUse)
@@ -80,7 +90,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
                     }
                     catch (IOException ex)
                     {
-                        Logger.ErrorException("Error deleting {0}", ex, file);
+                        _logger.ErrorException("Error deleting {0}", ex, file);
                     }
                 }
 
@@ -105,11 +115,11 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <returns>Task.</returns>
         private Task EnsureChapterImages(CancellationToken cancellationToken)
         {
-            var videos = Kernel.RootFolder.RecursiveChildren.OfType<Video>().Where(v => v.Chapters != null).ToList();
+            var videos = _kernel.RootFolder.RecursiveChildren.OfType<Video>().Where(v => v.Chapters != null).ToList();
 
             var tasks = videos.Select(v => Task.Run(async () =>
             {
-                await Kernel.FFMpegManager.PopulateChapterImages(v, cancellationToken, false, true);
+                await _kernel.FFMpegManager.PopulateChapterImages(v, cancellationToken, false, true);
             }));
 
             return Task.WhenAll(tasks);
@@ -181,7 +191,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the name of the task
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Images cleanup"; }
         }
@@ -190,7 +200,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return "Deletes downloaded and extracted images that are no longer being used."; }
         }
@@ -199,7 +209,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the category.
         /// </summary>
         /// <value>The category.</value>
-        public override string Category
+        public string Category
         {
             get
             {

+ 27 - 12
MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs → MediaBrowser.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs

@@ -13,23 +13,33 @@ namespace MediaBrowser.Controller.ScheduledTasks
     /// <summary>
     /// Plugin Update Task
     /// </summary>
-    public class PluginUpdateTask : BaseScheduledTask<Kernel>
+    public class PluginUpdateTask : IScheduledTask
     {
+        /// <summary>
+        /// The _kernel
+        /// </summary>
+        private readonly Kernel _kernel;
+        /// <summary>
+        /// The _logger
+        /// </summary>
+        private readonly ILogger _logger;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="PluginUpdateTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="logger"></param>
-        public PluginUpdateTask(Kernel kernel, ITaskManager taskManager, ILogger logger)
-            : base(kernel, taskManager, logger)
+        /// <param name="logger">The logger.</param>
+        public PluginUpdateTask(Kernel kernel, ILogger logger)
         {
+            _kernel = kernel;
+            _logger = logger;
         }
 
         /// <summary>
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             return new ITaskTrigger[] { 
             
@@ -46,11 +56,11 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
             progress.Report(0);
 
-            var packagesToInstall = (await Kernel.InstallationManager.GetAvailablePluginUpdates(true, cancellationToken).ConfigureAwait(false)).ToList();
+            var packagesToInstall = (await _kernel.InstallationManager.GetAvailablePluginUpdates(true, cancellationToken).ConfigureAwait(false)).ToList();
 
             progress.Report(10);
 
@@ -63,7 +73,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
 
                 try
                 {
-                    await Kernel.InstallationManager.InstallPackage(i, new Progress<double> { }, cancellationToken).ConfigureAwait(false);
+                    await _kernel.InstallationManager.InstallPackage(i, new Progress<double> { }, cancellationToken).ConfigureAwait(false);
                 }
                 catch (OperationCanceledException)
                 {
@@ -75,11 +85,11 @@ namespace MediaBrowser.Controller.ScheduledTasks
                 }
                 catch (HttpException ex)
                 {
-                    Logger.ErrorException("Error downloading {0}", ex, i.name);
+                    _logger.ErrorException("Error downloading {0}", ex, i.name);
                 }
                 catch (IOException ex)
                 {
-                    Logger.ErrorException("Error updating {0}", ex, i.name);
+                    _logger.ErrorException("Error updating {0}", ex, i.name);
                 }
 
                 // Update progress
@@ -104,7 +114,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the name of the task
         /// </summary>
         /// <value>The name.</value>
-        public override string Name
+        public string Name
         {
             get { return "Check for plugin updates"; }
         }
@@ -113,9 +123,14 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the description.
         /// </summary>
         /// <value>The description.</value>
-        public override string Description
+        public string Description
         {
             get { return "Downloads and installs updates for plugins that are configured to update automatically."; }
         }
+
+        public string Category
+        {
+            get { return "Application"; }
+        }
     }
 }

+ 1 - 0
MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
+using MediaBrowser.Server.Implementations.Reflection;
 using System;
 using System.Collections.Generic;
 using System.Data;

+ 7 - 8
MediaBrowser.ServerApplication/App.xaml.cs

@@ -1,8 +1,6 @@
 using MediaBrowser.ClickOnce;
-using MediaBrowser.Common.Implementations.Serialization;
 using MediaBrowser.Common.Kernel;
 using MediaBrowser.Controller;
-using MediaBrowser.Logging.Nlog;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Server.Uninstall;
 using Microsoft.Win32;
@@ -30,7 +28,7 @@ namespace MediaBrowser.ServerApplication
         [STAThread]
         public static void Main()
         {
-            var application = new App(new NLogger("App"));
+            var application = new App();
 
             application.Run();
         }
@@ -74,10 +72,8 @@ namespace MediaBrowser.ServerApplication
         /// Initializes a new instance of the <see cref="App" /> class.
         /// </summary>
         /// <param name="logger">The logger.</param>
-        public App(ILogger logger)
+        public App()
         {
-            Logger = logger;
-
             InitializeComponent();
         }
 
@@ -174,13 +170,16 @@ namespace MediaBrowser.ServerApplication
         /// </summary>
         protected async void LoadKernel()
         {
-            CompositionRoot = new ApplicationHost(Logger);
+            CompositionRoot = new ApplicationHost();
 
+            Logger = CompositionRoot.Logger;
             Kernel = CompositionRoot.Kernel;
 
             try
             {
-                new MainWindow(new JsonSerializer(), Logger).Show();
+                var win = (MainWindow)CompositionRoot.CreateInstance(typeof(MainWindow));
+
+                win.Show();
 
                 var now = DateTime.UtcNow;
 

+ 40 - 278
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -1,5 +1,6 @@
 using BDInfo;
 using MediaBrowser.ClickOnce;
+using MediaBrowser.Common.Implementations;
 using MediaBrowser.Common.Implementations.ScheduledTasks;
 using MediaBrowser.Common.Implementations.Serialization;
 using MediaBrowser.Common.IO;
@@ -10,7 +11,6 @@ using MediaBrowser.Controller;
 using MediaBrowser.IsoMounter;
 using MediaBrowser.Logging.Nlog;
 using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
@@ -22,7 +22,6 @@ using MediaBrowser.Networking.Udp;
 using MediaBrowser.Networking.WebSocket;
 using MediaBrowser.Server.Implementations;
 using MediaBrowser.ServerApplication.Implementations;
-using SimpleInjector;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -37,56 +36,19 @@ namespace MediaBrowser.ServerApplication
     /// <summary>
     /// Class CompositionRoot
     /// </summary>
-    public class ApplicationHost : IApplicationHost, IDisposable
+    public class ApplicationHost : BaseApplicationHost, IApplicationHost
     {
-        /// <summary>
-        /// Gets or sets the logger.
-        /// </summary>
-        /// <value>The logger.</value>
-        private ILogger Logger { get; set; }
-
         /// <summary>
         /// Gets or sets the log file path.
         /// </summary>
         /// <value>The log file path.</value>
         public string LogFilePath { get; private set; }
 
-        /// <summary>
-        /// The container
-        /// </summary>
-        private readonly Container _container = new Container();
-
         /// <summary>
         /// Gets or sets the kernel.
         /// </summary>
         /// <value>The kernel.</value>
-        public Kernel Kernel { get; private set; }
-
-        private readonly List<string> _failedAssemblies = new List<string>();
-        /// <summary>
-        /// Gets assemblies that failed to load
-        /// </summary>
-        public IEnumerable<string> FailedAssemblies
-        {
-            get { return _failedAssemblies; }
-        }
-
-        /// <summary>
-        /// Gets all types within all running assemblies
-        /// </summary>
-        /// <value>All types.</value>
-        public Type[] AllTypes { get; private set; }
-
-        /// <summary>
-        /// Gets all concrete types.
-        /// </summary>
-        /// <value>All concrete types.</value>
-        public Type[] AllConcreteTypes { get; private set; }
-
-        /// <summary>
-        /// The disposable parts
-        /// </summary>
-        private readonly List<IDisposable> _disposableParts = new List<IDisposable>();
+        internal Kernel Kernel { get; private set; }
 
         /// <summary>
         /// The json serializer
@@ -107,20 +69,40 @@ namespace MediaBrowser.ServerApplication
         /// The _task manager
         /// </summary>
         private readonly ITaskManager _taskManager;
-        
+
+        /// <summary>
+        /// The _task manager
+        /// </summary>
+        private readonly IHttpServer _httpServer;
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is first run.
+        /// </summary>
+        /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
+        public bool IsFirstRun { get; private set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ApplicationHost" /> class.
         /// </summary>
         /// <param name="logger">The logger.</param>
-        public ApplicationHost(ILogger logger)
+        public ApplicationHost()
+            : base()
         {
-            Logger = logger;
+            IsFirstRun = !File.Exists(_applicationPaths.SystemConfigurationFilePath);
+            
+            Logger = new NLogger("App");
+
+            DiscoverTypes();
 
             _taskManager = new TaskManager(_applicationPaths, _jsonSerializer, Logger);
 
             Kernel = new Kernel(this, _applicationPaths, _xmlSerializer, _taskManager, Logger);
             ReloadLogger();
 
+            Logger.Info("Version {0} initializing", ApplicationVersion);
+
+            _httpServer = ServerFactory.CreateServer(this, ProtobufSerializer, Logger, "Media Browser", "index.html");
+
             RegisterResources();
 
             FindParts();
@@ -129,42 +111,28 @@ namespace MediaBrowser.ServerApplication
         /// <summary>
         /// Registers resources that classes will depend on
         /// </summary>
-        internal void RegisterResources()
+        private void RegisterResources()
         {
-            DiscoverTypes();
-
             RegisterSingleInstance<IKernel>(Kernel);
             RegisterSingleInstance(Kernel);
-            
+
             RegisterSingleInstance<IApplicationHost>(this);
             RegisterSingleInstance(Logger);
 
             RegisterSingleInstance(_applicationPaths);
             RegisterSingleInstance<IApplicationPaths>(_applicationPaths);
             RegisterSingleInstance(_taskManager);
-            RegisterSingleInstance<IIsoManager>(() => new PismoIsoManager(Logger));
-            RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer());
-            RegisterSingleInstance<IHttpClient>(() => new HttpManager(_applicationPaths, Logger));
-            RegisterSingleInstance<INetworkManager>(() => new NetworkManager());
-            RegisterSingleInstance<IZipClient>(() => new DotNetZipClient());
+            RegisterSingleInstance<IIsoManager>(new PismoIsoManager(Logger));
+            RegisterSingleInstance<IBlurayExaminer>(new BdInfoExaminer());
+            RegisterSingleInstance<IHttpClient>(new HttpManager(_applicationPaths, Logger));
+            RegisterSingleInstance<INetworkManager>(new NetworkManager());
+            RegisterSingleInstance<IZipClient>(new DotNetZipClient());
             RegisterSingleInstance<IWebSocketServer>(() => new AlchemyServer(Logger));
             RegisterSingleInstance(_jsonSerializer);
             RegisterSingleInstance(_xmlSerializer);
-            RegisterSingleInstance<IProtobufSerializer>(() => ProtobufSerializer);
-            Register(typeof(IUdpServer), typeof(UdpServer));
-            RegisterSingleInstance(() => ServerFactory.CreateServer(this, Kernel, ProtobufSerializer, Logger, "Media Browser", "index.html"));
-        }
-
-        /// <summary>
-        /// Discovers the types.
-        /// </summary>
-        private void DiscoverTypes()
-        {
-            _failedAssemblies.Clear();
-
-            AllTypes = GetComposablePartAssemblies().SelectMany(GetTypes).ToArray();
-
-            AllConcreteTypes = AllTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray();
+            RegisterSingleInstance(ProtobufSerializer);
+            RegisterSingleInstance<IUdpServer>(new UdpServer());
+            RegisterSingleInstance(_httpServer);
         }
 
         /// <summary>
@@ -173,150 +141,8 @@ namespace MediaBrowser.ServerApplication
         private void FindParts()
         {
             _taskManager.AddTasks(GetExports<IScheduledTask>(false));
-        }
-
-        /// <summary>
-        /// Gets a list of types within an assembly
-        /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
-        /// </summary>
-        /// <param name="assembly">The assembly.</param>
-        /// <returns>IEnumerable{Type}.</returns>
-        /// <exception cref="System.ArgumentNullException">assembly</exception>
-        private IEnumerable<Type> GetTypes(Assembly assembly)
-        {
-            if (assembly == null)
-            {
-                throw new ArgumentNullException("assembly");
-            }
-
-            try
-            {
-                return assembly.GetTypes();
-            }
-            catch (ReflectionTypeLoadException ex)
-            {
-                // If it fails we can still get a list of the Types it was able to resolve
-                return ex.Types.Where(t => t != null);
-            }
-        }
-
-        /// <summary>
-        /// The _protobuf serializer initialized
-        /// </summary>
-        private bool _protobufSerializerInitialized;
-        /// <summary>
-        /// The _protobuf serializer sync lock
-        /// </summary>
-        private object _protobufSerializerSyncLock = new object();
-        /// <summary>
-        /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection
-        /// </summary>
-        private ProtobufSerializer _protobufSerializer;
-        /// <summary>
-        /// Gets the protobuf serializer.
-        /// </summary>
-        /// <value>The protobuf serializer.</value>
-        public ProtobufSerializer ProtobufSerializer
-        {
-            get
-            {
-                // Lazy load
-                LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => ProtobufSerializer.Create(AllTypes));
-                return _protobufSerializer;
-            }
-            private set
-            {
-                _protobufSerializer = value;
-                _protobufSerializerInitialized = value != null;
-            }
-        }
-
-        /// <summary>
-        /// Creates an instance of type and resolves all constructor dependancies
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <returns>System.Object.</returns>
-        public object CreateInstance(Type type)
-        {
-            try
-            {
-                return _container.GetInstance(type);
-            }
-            catch
-            {
-                Logger.Error("Error creating {0}", type.Name);
 
-                throw;
-            }
-        }
-
-        /// <summary>
-        /// Registers the specified obj.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="obj">The obj.</param>
-        public void RegisterSingleInstance<T>(T obj)
-            where T : class
-        {
-            _container.RegisterSingle(obj);
-        }
-
-        /// <summary>
-        /// Registers the specified func.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="func">The func.</param>
-        public void Register<T>(Func<T> func)
-            where T : class
-        {
-            _container.Register(func);
-        }
-
-        /// <summary>
-        /// Registers the single instance.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="func">The func.</param>
-        public void RegisterSingleInstance<T>(Func<T> func)
-            where T : class
-        {
-            _container.RegisterSingle(func);
-        }
-
-        /// <summary>
-        /// Resolves this instance.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <returns>``0.</returns>
-        public T Resolve<T>()
-        {
-            return (T)_container.GetRegistration(typeof(T), true).GetInstance();
-        }
-
-        /// <summary>
-        /// Resolves this instance.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <returns>``0.</returns>
-        public T TryResolve<T>()
-        {
-            var result = _container.GetRegistration(typeof(T), false);
-
-            if (result == null)
-            {
-                return default(T);
-            }
-            return (T)result.GetInstance();
-        }
-
-        /// <summary>
-        /// Registers the specified service type.
-        /// </summary>
-        /// <param name="serviceType">Type of the service.</param>
-        /// <param name="implementation">Type of the concrete.</param>
-        public void Register(Type serviceType, Type implementation)
-        {
-            _container.Register(serviceType, implementation);
+            _httpServer.Init(GetExports<IRestfulService>(false));
         }
 
         /// <summary>
@@ -374,12 +200,12 @@ namespace MediaBrowser.ServerApplication
         /// Gets the composable part assemblies.
         /// </summary>
         /// <returns>IEnumerable{Assembly}.</returns>
-        private IEnumerable<Assembly> GetComposablePartAssemblies()
+        protected override IEnumerable<Assembly> GetComposablePartAssemblies()
         {
             // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that
             // This will prevent the .dll file from getting locked, and allow us to replace it when needed
             foreach (var pluginAssembly in Directory
-                .EnumerateFiles(Kernel.ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly)
+                .EnumerateFiles(_applicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly)
                 .Select(LoadAssembly).Where(a => a != null))
             {
                 yield return pluginAssembly;
@@ -410,73 +236,9 @@ namespace MediaBrowser.ServerApplication
 
             // Server implementations
             yield return typeof(ServerApplicationPaths).Assembly;
-            
+
             // Include composable parts in the running assembly
             yield return GetType().Assembly;
         }
-
-        /// <summary>
-        /// Loads the assembly.
-        /// </summary>
-        /// <param name="file">The file.</param>
-        /// <returns>Assembly.</returns>
-        private Assembly LoadAssembly(string file)
-        {
-            try
-            {
-                return Assembly.Load(File.ReadAllBytes((file)));
-            }
-            catch (Exception ex)
-            {
-                _failedAssemblies.Add(file);
-                Logger.ErrorException("Error loading assembly {0}", ex, file);
-                return null;
-            }
-        }
-
-        /// <summary>
-        /// Gets the exports.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="allTypes">All types.</param>
-        /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
-        /// <returns>IEnumerable{``0}.</returns>
-        public IEnumerable<T> GetExports<T>(bool manageLiftime = true)
-        {
-            var currentType = typeof(T);
-
-            Logger.Info("Composing instances of " + currentType.Name);
-
-            var parts = AllConcreteTypes.Where(currentType.IsAssignableFrom).Select(CreateInstance).Cast<T>().ToArray();
-
-            if (manageLiftime)
-            {
-                _disposableParts.AddRange(parts.OfType<IDisposable>());
-            }
-
-            return parts;
-        }
-
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        public void Dispose()
-        {
-            Dispose(true);
-        }
-
-        /// <summary>
-        /// Releases unmanaged and - optionally - managed resources.
-        /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected virtual void Dispose(bool dispose)
-        {
-            foreach (var part in _disposableParts)
-            {
-                part.Dispose();
-            }
-
-            _disposableParts.Clear();
-        }
     }
 }

+ 4 - 3
MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
@@ -38,13 +39,13 @@ namespace MediaBrowser.ServerApplication
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryExplorer" /> class.
         /// </summary>
-        public LibraryExplorer(IJsonSerializer jsonSerializer, ILogger logger)
+        public LibraryExplorer(IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost)
         {
             _logger = logger;
             _jsonSerializer = jsonSerializer;
 
             InitializeComponent();
-            lblVersion.Content = "Version: " + Kernel.Instance.ApplicationVersion;
+            lblVersion.Content = "Version: " + appHost.ApplicationVersion;
             foreach (var user in Kernel.Instance.Users)
                 ddlProfile.Items.Add(user);
             ddlProfile.Items.Insert(0,new User {Name = "Physical"});

+ 13 - 4
MediaBrowser.ServerApplication/MainWindow.xaml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
@@ -49,12 +50,19 @@ namespace MediaBrowser.ServerApplication
         /// </summary>
         private readonly ILogger _logger;
 
+        /// <summary>
+        /// The _app host
+        /// </summary>
+        private readonly IApplicationHost _appHost;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="MainWindow" /> class.
         /// </summary>
+        /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logger">The logger.</param>
+        /// <param name="appHost">The app host.</param>
         /// <exception cref="System.ArgumentNullException">logger</exception>
-        public MainWindow(IJsonSerializer jsonSerializer, ILogger logger)
+        public MainWindow(IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost)
         {
             if (jsonSerializer == null)
             {
@@ -67,6 +75,7 @@ namespace MediaBrowser.ServerApplication
 
             _jsonSerializer = jsonSerializer;
             _logger = logger;
+            _appHost = appHost;
 
             InitializeComponent();
 
@@ -236,7 +245,7 @@ namespace MediaBrowser.ServerApplication
             Kernel.Instance.LibraryManager.LibraryChanged -= Instance_LibraryChanged;
             Kernel.Instance.LibraryManager.LibraryChanged += Instance_LibraryChanged;
 
-            if (Kernel.Instance.IsFirstRun)
+            if (_appHost.IsFirstRun)
             {
                 LaunchStartupWizard();
             }
@@ -293,7 +302,7 @@ namespace MediaBrowser.ServerApplication
         /// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
         private void cmOpenExplorer_click(object sender, RoutedEventArgs e)
         {
-            (new LibraryExplorer(_jsonSerializer, _logger)).Show();
+            (new LibraryExplorer(_jsonSerializer, _logger, _appHost)).Show();
         }
 
         /// <summary>

+ 12 - 0
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -128,6 +128,18 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\ThirdParty\UPnP\Libs\Platinum.Managed.dll</HintPath>
     </Reference>
+    <Reference Include="ServiceStack.Common, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll</HintPath>
+    </Reference>
+    <Reference Include="ServiceStack.Interfaces, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll</HintPath>
+    </Reference>
+    <Reference Include="ServiceStack.Text, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath>
+    </Reference>
     <Reference Include="SimpleInjector, Version=2.0.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\SimpleInjector.2.0.0-beta5\lib\net40-client\SimpleInjector.dll</HintPath>

+ 2 - 0
MediaBrowser.ServerApplication/packages.config

@@ -3,6 +3,8 @@
   <package id="DotNetZip" version="1.9.1.8" targetFramework="net45" />
   <package id="Hardcodet.Wpf.TaskbarNotification" version="1.0.4.0" targetFramework="net45" />
   <package id="NLog" version="2.0.0.2000" targetFramework="net45" />
+  <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" />
+  <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" />
   <package id="SimpleInjector" version="2.0.0-beta5" targetFramework="net45" />
   <package id="System.Data.SQLite" version="1.0.84.0" targetFramework="net45" />
 </packages>

+ 5 - 15
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -6,8 +6,8 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Tasks;
+using MediaBrowser.Networking.HttpServer;
 using ServiceStack.ServiceHost;
-using ServiceStack.WebHost.Endpoints;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel.Composition;
@@ -49,6 +49,7 @@ namespace MediaBrowser.WebDashboard.Api
     /// <summary>
     /// Class GetDashboardResource
     /// </summary>
+    [Route("/dashboard/{name*}", "GET")]
     public class GetDashboardResource
     {
         /// <summary>
@@ -91,17 +92,6 @@ namespace MediaBrowser.WebDashboard.Api
         {
             _taskManager = taskManager;
         }
-        
-        /// <summary>
-        /// Adds the routes.
-        /// </summary>
-        /// <param name="appHost">The app host.</param>
-        public override void Configure(IAppHost appHost)
-        {
-            base.Configure(appHost);
-
-            appHost.Routes.Add<GetDashboardResource>("/dashboard/{name*}", "GET");
-        }
 
         /// <summary>
         /// Gets the specified request.
@@ -136,7 +126,7 @@ namespace MediaBrowser.WebDashboard.Api
                                      .Select(ScheduledTaskHelpers.GetTaskInfo)
                                      .ToArray(),
 
-                ApplicationUpdateTaskId = taskManager.ScheduledTasks.First(t => t.GetType().Name.Equals("SystemUpdateTask", StringComparison.OrdinalIgnoreCase)).Id,
+                ApplicationUpdateTaskId = taskManager.ScheduledTasks.First(t => t.ScheduledTask.GetType().Name.Equals("SystemUpdateTask", StringComparison.OrdinalIgnoreCase)).Id,
 
                 ActiveConnections = connections,
 
@@ -370,7 +360,7 @@ namespace MediaBrowser.WebDashboard.Api
 
             var files = new[]
                             {
-                                "http://code.jquery.com/mobile/1.3.0-rc.1/jquery.mobile-1.3.0-rc.1.min.css",
+                                "http://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.css",
                                 "thirdparty/jqm-icon-pack-3.0/font-awesome/jqm-icon-pack-3.0.0-fa.css",
                                 "css/site.css" + versionString
                             };
@@ -391,7 +381,7 @@ namespace MediaBrowser.WebDashboard.Api
             var files = new[]
                             {
                                 "http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js", 
-                                "http://code.jquery.com/mobile/1.3.0-rc.1/jquery.mobile-1.3.0-rc.1.min.js",
+                                "http://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.js",
                                 "../jsapiclient.js" + versionString,
                                 "scripts/all.js" + versionString
             };

+ 4 - 0
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -99,6 +99,10 @@
       <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.Networking\MediaBrowser.Networking.csproj">
+      <Project>{7c11010e-179a-49b7-bfb2-f1656f5e71ad}</Project>
+      <Name>MediaBrowser.Networking</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Html\index.html" />

+ 1 - 3
Nuget/MediaBrowser.ApiClient.nuspec

@@ -11,14 +11,12 @@
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
             <group targetFramework=".NETFramework4.5">
-                <dependency id="ServiceStack.Text" version="3.9.37" />
-                <dependency id="protobuf-net" version="2.0.0.621" />
+                <dependency id="Newtonsoft.Json" version="4.5.11" />
             </group>
             <group targetFramework=".NETPortable0.0-net45+sl4+wp71+win8">
                 <dependency id="Newtonsoft.Json" version="4.5.11" />
                 <dependency id="Microsoft.Bcl.Async" version="1.0.14-rc" />
                 <dependency id="Microsoft.Net.Http" version="2.1.3-beta" />
-                <dependency id="protobuf-net" version="2.0.0.621" />
             </group>
         </dependencies>
     </metadata>