initial source commit

This commit is contained in:
Gary Sharp
2013-02-01 12:35:28 +11:00
parent 543a005d31
commit 0a93429800
1103 changed files with 285609 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
@@ -0,0 +1,21 @@
using System.Web;
using System.Web.Mvc;
using System.Web.WebPages;
using RazorGenerator.Mvc;
[assembly: WebActivator.PostApplicationStartMethod(typeof(Disco.Services.App_Start.RazorGeneratorMvcStart), "Start")]
namespace Disco.Services.App_Start {
public static class RazorGeneratorMvcStart {
public static void Start() {
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) {
UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
};
ViewEngines.Engines.Insert(0, engine);
// StartPage lookups are done by WebPages.
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
}
}
+186
View File
@@ -0,0 +1,186 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{B80A737F-BD6A-4986-9182-DD7B932BD950}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Disco.Services</RootNamespace>
<AssemblyName>Disco.Services</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityFramework">
<HintPath>..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Quartz, Version=2.0.1.100, Culture=neutral, PublicKeyToken=f6b8c98a402cc8a4, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
</Reference>
<Reference Include="RazorGenerator.Mvc, Version=1.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\RazorGenerator.Mvc.1.5.0.0\lib\net40\RazorGenerator.Mvc.dll</HintPath>
</Reference>
<Reference Include="SignalR, Version=0.5.1.10822, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\SignalR.Server.0.5.3\lib\net40\SignalR.dll</HintPath>
</Reference>
<Reference Include="SignalR.Hosting.AspNet, Version=0.5.1.10822, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\SignalR.Hosting.AspNet.0.5.3\lib\net45\SignalR.Hosting.AspNet.dll</HintPath>
</Reference>
<Reference Include="SignalR.Hosting.Common">
<HintPath>..\packages\SignalR.Hosting.Common.0.5.3\lib\net40\SignalR.Hosting.Common.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.SqlServer.Compact.4.0.8876.1\lib\net40\System.Data.SqlServerCe.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WebActivator, Version=1.5.3.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\WebActivator.1.5.3\lib\net40\WebActivator.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="App_Start\RazorGeneratorMvcStart.cs" />
<Compile Include="Logging\LogBase.cs" />
<Compile Include="Logging\LogContext.cs" />
<Compile Include="Logging\LogReInitalizeJob.cs" />
<Compile Include="Logging\Models\LogEvent.cs" />
<Compile Include="Logging\Models\LogEventType.cs" />
<Compile Include="Logging\Models\LogLiveEvent.cs" />
<Compile Include="Logging\Models\LogModule.cs" />
<Compile Include="Logging\ReadLogContext.cs" />
<Compile Include="Logging\SystemLog.cs" />
<Compile Include="Logging\Targets\LogLiveContext.cs" />
<Compile Include="Logging\Targets\LogPersistContext.cs" />
<Compile Include="Logging\Utilities.cs" />
<None Include="_Plugins\Categories\CertificateProvider\CertificateProviderPlugin.cs" />
<None Include="_Plugins\Categories\CertificateProvider\CertificateProviderLog.cs" />
<None Include="_Plugins\Categories\InteroperabilityProvider\InteroperabilityProviderPlugin.cs" />
<None Include="_Plugins\Categories\WarrantyProvider\WarrantyProviderPlugin.cs" />
<None Include="_Plugins\Categories\WarrantyProvider\WarrantyProviderSubmitJobException.cs" />
<None Include="_Plugins\PluginCategoryAttribute.cs" />
<None Include="_Plugins\PluginDefinition.cs" />
<None Include="_Plugins\Plugins.cs" />
<None Include="_Plugins\Plugin.cs" />
<None Include="_Plugins\IPluginConfiguration.cs" />
<None Include="_Plugins\IPluginWebController.cs" />
<None Include="_Plugins\InvalidCategoryTypeException.cs" />
<None Include="_Plugins\PluginExtensions.cs" />
<None Include="_Plugins\PluginsLog.cs" />
<None Include="_Plugins\PluginWebControllerException.cs" />
<None Include="_Plugins\PluginWebControllerExtensions.cs" />
<None Include="_Plugins\UnknownPluginException.cs" />
<Compile Include="Plugins\PluginAttribute.cs" />
<Compile Include="Plugins\PluginExtensions.cs" />
<Compile Include="Plugins\PluginFeatureAttribute.cs" />
<Compile Include="Plugins\Features\CertificateProvider\CertificateProviderFeature.cs" />
<Compile Include="Plugins\Features\CertificateProvider\CertificateProviderLog.cs" />
<Compile Include="Plugins\Features\InteroperabilityProvider\InteroperabilityProviderFeature.cs" />
<Compile Include="Plugins\Features\Other\OtherFeature.cs" />
<Compile Include="Plugins\Features\WarrantyProvider\WarrantyProviderFeature.cs" />
<Compile Include="Plugins\Features\WarrantyProvider\WarrantyProviderSubmitJobException.cs" />
<Compile Include="Plugins\InvalidFeatureCategoryTypeException.cs" />
<Compile Include="Plugins\Plugin.cs" />
<Compile Include="Plugins\PluginConfigurationHandler.cs" />
<Compile Include="Plugins\PluginFeature.cs" />
<Compile Include="Plugins\PluginFeatureCategoryAttribute.cs" />
<Compile Include="Plugins\PluginFeatureManifest.cs" />
<Compile Include="Plugins\PluginManifest.cs" />
<Compile Include="Plugins\Plugins.cs" />
<Compile Include="Plugins\PluginsLog.cs" />
<Compile Include="Plugins\PluginWebHandler.cs" />
<Compile Include="Plugins\PluginWebHandlerController.cs" />
<Compile Include="Plugins\UnknownPluginException.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tasks\ScheduledTask.cs" />
<Compile Include="Tasks\ScheduledTaskCleanup.cs" />
<Compile Include="Tasks\ScheduledTasks.cs" />
<Compile Include="Tasks\ScheduledTasksLog.cs" />
<Compile Include="Tasks\ScheduledTaskStatus.cs" />
<Compile Include="Tasks\ScheduledTasksLiveStatusService.cs" />
<Compile Include="Tasks\ScheduledTaskStatusLive.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Disco.Data\Disco.Data.csproj">
<Project>{85A6BD19-2C64-4746-8F2C-A68A86E8C2D7}</Project>
<Name>Disco.Data</Name>
</ProjectReference>
<ProjectReference Include="..\Disco.Models\Disco.Models.csproj">
<Project>{FBC05512-FCCA-4B16-9E76-8C413C5DE6C9}</Project>
<Name>Disco.Models</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties BuildVersion_UseGlobalSettings="True" BuildVersion_DetectChanges="False" BuildVersion_BuildAction="ReBuild" BuildVersion_StartDate="2001/1/1" />
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PostBuildEvent>
if not exist "$(TargetDir)x86" md "$(TargetDir)x86"
xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\x86\*.*" "$(TargetDir)x86"
if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64"
xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64"</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
+43
View File
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Logging
{
public abstract class LogBase
{
private Dictionary<int, Models.LogEventType> _EventTypes;
public LogBase()
{
// Cache Event Types
_EventTypes = this.LoadEventTypes().ToDictionary(et => et.Id);
}
public abstract int ModuleId { get; }
public abstract string ModuleName { get; }
public abstract string ModuleDescription { get; }
protected abstract List<Models.LogEventType> LoadEventTypes();
public Dictionary<int, Models.LogEventType> EventTypes
{
get
{
return _EventTypes;
}
}
protected void Log(int EventTypeId, params object[] Args)
{
LogContext.Current.Log(this.ModuleId, EventTypeId, Args);
}
public string LiveLogGroupName
{
get
{
return this.ModuleName;
}
}
}
}
+314
View File
@@ -0,0 +1,314 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Data.Repository;
using System.IO;
using System.Management;
using System.Diagnostics;
using System.Data.SqlServerCe;
using System.Data.EntityClient;
using System.Data.Entity;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;
using Newtonsoft.Json;
namespace Disco.Services.Logging
{
public class LogContext
{
public static Dictionary<int, LogBase> LogModules { get; private set; }
private static object _LogModulesLock = new object();
private static LogContext _Current;
private static object _CurrentLock = new Object();
public static LogContext Current
{
get
{
lock (_CurrentLock)
{
if (_Current == null)
throw new InvalidOperationException("Logging Context has not been Initialized");
return _Current;
}
}
private set
{
lock (_CurrentLock)
{
_Current = value;
}
}
}
private static void InitalizeModules()
{
if (LogModules == null)
{
lock (_LogModulesLock)
{
if (LogModules == null)
{
LogModules = new Dictionary<int, LogBase>();
// Load all LogModules (Only from Disco Assemblies)
var appDomain = AppDomain.CurrentDomain;
var logModuleTypes = (from a in appDomain.GetAssemblies()
where !a.GlobalAssemblyCache && !a.IsDynamic && a.FullName.StartsWith("Disco.", StringComparison.InvariantCultureIgnoreCase)
from type in a.GetTypes()
where typeof(LogBase).IsAssignableFrom(type) && !type.IsAbstract
select type);
foreach (var logModuleType in logModuleTypes)
{
var instance = (LogBase)Activator.CreateInstance(logModuleType);
LogModules[instance.ModuleId] = instance;
}
}
}
}
}
private static void InitalizeDatabase(Targets.LogPersistContext logDbContext)
{
// Add Modules
var existingModules = logDbContext.Modules.Include("EventTypes").ToDictionary(m => m.Id);
foreach (var module in LogModules)
{
// Update/Insert Module
Models.LogModule dbModule;
if (existingModules.TryGetValue(module.Key, out dbModule))
{
// Update
if (dbModule.Name != module.Value.ModuleName)
dbModule.Name = module.Value.ModuleName;
if (dbModule.Description != module.Value.ModuleDescription)
dbModule.Description = module.Value.ModuleDescription;
}
else
{
// Insert
dbModule = new Models.LogModule()
{
Id = module.Key,
Name = module.Value.ModuleName,
Description = module.Value.ModuleDescription
};
logDbContext.Modules.Add(dbModule);
}
// Update/Insert Event Types
Dictionary<int, Models.LogEventType> existingEventTypes = (dbModule.EventTypes == null) ? new Dictionary<int, Models.LogEventType>() : dbModule.EventTypes.ToDictionary(et => et.Id);
foreach (var eventType in module.Value.EventTypes)
{
Models.LogEventType dbEventType;
if (existingEventTypes.TryGetValue(eventType.Key, out dbEventType))
{
// Update
if (dbEventType.Name != eventType.Value.Name)
dbEventType.Name = eventType.Value.Name;
if (dbEventType.Severity != eventType.Value.Severity)
dbEventType.Severity = eventType.Value.Severity;
if (dbEventType.Format != eventType.Value.Format)
dbEventType.Format = eventType.Value.Format;
}
else
{
// Insert
dbEventType = new Models.LogEventType()
{
Id = eventType.Key,
ModuleId = module.Key,
Name = eventType.Value.Name,
Severity = eventType.Value.Severity,
Format = eventType.Value.Format
};
logDbContext.EventTypes.Add(dbEventType);
}
}
}
logDbContext.SaveChanges();
}
public static string LogFileBasePath(DiscoDataContext DiscoContext)
{
var logDirectoryBase = Path.Combine(DiscoContext.DiscoConfiguration.DataStoreLocation, "Logs");
// Create Directory Structure
if (!Directory.Exists(logDirectoryBase))
{
Directory.CreateDirectory(logDirectoryBase);
}
// Ensure Logs are NTFS Compressed - TODO...
//Utilities.CompressDirectory(logDirectory);
// WMI - Doesn't Work for Network Folders...
//var logDirectoryBaseInfo = new DirectoryInfo(logDirectoryBase);
//if ((logDirectoryBaseInfo.Attributes & FileAttributes.Compressed) != FileAttributes.Compressed)
//{
// var logDirectoryWmiPath = string.Format("Win32_Directory.Name=\"{0}\"", logDirectoryBase);
// using (ManagementObject logDirectoryBaseMO = new ManagementObject(logDirectoryWmiPath))
// {
// ManagementBaseObject outParams = logDirectoryBaseMO.InvokeMethod("Compress", null, null);
// Debug.WriteLine("LoggingContext.InitalizeCurrent: Compressing Log Folder; Result: " + outParams.Properties["ReturnValue"].Value.ToString());
// }
//}
return logDirectoryBase;
}
public static string LogFilePath(DiscoDataContext DiscoContext, DateTime Date, bool CreateDirectory = true)
{
var logDirectoryBase = LogFileBasePath(DiscoContext);
var logDirectory = Path.Combine(logDirectoryBase, Date.Year.ToString());
if (CreateDirectory && !Directory.Exists(logDirectory))
{
Directory.CreateDirectory(logDirectory);
}
var logFileName = string.Format("DiscoLog_{0:yyy-MM-dd}.sdf", Date);
return Path.Combine(logDirectory, logFileName);
}
internal static void ReInitalize(DiscoDataContext DiscoContext)
{
lock (_CurrentLock)
{
var logPath = LogFilePath(DiscoContext, DateTime.Today);
//var connectionString = string.Format("Data Source=\"{0}\"", logPath);
SqlCeConnectionStringBuilder sqlCeCSB = new SqlCeConnectionStringBuilder();
sqlCeCSB.DataSource = logPath;
var connectionString = sqlCeCSB.ToString();
// Ensure Database Exists
if (!File.Exists(logPath))
{
// Create Database
using (var context = new Targets.LogPersistContext(connectionString))
{
context.Database.CreateIfNotExists();
}
}
// Add Modules/Event Types
InitalizeModules();
using (var context = new Targets.LogPersistContext(connectionString))
{
InitalizeDatabase(context);
}
// Create Current LogContext
var currentLogContext = new LogContext(logPath, connectionString);
_Current = currentLogContext;
}
SystemLog.LogLogInitialized(_Current.PersistantStorePath);
try
{
// Get Yesterdays Log
var yesterdaysLogPath = LogFilePath(DiscoContext, DateTime.Today.AddDays(-1), false);
if (File.Exists(yesterdaysLogPath))
{
SqlCeConnectionStringBuilder sqlCeCSB = new SqlCeConnectionStringBuilder();
sqlCeCSB.DataSource = yesterdaysLogPath;
var connectionString = sqlCeCSB.ToString();
int logCount;
using (var context = new Targets.LogPersistContext(connectionString))
{
logCount = context.Events.Where(e => !(e.ModuleId == 0 && e.EventTypeId == 100)).Count();
if (logCount == 0)
{
// Delete (empty) Database
context.Database.Delete();
}
}
}
}
catch (Exception ex)
{
SystemLog.LogError("Error occurred while investigating yesterdays log for deletion", ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
private static IScheduler _ReInitializeScheduler;
public static void Initalize(DiscoDataContext DiscoContext, ISchedulerFactory SchedulerFactory)
{
ReInitalize(DiscoContext);
_ReInitializeScheduler = SchedulerFactory.GetScheduler();
var reInitalizeJobDetail = new JobDetailImpl("DiscoLogContextReinialize", typeof(LogReInitalizeJob));
// Simple Trigger - Issue with Day light savings
//var reInitalizeTrigger = TriggerBuilder.Create()
// .WithIdentity("DiscoLogContextReinializeTrigger")
// .StartAt(DateBuilder.TomorrowAt(0,0,0))
// .WithSchedule(SimpleScheduleBuilder.Create().WithIntervalInHours(24).RepeatForever())
// .Build();
// Use Cron Schedule instead
var reInitalizeTrigger = TriggerBuilder.Create()
.WithIdentity("DiscoLogContextReinializeTrigger")
.StartNow()
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(0, 0)) // Midnight
.Build();
_ReInitializeScheduler.ScheduleJob(reInitalizeJobDetail, reInitalizeTrigger);
}
public static string LiveLogAllEventsGroupName
{
get
{
return Targets.LogLiveContext.LiveLogNameAll;
}
}
private LogContext(string PersistantStorePath, string PersistantStoreConnectionString)
{
this.PersistantStorePath = PersistantStorePath;
this.PersistantStoreConnectionString = PersistantStoreConnectionString;
}
public string PersistantStorePath { get; private set; }
public string PersistantStoreConnectionString { get; private set; }
public void Log(int ModuleId, int EventTypeId, params object[] Args)
{
LogBase logModule;
if (LogModules.TryGetValue(ModuleId, out logModule))
{
Models.LogEventType eventType;
if (logModule.EventTypes.TryGetValue(EventTypeId, out eventType))
{
var eventTimestamp = DateTime.Now;
if (eventType.UseLive)
{
Targets.LogLiveContext.Broadcast(logModule, eventType, eventTimestamp, Args);
}
if (eventType.UsePersist)
{
string args = null;
if (Args != null && Args.Length > 0)
{ //args = fastJSON.JSON.Instance.ToJSON(Args, false); // Old fastJSON Implementation
args = JsonConvert.SerializeObject(Args);
}
using (var context = new Targets.LogPersistContext(PersistantStoreConnectionString))
{
var e = new Models.LogEvent()
{
Timestamp = eventTimestamp,
ModuleId = logModule.ModuleId,
EventTypeId = eventType.Id,
Arguments = args
};
context.Events.Add(e);
context.SaveChanges();
}
}
}
else
throw new InvalidOperationException(string.Format("Unknown Log Event Type Called: {0} (for Module: {1})", EventTypeId, ModuleId));
}
else
throw new InvalidOperationException(string.Format("Unknown Log Module Called: {0}", ModuleId));
}
}
}
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;
using Disco.Data.Repository;
namespace Disco.Services.Logging
{
class LogReInitalizeJob : IJob
{
public void Execute(IJobExecutionContext context)
{
using (DiscoDataContext DiscoContext = new DiscoDataContext())
{
LogContext.ReInitalize(DiscoContext);
}
}
}
}
+23
View File
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Disco.Services.Logging.Models
{
[Table("Events")]
public class LogEvent
{
[Required, Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public int ModuleId { get; set; }
[Required]
public int EventTypeId { get; set; }
[Required]
public DateTime Timestamp { get; set; }
public string Arguments { get; set; }
}
}
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Disco.Services.Logging.Models
{
[Table("EventTypes")]
public class LogEventType
{
[Required, Key, Column(Order=0), DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ModuleId { get; set; }
[Required, Key, Column(Order = 1), DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required, MaxLength(200)]
public string Name { get; set; }
[Required]
public int Severity { get; set; }
[MaxLength(1024)]
public string Format { get; set; }
[NotMapped]
public bool UsePersist { get; set; }
[NotMapped]
public bool UseLive { get; set; }
[NotMapped]
public bool UseDisplay { get; set; }
[ForeignKey("ModuleId")]
public LogModule Module { get; set; }
public enum Severities
{
Information = 0,
Warning = 1,
Error = 2
}
public string FormatMessage(object[] Arguments)
{
if (Arguments != null && Arguments.Length > 0)
{
if (!string.IsNullOrEmpty(Format))
{
return string.Format(Format, Arguments);
}
else
{
return Arguments
.Select(v => v == null ? string.Empty : v.ToString())
.Aggregate((a, b) => a + ", " + (b == null ? string.Empty : b));
}
}
else
{
if (!string.IsNullOrEmpty(Format))
{
return Format;
}
}
return string.Empty;
}
}
}
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Newtonsoft.Json;
namespace Disco.Services.Logging.Models
{
public class LogLiveEvent
{
public int ModuleId { get; set; }
public string ModuleName { get; set; }
public string ModuleDescription { get; set; }
public int EventTypeId { get; set; }
public string EventTypeName { get; set; }
public int EventTypeSeverity { get; set; }
public DateTime Timestamp { get; set; }
public object[] Arguments { get; set; }
public string FormattedMessage { get; set; }
public string FormattedTimestamp { get; set; }
public bool UseDisplay { get; set; }
public static LogLiveEvent Create(LogBase logModule, Models.LogEventType eventType, DateTime Timestamp, string jsonArguments)
{
object[] Arguments = null;
if (jsonArguments != null)
{
//var alArguments = fastJSON.JSON.Instance.Parse(jsonArguments) as ArrayList; // Old fastJSON Implementation
Arguments = JsonConvert.DeserializeObject<object[]>(jsonArguments);
//if (alArguments != null)
//{
// Arguments = alArguments.ToArray();
//}
}
return Create(logModule, eventType, Timestamp, Arguments);
}
public static LogLiveEvent Create(LogBase logModule, Models.LogEventType eventType, DateTime Timestamp, params object[] Arguments)
{
return new Models.LogLiveEvent()
{
ModuleId = logModule.ModuleId,
ModuleName = logModule.ModuleName,
ModuleDescription = logModule.ModuleDescription,
EventTypeId = eventType.Id,
EventTypeName = eventType.Name,
EventTypeSeverity = eventType.Severity,
Timestamp = Timestamp,
Arguments = Arguments,
FormattedMessage = eventType.FormatMessage(Arguments),
FormattedTimestamp = Timestamp.ToString("dd/MM/yyy hh:mm:ss tt"),
UseDisplay = eventType.UseDisplay
};
}
}
}
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Disco.Services.Logging.Models
{
[Table("Modules")]
public class LogModule
{
[Required, Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required, MaxLength(200)]
public string Name { get; set; }
[Required, MaxLength(500)]
public string Description { get; set; }
public virtual IList<LogEventType> EventTypes { get; set; }
}
}
+179
View File
@@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Services.Logging.Targets;
using Disco.Data.Repository;
using System.IO;
using System.Text.RegularExpressions;
using System.Data.SqlServerCe;
using Disco.Services.Logging.Models;
namespace Disco.Services.Logging
{
public class ReadLogContext
{
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public int? Take { get; set; }
public int? Module { get; set; }
public List<int> EventTypes { get; set; }
public bool Validate()
{
if (this.Start.HasValue && this.End.HasValue && this.End.Value < this.Start.Value)
throw new ArgumentOutOfRangeException("End", "End must be greater than Start");
if (this.Start.HasValue && !this.End.HasValue && this.Start > DateTime.Now)
throw new ArgumentOutOfRangeException("Start", "Start must be less than current time");
return true;
}
public List<Models.LogLiveEvent> Query(DiscoDataContext DiscoContext)
{
List<Models.LogLiveEvent> results = new List<LogLiveEvent>();
// Validate Options
this.Validate();
var relevantLogFiles = RelevantLogFiles(DiscoContext);
relevantLogFiles.Reverse();
foreach (var logFile in relevantLogFiles)
{
SqlCeConnectionStringBuilder sqlCeCSB = new SqlCeConnectionStringBuilder();
sqlCeCSB.DataSource = logFile.Item1;
var logModules = LogContext.LogModules;
using (var context = new Targets.LogPersistContext(sqlCeCSB.ToString()))
{
var query = this.BuildQuery(context, logFile.Item2, results.Count);
IEnumerable<LogEvent> queryResults = query; // Run the Query
results.AddRange(queryResults.Select(le => Models.LogLiveEvent.Create(logModules[le.ModuleId], logModules[le.ModuleId].EventTypes[le.EventTypeId], le.Timestamp, le.Arguments)));
}
if (this.Take.HasValue && this.Take.Value < results.Count)
break;
}
return results;
}
private static Regex LogFileDateRegex = new Regex("DiscoLog_([0-9]{4})-([0-9]{2})-([0-9]{2}).sdf", RegexOptions.IgnoreCase);
private static DateTime? LogFileDate(string LogFilePath)
{
var fileNameMatch = LogFileDateRegex.Match(LogFilePath);
if (fileNameMatch.Success)
{
return new DateTime(int.Parse(fileNameMatch.Groups[1].Value),
int.Parse(fileNameMatch.Groups[2].Value),
int.Parse(fileNameMatch.Groups[3].Value));
}
else
{
return null;
}
}
private List<Tuple<string, DateTime>> RelevantLogFiles(DiscoDataContext DiscoContext)
{
List<Tuple<string, DateTime>> relevantFiles = new List<Tuple<string, DateTime>>();
var logDirectoryBase = LogContext.LogFileBasePath(DiscoContext);
var logDirectoryBaseInfo = new DirectoryInfo(logDirectoryBase);
var endDate = this.End.HasValue ? this.End.Value : DateTime.Now;
var endDateYear = endDate.Year.ToString();
// Try Shortcut ( < 31 Days in Query)
if (this.Start.HasValue)
{
if ((this.End.HasValue && this.End.Value.Subtract(this.Start.Value).Days < 31) ||
(!this.End.HasValue && DateTime.Now.Subtract(this.Start.Value).Days < 31))
{
// Less than 31 Days in Query - Just evaluate each Path
var queryDate = this.Start.Value.Date;
while (queryDate <= endDate)
{
var fileName = LogContext.LogFilePath(DiscoContext, queryDate, false);
if (File.Exists(fileName))
relevantFiles.Add(new Tuple<string, DateTime>(fileName, LogFileDate(fileName).Value));
queryDate = queryDate.AddDays(1);
}
return relevantFiles;
}
}
List<string> logYears = new List<string>();
foreach (var directoryName in logDirectoryBaseInfo.GetDirectories())
{
int directoryYear;
if (int.TryParse(directoryName.Name, out directoryYear))
{
logYears.Add(directoryName.Name);
}
}
logYears.Sort();
foreach (var logYear in logYears)
{
List<string> logFiles = Directory.EnumerateFiles(Path.Combine(logDirectoryBase, logYear), "DiscoLog_*.sdf").ToList();
logFiles.Sort();
if (logYear != endDateYear)
{
foreach (var logFile in logFiles)
{
relevantFiles.Add(new Tuple<string, DateTime>(logFile, LogFileDate(logFile).Value));
}
}
else
{
foreach (var logFile in logFiles)
{
var fileNameDate = LogFileDate(logFile);
if (fileNameDate != null)
{
if (fileNameDate.Value < endDate)
{
relevantFiles.Add(new Tuple<string, DateTime>(logFile, fileNameDate.Value));
}
else
{
break; // Files are sorted, must be no more...
}
}
}
break; // Years are sorted, must be no more...
}
}
return relevantFiles;
}
private IQueryable<LogEvent> BuildQuery(LogPersistContext LogContext, DateTime LogDate, int Taken)
{
IQueryable<LogEvent> query = LogContext.Events.OrderByDescending(le => le.Timestamp);
if (this.Module.HasValue)
{
query = query.Where(le => le.ModuleId == this.Module.Value);
}
if (this.EventTypes != null && this.EventTypes.Count > 0)
{
query = query.Where(le => this.EventTypes.Contains(le.EventTypeId));
}
if (this.Start.HasValue && this.Start.Value > LogDate)
{
var startValue = DateTime.SpecifyKind(this.Start.Value, DateTimeKind.Local);
query = query.Where(le => le.Timestamp > startValue);
}
if (this.End.HasValue && this.End.Value <= LogDate.AddDays(1))
{
var endValue = DateTime.SpecifyKind(this.End.Value, DateTimeKind.Local);
query = query.Where(le => le.Timestamp < endValue);
}
if (this.Take.HasValue && this.Take.Value > 0)
{
var take = this.Take.Value - Taken;
query = query.Take(take);
}
return query;
}
}
}
+140
View File
@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Services.Logging.Models;
namespace Disco.Services.Logging
{
public class SystemLog : LogBase
{
private const int _ModuleId = 0;
public enum EventTypeIds : int
{
Information = 0,
Warning = 1,
Error = 2,
Exception = 10,
ExceptionWithInner = 11,
LogInitialized = 100,
Uninitialized = 200
}
public static SystemLog Current
{
get
{
return (SystemLog)LogContext.LogModules[_ModuleId];
}
}
private static void Log(EventTypeIds EventTypeId, params object[] Args)
{
Current.Log((int)EventTypeId, Args);
}
public static void LogInformation(params object[] Messages)
{
Log(EventTypeIds.Information, Messages);
}
public static void LogWarning(params object[] Messages)
{
Log(EventTypeIds.Warning, Messages);
}
public static void LogError(params object[] Messages)
{
Log(EventTypeIds.Error, Messages);
}
public static void LogException(string Component, Exception ex)
{
if (ex.InnerException != null)
{
Log(EventTypeIds.ExceptionWithInner, Component, ex.GetType().Name, ex.Message, ex.StackTrace, ex.InnerException.GetType().Name, ex.InnerException.Message, ex.InnerException.StackTrace);
}
else
{
Log(EventTypeIds.Exception, Component, ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
public static void LogLogInitialized(string PersistantStorePath)
{
Log(EventTypeIds.LogInitialized, PersistantStorePath);
}
public static void LogUninitialized()
{
if (Current != null)
Log(EventTypeIds.Uninitialized);
}
public override int ModuleId
{
get { return _ModuleId; }
}
public override string ModuleName
{
get { return "System"; }
}
public override string ModuleDescription
{
get { return "Core System Log"; }
}
protected override List<LogEventType> LoadEventTypes()
{
List<LogEventType> eventTypes = new List<LogEventType>() {
new LogEventType() {
Id = (int)EventTypeIds.Information,
ModuleId = _ModuleId,
Name = "Information",
Format = null,
Severity = (int)LogEventType.Severities.Information,
UseLive = true, UsePersist = true, UseDisplay = true },
new LogEventType() {
Id = (int)EventTypeIds.Warning,
ModuleId = _ModuleId,
Name = "Warning",
Format = null,
Severity = (int)LogEventType.Severities.Warning,
UseLive = true, UsePersist = true, UseDisplay = true },
new LogEventType() {
Id = (int)EventTypeIds.Error,
ModuleId = _ModuleId,
Name = "Error",
Format = null,
Severity = (int)LogEventType.Severities.Error,
UseLive = true, UsePersist = true, UseDisplay = true },
new LogEventType() {
Id = (int)EventTypeIds.Exception,
ModuleId = _ModuleId,
Name = "Exception",
Format = "{0}; {1}: {2}; {3}",
Severity = (int)LogEventType.Severities.Error,
UseLive = true, UsePersist = true, UseDisplay = true },
new LogEventType() {
Id = (int)EventTypeIds.ExceptionWithInner,
ModuleId = _ModuleId,
Name = "Exception with Inner Exception",
Format = "{0}; {1}: {2}; {3}; {4}: {5}; {6}",
Severity = (int)LogEventType.Severities.Error,
UseLive = true, UsePersist = true, UseDisplay = true },
new LogEventType() {
Id = (int)EventTypeIds.LogInitialized,
ModuleId = _ModuleId,
Name = "Log Initialized",
Format = "Log Initialized to '{0}'",
Severity = (int)LogEventType.Severities.Information,
UseLive = false, UsePersist = true, UseDisplay = true },
new LogEventType() {
Id = (int)EventTypeIds.Uninitialized,
ModuleId = _ModuleId,
Name = "Disco Uninitialized",
Format = "Disco Uninitialized",
Severity = (int)LogEventType.Severities.Information,
UseLive = false, UsePersist = true, UseDisplay = false }
};
return eventTypes;
}
}
}
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SignalR;
using SignalR.Hosting.AspNet;
using SignalR.Infrastructure;
namespace Disco.Services.Logging.Targets
{
public class LogLiveContext : PersistentConnection
{
protected override System.Threading.Tasks.Task OnReceivedAsync(IRequest request, string connectionId, string data)
{
// Add to Group
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
{
var groups = data.Substring(13).Split(',');
foreach (var g in groups)
{
this.Groups.Add(connectionId, g);
}
}
return base.OnReceivedAsync(request, connectionId, data);
}
internal static void Broadcast(LogBase logModule, Models.LogEventType eventType, DateTime Timestamp, params object[] Arguments)
{
var message = Models.LogLiveEvent.Create(logModule, eventType, Timestamp, Arguments);
var connectionManager = GlobalHost.ConnectionManager;
var connectionContext = connectionManager.GetConnectionContext<LogLiveContext>();
connectionContext.Groups.Send(_GroupNameAll, message);
connectionContext.Groups.Send(logModule.ModuleName, message);
}
private const string _GroupNameAll = "__All";
//private static string _QualifiedTypeName = typeof(LogLiveContext).FullName + ".";
//private static string _QualifiedTypeNameAll = _QualifiedTypeName + "__All";
//private static string LiveLogNameGroup(string LogName)
//{
// return string.Concat(_QualifiedTypeName, LogName);
//}
public static string LiveLogNameAll
{
get
{
//return _QualifiedTypeNameAll;
return _GroupNameAll;
}
}
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
namespace Disco.Services.Logging.Targets
{
public class LogPersistContext : DbContext
{
public LogPersistContext(string ConnectionString) : base(ConnectionString) { }
public DbSet<Models.LogModule> Modules { get; set; }
public DbSet<Models.LogEventType> EventTypes { get; set; }
public DbSet<Models.LogEvent> Events { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
}
}
+266
View File
@@ -0,0 +1,266 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.IO;
using System.Web.Mvc;
namespace Disco.Services.Logging
{
public static class Utilities
{
public const string LogEventCSVHeader = "Timestamp,ModuleId,ModuleName,ModuleDescription,EventTypeId,EventTypeName,Severity,Message";
public static void ToCsvLine(this Models.LogLiveEvent e, TextWriter writer)
{
writer.Write(e.Timestamp.ToString("yyy-MM-dd HH:mm:ss"));
writer.Write(",");
writer.Write(e.ModuleId);
writer.Write(",\"");
writer.Write(e.ModuleName);
writer.Write("\",\"");
writer.Write(e.ModuleDescription);
writer.Write("\",");
writer.Write(e.EventTypeId);
writer.Write(",\"");
writer.Write(e.EventTypeName);
writer.Write("\",");
writer.Write(e.EventTypeSeverity);
writer.Write(",\"");
writer.Write(e.FormattedMessage.Replace("\"", "'"));
writer.Write("\"");
if (e.Arguments != null)
{
foreach (var arg in e.Arguments)
{
writer.Write(",\"");
if (arg == null)
writer.Write("null");
else
writer.Write(arg.ToString().Replace("\"", "'"));
writer.Write("\"");
}
}
writer.WriteLine();
}
public static MemoryStream ToCsv(this List<Models.LogLiveEvent> e)
{
var ms = new MemoryStream();
StreamWriter sw = new StreamWriter(ms);
sw.WriteLine(LogEventCSVHeader);
if (e != null)
{
foreach (var le in e)
{
le.ToCsvLine(sw);
}
}
sw.Flush();
ms.Position = 0;
return ms;
}
public static List<SelectListItem> ToSelectListItems(this List<Models.LogEventType> items)
{
return items.Select(et => new SelectListItem() { Value = et.Id.ToString(), Text = et.Name }).ToList();
}
#region Win32 APIs
/// <summary>
/// The CreateFile function creates or opens a file, file stream, directory, physical disk, volume, console buffer, tape drive,
/// communications resource, mailslot, or named pipe. The function returns a handle that can be used to access an object.
/// </summary>
/// <param name="lpFileName"></param>
/// <param name="dwDesiredAccess"> access to the object, which can be read, write, or both</param>
/// <param name="dwShareMode">The sharing mode of an object, which can be read, write, both, or none</param>
/// <param name="SecurityAttributes">A pointer to a SECURITY_ATTRIBUTES structure that determines whether or not the returned handle can
/// be inherited by child processes. Can be null</param>
/// <param name="dwCreationDisposition">An action to take on files that exist and do not exist</param>
/// <param name="dwFlagsAndAttributes">The file attributes and flags. </param>
/// <param name="hTemplateFile">A handle to a template file with the GENERIC_READ access right. The template file supplies file attributes
/// and extended attributes for the file that is being created. This parameter can be null</param>
/// <returns>If the function succeeds, the return value is an open handle to a specified file. If a specified file exists before the function
/// all and dwCreationDisposition is CREATE_ALWAYS or OPEN_ALWAYS, a call to GetLastError returns ERROR_ALREADY_EXISTS, even when the function
/// succeeds. If a file does not exist before the call, GetLastError returns 0 (zero).
/// If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.
/// </returns>
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern SafeFileHandle CreateFile(
string lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
IntPtr SecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[Flags]
private enum EFileAccess : uint
{
Delete = 0x10000,
ReadControl = 0x20000,
WriteDAC = 0x40000,
WriteOwner = 0x80000,
Synchronize = 0x100000,
StandardRightsRequired = 0xF0000,
StandardRightsRead = ReadControl,
StandardRightsWrite = ReadControl,
StandardRightsExecute = ReadControl,
StandardRightsAll = 0x1F0000,
SpecificRightsAll = 0xFFFF,
AccessSystemSecurity = 0x1000000, // AccessSystemAcl access type
MaximumAllowed = 0x2000000, // MaximumAllowed access type
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000
}
[Flags]
private enum EFileShare : uint
{
/// <summary>
///
/// </summary>
None = 0x00000000,
/// <summary>
/// Enables subsequent open operations on an object to request read access.
/// Otherwise, other processes cannot open the object if they request read access.
/// If this flag is not specified, but the object has been opened for read access, the function fails.
/// </summary>
Read = 0x00000001,
/// <summary>
/// Enables subsequent open operations on an object to request write access.
/// Otherwise, other processes cannot open the object if they request write access.
/// If this flag is not specified, but the object has been opened for write access, the function fails.
/// </summary>
Write = 0x00000002,
/// <summary>
/// Enables subsequent open operations on an object to request delete access.
/// Otherwise, other processes cannot open the object if they request delete access.
/// If this flag is not specified, but the object has been opened for delete access, the function fails.
/// </summary>
Delete = 0x00000004
}
private enum ECreationDisposition : uint
{
/// <summary>
/// Creates a new file. The function fails if a specified file exists.
/// </summary>
New = 1,
/// <summary>
/// Creates a new file, always.
/// If a file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes,
/// and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor that the SECURITY_ATTRIBUTES structure specifies.
/// </summary>
CreateAlways = 2,
/// <summary>
/// Opens a file. The function fails if the file does not exist.
/// </summary>
OpenExisting = 3,
/// <summary>
/// Opens a file, always.
/// If a file does not exist, the function creates a file as if dwCreationDisposition is CREATE_NEW.
/// </summary>
OpenAlways = 4,
/// <summary>
/// Opens a file and truncates it so that its size is 0 (zero) bytes. The function fails if the file does not exist.
/// The calling process must open the file with the GENERIC_WRITE access right.
/// </summary>
TruncateExisting = 5
}
[Flags]
private enum EFileAttributes : uint
{
None = 0x0000000,
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000
}
private const int FSCTL_SET_COMPRESSION = 0x9C040;
private const short COMPRESSION_FORMAT_DEFAULT = 1;
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int DeviceIoControl(
SafeFileHandle hDevice,
int dwIoControlCode,
ref short lpInBuffer,
int nInBufferSize,
IntPtr lpOutBuffer,
int nOutBufferSize,
ref int lpBytesReturned,
IntPtr lpOverlapped);
#endregion
public static void CompressDirectory(string DirectoryPath)
{
if (DirectoryPath.Length > 250)
throw new InvalidOperationException(string.Format("Directory Path to Long (>250) to Compress: {0}", DirectoryPath));
DirectoryInfo dirInfo = new DirectoryInfo(DirectoryPath);
if (dirInfo.Exists)
{
if ((dirInfo.Attributes & FileAttributes.Compressed) != FileAttributes.Compressed)
{
var dirHandle = CreateFile(DirectoryPath, EFileAccess.GenericWrite, EFileShare.Read, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.None, IntPtr.Zero);
if (dirHandle.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
else
{
EnableCompression(dirHandle);
dirHandle.Close();
}
}
}
else
{
throw new InvalidOperationException(string.Format("Directory doesn't exist: {0}", DirectoryPath));
}
}
private static void EnableCompression(SafeFileHandle handle)
{
int lpBytesReturned = 0;
short lpInBuffer = COMPRESSION_FORMAT_DEFAULT;
int result = DeviceIoControl(handle, FSCTL_SET_COMPRESSION,
ref lpInBuffer, sizeof(short), IntPtr.Zero, 0,
ref lpBytesReturned, IntPtr.Zero);
if (result != 0)
{
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
}
}
}
}
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Disco.Data.Repository;
using Disco.Models.Repository;
namespace Disco.Services.Plugins.Features.CertificateProvider
{
[PluginFeatureCategory(DisplayName = "Certificate Providers")]
public abstract class CertificateProviderFeature : PluginFeature
{
// Certificate Plugin Requirements
public abstract string CertificateProviderId { get; }
public abstract Tuple<DeviceCertificate, List<string>> AllocateCertificate(DiscoDataContext dbContext, Device Device);
}
}
@@ -0,0 +1,304 @@
using Disco.Services.Logging;
using Disco.Services.Logging.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Disco.Services.Plugins.Features.CertificateProvider
{
public class CertificateProvidersLog : LogBase
{
public enum EventTypeIds
{
RetrievalStarting = 10,
RetrievalProgress,
RetrievalFinished,
RetrievalWarning = 15,
RetrievalError,
RetrievalCertificateStarting = 20,
RetrievalCertificateFinished = 22,
RetrievalCertificateWarning = 25,
RetrievalCertificateError,
Allocated = 40,
AllocationFailed = 50
}
private const int _ModuleId = 60;
private static bool _IsCertificateRetrievalProcessing;
private static string _CertificateRetrievalStatus;
private static int _CertificateRetrievalProgress;
public static CertificateProvidersLog Current
{
get
{
return (CertificateProvidersLog)LogContext.LogModules[60];
}
}
public static bool IsCertificateRetrievalProcessing
{
get
{
return CertificateProvidersLog._IsCertificateRetrievalProcessing;
}
}
public override string ModuleDescription
{
get
{
return "Certificate Providers";
}
}
public override int ModuleId
{
get
{
return 60;
}
}
public override string ModuleName
{
get
{
return "CertificateProviders";
}
}
[System.Diagnostics.DebuggerNonUserCode]
public CertificateProvidersLog()
{
}
private static void Log(CertificateProvidersLog.EventTypeIds EventTypeId, params object[] Args)
{
CertificateProvidersLog.Current.Log((int)EventTypeId, Args);
}
public static void LogRetrievalStarting(int CertificateCount, int CertificateIdFrom, int CertificateIdTo)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalStarting, new object[]
{
CertificateCount,
CertificateIdFrom,
CertificateIdTo
});
}
public static void LogRetrievalFinished()
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalFinished, new object[0]);
}
public static void LogRetrievalWarning(string Message)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalWarning, new object[]
{
Message
});
}
public static void LogRetrievalError(string Message)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalError, new object[]
{
Message
});
}
public static void LogRetrievalCertificateStarting(string CertificateId)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalCertificateStarting, new object[]
{
CertificateId
});
}
public static void LogRetrievalCertificateFinished(string CertificateId)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalCertificateFinished, new object[]
{
CertificateId
});
}
public static void LogRetrievalCertificateWarning(string CertificateId, string Message)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalCertificateWarning, new object[]
{
CertificateId,
Message
});
}
public static void LogRetrievalCertificateError(string CertificateId, string Message)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalCertificateError, new object[]
{
CertificateId,
Message
});
}
public static void LogAllocated(string CertificateId, string DeviceSerialNumber)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.Allocated, new object[]
{
CertificateId,
DeviceSerialNumber
});
}
public static void LogAllocationFailed(string DeviceSerialNumber)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.AllocationFailed, new object[]
{
DeviceSerialNumber
});
}
public static void LogCertificateRetrievalProgress(bool? IsProcessing, int? Progress, string Status)
{
bool flag = IsProcessing.HasValue;
if (flag)
{
CertificateProvidersLog._IsCertificateRetrievalProcessing = IsProcessing.Value;
}
flag = CertificateProvidersLog._IsCertificateRetrievalProcessing;
if (flag)
{
bool flag2 = Status != null;
if (flag2)
{
CertificateProvidersLog._CertificateRetrievalStatus = Status;
}
flag2 = Progress.HasValue;
if (flag2)
{
CertificateProvidersLog._CertificateRetrievalProgress = Progress.Value;
}
}
else
{
CertificateProvidersLog._CertificateRetrievalStatus = null;
CertificateProvidersLog._CertificateRetrievalProgress = 0;
}
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalProgress, new object[]
{
CertificateProvidersLog._IsCertificateRetrievalProcessing,
CertificateProvidersLog._CertificateRetrievalProgress,
CertificateProvidersLog._CertificateRetrievalStatus
});
}
protected override System.Collections.Generic.List<LogEventType> LoadEventTypes()
{
return new System.Collections.Generic.List<LogEventType>
{
new LogEventType
{
Id = 10,
ModuleId = 60,
Name = "Retrieval Starting",
Format = "Starting retrieval of {0} certificate/s ({1} to {2})",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 11,
ModuleId = 60,
Name = "Retrieval Progress",
Format = "Processing: {0}; {1}% Complete; Status: {2}",
Severity = 0,
UseLive = true,
UsePersist = false,
UseDisplay = false
},
new LogEventType
{
Id = 12,
ModuleId = 60,
Name = "Retrieval Finished",
Format = "Retrieval of Certificates Complete",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 15,
ModuleId = 60,
Name = "Retrieval Warning",
Format = "Retrieval Warning: {0}",
Severity = 1,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 16,
ModuleId = 60,
Name = "Retrieval Error",
Format = "Retrieval Error: {0}",
Severity = 2,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 20,
ModuleId = 60,
Name = "Retrieval Certificate Starting",
Format = "Retrieving Certificate: {0}",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 22,
ModuleId = 60,
Name = "Retrieval Certificate Finished",
Format = "Certificate Retrieved: {0}",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 25,
ModuleId = 60,
Name = "Retrieval Certificate Warning",
Format = "{0} Certificate Warning: {1}",
Severity = 1,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 26,
ModuleId = 60,
Name = "Retrieval Certificate Error",
Format = "{0} Certificate Error: {1}",
Severity = 2,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 40,
ModuleId = 60,
Name = "Allocated",
Format = "Certificate {0} allocated to {1}",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 50,
ModuleId = 60,
Name = "Allocation Failed",
Format = "No certificates available for Device: {0}",
Severity = 2,
UseLive = true,
UsePersist = true,
UseDisplay = true
}
};
}
}
}
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Plugins.Features.InteroperabilityProvider
{
[PluginFeatureCategory(DisplayName = "Interoperability Providers")]
public abstract class InteroperabilityProviderFeature : PluginFeature
{
}
}
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Plugins.Features.Other
{
[PluginFeatureCategory(DisplayName = "Other")]
public abstract class OtherFeature : PluginFeature
{
}
}
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using Disco.Data.Repository;
using Disco.Models.BI.Config;
using Disco.Models.Repository;
namespace Disco.Services.Plugins.Features.WarrantyProvider
{
[PluginFeatureCategory(DisplayName = "Warranty Providers")]
public abstract class WarrantyProviderFeature : PluginFeature
{
// Warranty Plugin Requirements
public abstract string WarrantyProviderId { get; }
public abstract Type SubmitJobViewType { get; }
public abstract dynamic SubmitJobViewModel(DiscoDataContext dbContext, Controller controller, Job Job, OrganisationAddress Address, User TechUser);
public abstract Dictionary<string, string> SubmitJobParseProperties(DiscoDataContext dbContext, FormCollection form, Controller controller, Job Job, OrganisationAddress Address, User TechUser, string FaultDescription);
public abstract Dictionary<string, string> SubmitJobDiscloseInfo(DiscoDataContext dbContext, Job Job, OrganisationAddress Address, User TechUser, string FaultDescription, Dictionary<string, string> WarrantyProviderProperties);
public abstract string SubmitJob(DiscoDataContext dbContext, Job Job, OrganisationAddress Address, User TechUser, string FaultDescription, Dictionary<string, string> WarrantyProviderProperties);
public abstract Type JobDetailsViewType { get; }
public bool JobDetailsSupported { get { return this.JobDetailsViewType != null; } }
public abstract dynamic JobDetailsViewModel(DiscoDataContext dbContext, Controller controller, Job Job);
public static PluginFeatureManifest FindPluginFeature(string PluginIdOrWarrantyProviderId)
{
var defs = Plugins.GetPluginFeatures(typeof(WarrantyProviderFeature));
var def = defs.FirstOrDefault(d => d.PluginManifest.Id.Equals(PluginIdOrWarrantyProviderId, StringComparison.InvariantCultureIgnoreCase));
if (def != null)
return def;
else
foreach (var d in defs)
{
using (var providerInstance = d.CreateInstance<WarrantyProviderFeature>())
{
if (providerInstance.WarrantyProviderId != null && providerInstance.WarrantyProviderId.Equals(PluginIdOrWarrantyProviderId, StringComparison.InvariantCultureIgnoreCase))
{
return d;
}
}
}
return null;
}
}
}
@@ -0,0 +1,12 @@
using System;
namespace Disco.Services.Plugins.Features.WarrantyProvider
{
public class WarrantyProviderSubmitJobException : Exception
{
public WarrantyProviderSubmitJobException(string Message)
: base(Message)
{
}
}
}
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Plugins
{
public class InvalidFeatureCategoryTypeException : Exception
{
private string _pluginRequested;
private Type _categoryType;
public string PluginRequested
{
get
{
return _pluginRequested;
}
}
public Type CategoryType
{
get
{
return _categoryType;
}
}
public InvalidFeatureCategoryTypeException(Type CategoryType)
: this(CategoryType, null)
{
}
public InvalidFeatureCategoryTypeException(Type CategoryType, string PluginRequested)
{
this._categoryType = CategoryType;
this._pluginRequested = PluginRequested;
}
public override string Message
{
get
{
if (string.IsNullOrEmpty(_pluginRequested))
return string.Format("Invalid Category Type [{0}]", _categoryType.Name);
else
return string.Format("Plugin [{1}] is not of the correct Category Type [{0}]", _categoryType.Name, _pluginRequested);
}
}
}
}
+31
View File
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Disco.Data.Repository;
namespace Disco.Services.Plugins
{
public abstract class Plugin : IDisposable
{
public PluginManifest Manifest {get; internal set;}
#region Lifecycle
public abstract bool Install(DiscoDataContext dbContext);
public abstract bool Initalize(DiscoDataContext dbContext);
public abstract bool Uninstall(DiscoDataContext dbContext);
public abstract bool BeforeUpdate(DiscoDataContext dbContext, PluginManifest updateManifest);
#endregion
public virtual void Dispose()
{
// Nothing in Base Class
}
public override sealed string ToString()
{
return string.Format("{0} ({1}) - v{2}", this.Manifest.Name, this.Manifest.Id, this.Manifest.Version.ToString(4));
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Plugins
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class PluginAttribute : Attribute
{
public string Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
}
}
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using Disco.Data.Repository;
namespace Disco.Services.Plugins
{
public abstract class PluginConfigurationHandler : IDisposable
{
public PluginManifest Manifest { get; set; }
public abstract PluginConfigurationHandlerGetResponse Get(DiscoDataContext dbContext, Controller controller);
public abstract bool Post(DiscoDataContext dbContext, FormCollection form, Controller controller);
public virtual void Dispose()
{
// Nothing in Base Class
}
protected PluginConfigurationHandlerGetResponse GetResponse(Type ViewType, dynamic ViewModel = null)
{
return new PluginConfigurationHandlerGetResponse(this.Manifest, ViewType, ViewModel);
}
public class PluginConfigurationHandlerGetResponse
{
public PluginManifest Manifest { get; set; }
public Type ViewType { get; set; }
public dynamic ViewModel { get; set; }
public PluginConfigurationHandlerGetResponse(PluginManifest Manifest, Type ViewType, dynamic ViewModel = null)
{
if (ViewType == null)
throw new ArgumentNullException("ViewType");
if (!typeof(WebViewPage).IsAssignableFrom(ViewType))
throw new ArgumentException("The PluginConfigurationHandler ViewType must inherit System.Web.Mvc.WebViewPage", "ViewType");
this.Manifest = Manifest;
this.ViewType = ViewType;
this.ViewModel = ViewModel;
}
}
}
}
+190
View File
@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Data.Repository;
using System.IO;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web;
using System.Web.Mvc.Html;
using System.Globalization;
namespace Disco.Services.Plugins
{
public static class PluginExtensions
{
#region Model Binding from Controller
public static bool TryUpdateModel<TModel>(this Controller controller, TModel model) where TModel : class
{
return controller.TryUpdateModel<TModel>(model, null, controller.ValueProvider);
}
public static bool TryUpdateModel<TModel>(this Controller controller, TModel model, IValueProvider valueProvider) where TModel : class
{
return controller.TryUpdateModel<TModel>(model, null, valueProvider);
}
public static bool TryUpdateModel<TModel>(this Controller controller, TModel model, string prefix) where TModel : class
{
return controller.TryUpdateModel<TModel>(model, prefix, controller.ValueProvider);
}
public static bool TryUpdateModel<TModel>(this Controller controller, TModel model, string prefix, IValueProvider valueProvider) where TModel : class
{
if (model == null)
throw new ArgumentNullException("model");
if (valueProvider == null)
throw new ArgumentNullException("valueProvider");
Predicate<string> predicate = propertyName => true;
IModelBinder binder = ModelBinders.Binders.GetBinder(typeof(TModel));
ModelBindingContext context2 = new ModelBindingContext
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(TModel)),
ModelName = prefix,
ModelState = controller.ModelState,
PropertyFilter = predicate,
ValueProvider = valueProvider
};
ModelBindingContext bindingContext = context2;
binder.BindModel(controller.ControllerContext, bindingContext);
return controller.ModelState.IsValid;
}
#endregion
#region Virtual Directories
//public static string WebHandlerResource(this PluginManifest pluginManifest, string resourcePath, RequestContext requestContext)
//{
// var rootPath = WebHandlerRootUrl(pluginManifest, requestContext);
// return string.Concat(rootPath, resourcePath);
//}
//public static string WebHandlerRootUrl(this PluginManifest pluginManifest, RequestContext requestContext)
//{
// var tempPath = pluginManifest.WebHandlerActionUrl(requestContext, "_");
// return tempPath.Substring(0, tempPath.LastIndexOf(@"/") + 1);
//}
//public static string WebHandlerActionUrl(this PluginManifest pluginManifest, RequestContext requestContext, string PluginAction)
//{
// var routeValues = new RouteValueDictionary(new { PluginId = pluginManifest.Id, PluginAction = PluginAction });
// return UrlHelper.GenerateUrl("Plugin", "PluginWebHandler", "Index", routeValues, RouteTable.Routes, requestContext, true);
//}
//public static string WebHandlerResourceUrl(this PluginManifest pluginManifest, RequestContext requestContext, string PluginAction)
//{
// var routeValues = new RouteValueDictionary(new { PluginId = pluginManifest.Id, PluginAction = PluginAction });
// return UrlHelper.GenerateUrl("Plugin", "PluginWebHandler", "Index", routeValues, RouteTable.Routes, requestContext, true);
//}
public static HtmlString DiscoPluginResourceUrl<T>(this WebViewPage<T> ViewPage, string Resource)
{
return ViewPage.DiscoPluginResourceUrl(Resource, false);
}
public static HtmlString DiscoPluginResourceUrl<T>(this WebViewPage<T> ViewPage, string Resource, bool Download)
{
if (string.IsNullOrEmpty(Resource))
throw new ArgumentNullException("Resource");
// Find Plugin
var pageType = ViewPage.GetType();
var pageAssembly = pageType.Assembly;
var manifest = Plugins.GetPlugin(pageAssembly);
var resourcePath = manifest.WebResourcePath(Resource);
var routeValues = new RouteValueDictionary(new { PluginId = manifest.Id, res = Resource });
string pluginActionUrl = UrlHelper.GenerateUrl("Plugin_Resources", null, null, routeValues, RouteTable.Routes, ViewPage.ViewContext.RequestContext, false);
pluginActionUrl += string.Format("?v={0}", resourcePath.Item2);
if (Download)
pluginActionUrl += "&Download=true";
return new HtmlString(pluginActionUrl);
}
public static HtmlString DiscoPluginActionUrl<T>(this WebViewPage<T> ViewPage, string PluginAction)
{
if (string.IsNullOrEmpty(PluginAction))
throw new ArgumentNullException("PluginAction");
// Find Plugin
var pageType = ViewPage.GetType();
var pageAssembly = pageType.Assembly;
var manifest = Plugins.GetPlugin(pageAssembly);
var routeValues = new RouteValueDictionary(new { PluginId = manifest.Id, PluginAction = PluginAction });
string pluginActionUrl = UrlHelper.GenerateUrl("Plugin", null, null, routeValues, RouteTable.Routes, ViewPage.ViewContext.RequestContext, false);
return new HtmlString(pluginActionUrl);
}
public static HtmlString DiscoPluginConfigureUrl<T>(this WebViewPage<T> ViewPage)
{
// Find Plugin
var pageType = ViewPage.GetType();
var pageAssembly = pageType.Assembly;
var manifest = Plugins.GetPlugin(pageAssembly);
var routeValues = new RouteValueDictionary(new { PluginId = manifest.Id });
string pluginActionUrl = UrlHelper.GenerateUrl("Config_Plugins_Configure", null, null, routeValues, RouteTable.Routes, ViewPage.ViewContext.RequestContext, false);
return new HtmlString(pluginActionUrl);
}
public static MvcForm DiscoPluginActionBeginForm<T>(this WebViewPage<T> ViewPage, string PluginAction, FormMethod method, IDictionary<string, object> htmlAttributes)
{
if (string.IsNullOrEmpty(PluginAction))
throw new ArgumentNullException("PluginAction");
// Find Plugin
var pageType = ViewPage.GetType();
var pageAssembly = pageType.Assembly;
var manifest = Plugins.GetPlugin(pageAssembly);
var routeValues = new RouteValueDictionary(new { PluginId = manifest.Id, PluginAction = PluginAction });
string pluginActionUrl = UrlHelper.GenerateUrl("Plugin", null, null, routeValues, RouteTable.Routes, ViewPage.ViewContext.RequestContext, false);
return ViewPage.FormHelper(pluginActionUrl, method, htmlAttributes);
}
public static MvcForm DiscoPluginActionBeginForm<T>(this WebViewPage<T> ViewPage, string PluginAction, FormMethod method)
{
return ViewPage.DiscoPluginActionBeginForm(PluginAction, method, null);
}
public static MvcForm DiscoPluginActionBeginForm<T>(this WebViewPage<T> ViewPage, string PluginAction, IDictionary<string, object> htmlAttributes)
{
return ViewPage.DiscoPluginActionBeginForm(PluginAction, FormMethod.Post, htmlAttributes);
}
public static MvcForm DiscoPluginActionBeginForm<T>(this WebViewPage<T> ViewPage, string PluginAction)
{
return ViewPage.DiscoPluginActionBeginForm(PluginAction, FormMethod.Post, null);
}
private static MvcForm FormHelper<T>(this WebViewPage<T> ViewPage, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes)
{
TagBuilder builder = new TagBuilder("form");
builder.MergeAttributes<string, object>(htmlAttributes);
builder.MergeAttribute("action", formAction);
builder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
bool flag = ViewPage.ViewContext.ClientValidationEnabled && !ViewPage.ViewContext.UnobtrusiveJavaScriptEnabled;
if (flag)
{
object obj2 = ViewPage.ViewContext.HttpContext.Items["DiscoPluginLastFormNum"];
int num = (obj2 != null) ? (((int)obj2) + 1) : 1000;
ViewPage.ViewContext.HttpContext.Items["DiscoPluginLastFormNum"] = num;
builder.GenerateId(string.Format(CultureInfo.InvariantCulture, "form{0}", new object[] { num }));
}
ViewPage.ViewContext.Writer.Write(builder.ToString(TagRenderMode.StartTag));
MvcForm form = new MvcForm(ViewPage.ViewContext);
if (flag)
{
ViewPage.ViewContext.FormContext.FormId = builder.Attributes["id"];
}
return form;
}
#endregion
}
}
+21
View File
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Disco.Data.Repository;
namespace Disco.Services.Plugins
{
public abstract class PluginFeature : IDisposable
{
public PluginFeatureManifest Manifest {get; internal set;}
public abstract bool Initalize(DiscoDataContext dbContext);
public virtual void Dispose()
{
// Nothing in Base Class
}
}
}
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Plugins
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class PluginFeatureAttribute : Attribute
{
public string Id { get; set; }
public string Name { get; set; }
}
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Plugins
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class PluginFeatureCategoryAttribute : Attribute
{
public string DisplayName { get; set; }
}
}
@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Disco.Data.Repository;
using Newtonsoft.Json;
using System.Reflection;
namespace Disco.Services.Plugins
{
public class PluginFeatureManifest
{
public string Id { get; set; }
public string Name { get; set; }
public string TypeName { get; set; }
[JsonProperty]
private string CategoryTypeName { get; set; }
[JsonIgnore]
public PluginManifest PluginManifest { get; private set; }
[JsonIgnore]
internal Type Type { get; private set; }
[JsonIgnore]
public Type CategoryType { get; private set; }
internal bool Initialize(DiscoDataContext dbContext, PluginManifest pluginManifest)
{
this.PluginManifest = pluginManifest;
if (this.Type == null)
this.Type = this.PluginManifest.PluginAssembly.GetType(this.TypeName, true, true);
if (this.CategoryType == null)
this.CategoryType = Type.GetType(this.CategoryTypeName, true, true);
using (var instance = this.CreateInstance())
{
instance.Initalize(dbContext);
}
PluginsLog.LogInitializedPluginFeature(this.PluginManifest, this);
return true;
}
public PluginFeature CreateInstance()
{
var i = (PluginFeature)Activator.CreateInstance(Type);
i.Manifest = this;
return i;
}
public CategoryType CreateInstance<CategoryType>() where CategoryType : PluginFeature
{
if (typeof(CategoryType).IsAssignableFrom(this.Type))
{
var i = (CategoryType)Activator.CreateInstance(Type);
i.Manifest = this;
return i;
}
else
throw new InvalidOperationException(string.Format("The feature [{0}] cannot be cast into type [{1}]", this.Type.Name, typeof(CategoryType).Name));
}
/// <summary>
/// Uses reflection to build a Plugin Manifest
/// </summary>
/// <param name="pluginAssembly">Assembly containing a plugin</param>
/// <returns>A plugin manifest for the first encountered plugin within the assembly</returns>
public static PluginFeatureManifest FromPluginFeatureType(Type featureType, PluginManifest pluginManifest)
{
var featureAttribute = (PluginFeatureAttribute)featureType.GetCustomAttributes(typeof(PluginFeatureAttribute), false).FirstOrDefault();
if (featureAttribute == null)
throw new ArgumentException(string.Format("Plugin Feature found [{0}], but no PluginFeatureAttribute found", featureType.Name), "featureType");
var featureId = featureAttribute.Id;
var featureName = featureAttribute.Name;
// Determine Feature Category
var featureCategoryType = featureType.BaseType;
if (featureCategoryType == null)
throw new ArgumentException(string.Format("Plugin Feature found [{0}], but has no Base Type to determine its Category", featureType.Name), "featureType");
if (featureCategoryType == typeof(PluginFeature) || !typeof(PluginFeature).IsAssignableFrom(featureCategoryType))
throw new ArgumentException(string.Format("Plugin Feature found [{0}], but its Base Type is not a valid Feature Category Type (Base Feature or not assignable)", featureType.Name), "featureType");
var featureCategoryAttribute = (PluginFeatureCategoryAttribute)featureCategoryType.GetCustomAttributes(typeof(PluginFeatureCategoryAttribute), false).FirstOrDefault();
if (featureCategoryAttribute == null)
throw new ArgumentException(string.Format("Plugin Feature found [{0}], but its Base Type is not a valid Feature Category Type (no attribute)", featureType.Name), "featureType");
return new PluginFeatureManifest()
{
PluginManifest = pluginManifest,
Id = featureId,
Name = featureName,
Type = featureType,
TypeName = featureType.FullName,
CategoryType = featureCategoryType,
CategoryTypeName = featureCategoryType.FullName
};
}
}
}
+321
View File
@@ -0,0 +1,321 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Disco.Data.Repository;
using Newtonsoft.Json;
namespace Disco.Services.Plugins
{
public class PluginManifest
{
public string Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public Version Version { get; set; }
[JsonProperty]
internal string AssemblyPath { get; set; }
[JsonProperty]
private string TypeName { get; set; }
[JsonProperty]
private string ConfigurationHandlerTypeName { get; set; }
[JsonProperty]
private string WebHandlerTypeName { get; set; }
[JsonProperty]
internal Dictionary<string, string> AssemblyReferences { get; set; }
[JsonProperty]
public List<PluginFeatureManifest> Features { get; private set; }
[JsonIgnore]
internal Assembly PluginAssembly { get; private set; }
[JsonIgnore]
internal Type Type { get; private set; }
[JsonIgnore]
private Type ConfigurationHandlerType { get; set; }
[JsonIgnore]
private Type WebHandlerType { get; set; }
[JsonIgnore]
public string PluginLocation { get; private set; }
[JsonIgnore]
public string StorageLocation { get; private set; }
private static Dictionary<string, Tuple<string, DateTime>> WebResourceHashes = new Dictionary<string, Tuple<string, DateTime>>();
public List<PluginFeatureManifest> GetFeatures(Type FeatureCategoryType)
{
return this.Features.Where(fm => fm.CategoryType.IsAssignableFrom(FeatureCategoryType)).ToList();
}
public PluginFeatureManifest GetFeature(string PluginFeatureId)
{
return this.Features.Where(fm => fm.Id == PluginFeatureId).FirstOrDefault();
}
public Plugin CreateInstance()
{
var i = (Plugin)Activator.CreateInstance(Type);
i.Manifest = this;
return i;
}
/// <summary>
/// Deserializes a Json Manifest
/// </summary>
/// <param name="FilePath">Path to the Json Manifest file</param>
/// <returns></returns>
public static PluginManifest FromPluginManifestFile(string FilePath)
{
using (Stream manifestStream = File.OpenRead(FilePath))
{
PluginManifest manifest = FromPluginManifestFile(manifestStream, Path.GetDirectoryName(FilePath));
return manifest;
}
}
/// <summary>
/// Deserializes a Json Manifest
/// </summary>
/// <param name="FileStream">Stream containing the encoded Json Manifest File</param>
/// <param name="PluginLocation">PluginLocation to be set in the manifest</param>
/// <returns></returns>
public static PluginManifest FromPluginManifestFile(Stream FileStream, string PluginLocation = null)
{
string manifestString;
using (StreamReader manifestStreamReader = new StreamReader(FileStream))
{
manifestString = manifestStreamReader.ReadToEnd();
}
var manifest = JsonConvert.DeserializeObject<PluginManifest>(manifestString);
manifest.PluginLocation = PluginLocation;
return manifest;
}
/// <summary>
/// Uses reflection to build a Plugin Manifest
/// </summary>
/// <param name="pluginAssembly">Assembly containing a plugin</param>
/// <returns>A plugin manifest for the first encountered plugin within the assembly</returns>
public static PluginManifest FromPluginAssembly(Assembly assembly)
{
// Determine Plugin Properties
var pluginType = (from type in assembly.GetTypes()
where typeof(Plugin).IsAssignableFrom(type) && !type.IsAbstract
select type).FirstOrDefault();
if (pluginType == null)
throw new ArgumentException("No Plugin was found in this Assembly", "pluginAssembly");
var assemblyName = assembly.GetName();
var pluginAttributes = pluginType.GetCustomAttribute<PluginAttribute>(false);
if (pluginAttributes == null)
throw new ArgumentException(string.Format("Plugin found [{0}], but no PluginAttribute found", pluginType.Name), "pluginAssembly");
var pluginId = pluginAttributes.Id;
var pluginName = pluginAttributes.Name;
var pluginAuthor = pluginAttributes.Author;
var pluginVersion = assemblyName.Version;
var pluginAssemblyPath = Path.GetFileName(assembly.Location);
var pluginTypeName = pluginType.FullName;
var pluginLocation = Path.GetDirectoryName(assembly.Location);
// Find Configuration Handler
var pluginConfigurationHandlerType = (from type in assembly.GetTypes()
where typeof(PluginConfigurationHandler).IsAssignableFrom(type) && !type.IsAbstract
select type).FirstOrDefault();
if (pluginConfigurationHandlerType == null)
throw new ArgumentException("A Plugin was found, but no Configuration Handler was found in this Assembly - this is required", "pluginAssembly");
// Find Web Handler
var pluginWebHandlerType = (from type in assembly.GetTypes()
where typeof(PluginWebHandler).IsAssignableFrom(type) && !type.IsAbstract
select type).FirstOrDefault();
Dictionary<string, string> pluginAssemblyReferences = new Dictionary<string, string>();
foreach (string referenceFilename in Directory.EnumerateFiles(pluginLocation, "*.dll", SearchOption.TopDirectoryOnly))
{
if (!referenceFilename.Equals(assembly.Location, StringComparison.InvariantCultureIgnoreCase))
{
try
{
Assembly pluginRefAssembly = Assembly.ReflectionOnlyLoadFrom(referenceFilename);
pluginAssemblyReferences[pluginRefAssembly.FullName] = referenceFilename.Substring(pluginLocation.Length + 1);
}
catch (Exception) { } // Ignore Load Exceptions
}
}
PluginManifest pluginManifest = new PluginManifest()
{
Id = pluginId,
Name = pluginName,
Author = pluginAuthor,
Version = pluginVersion,
AssemblyPath = pluginAssemblyPath,
TypeName = pluginTypeName,
AssemblyReferences = pluginAssemblyReferences,
PluginAssembly = assembly,
Type = pluginType,
PluginLocation = pluginLocation,
ConfigurationHandlerType = pluginConfigurationHandlerType,
ConfigurationHandlerTypeName = pluginConfigurationHandlerType.FullName,
WebHandlerType = pluginWebHandlerType,
WebHandlerTypeName = (pluginWebHandlerType == null ? null : pluginWebHandlerType.FullName)
};
pluginManifest.Features = (from type in assembly.GetTypes()
where typeof(PluginFeature).IsAssignableFrom(type) && !type.IsAbstract
select PluginFeatureManifest.FromPluginFeatureType(type, pluginManifest)).ToList();
return pluginManifest;
}
public string ToManifestFile()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
public bool InitializePlugin(DiscoDataContext dbContext)
{
var assemblyFullPath = Path.Combine(this.PluginLocation, this.AssemblyPath);
if (!File.Exists(assemblyFullPath))
throw new FileNotFoundException(string.Format("Plugin Assembly [{0}] not found at: {1}", this.Id, assemblyFullPath), assemblyFullPath);
if (this.PluginAssembly == null)
this.PluginAssembly = Assembly.LoadFile(assemblyFullPath);
if (this.PluginAssembly == null)
throw new InvalidOperationException(string.Format("Unable to load Plugin Assembly [{0}] at: {1}", this.Id, assemblyFullPath));
PluginsLog.LogInitializingPluginAssembly(this.PluginAssembly);
// Check Manifest/Assembly Versions Match
if (this.Version != this.PluginAssembly.GetName().Version)
throw new InvalidOperationException(string.Format("The plugin [{0}] manifest version [{1}] doesn't match the plugin assembly [{2} : {3}]", this.Id, this.Version, assemblyFullPath, this.PluginAssembly.GetName().Version));
if (this.Type == null)
this.Type = this.PluginAssembly.GetType(this.TypeName, true, true);
if (this.ConfigurationHandlerType == null)
this.ConfigurationHandlerType = this.PluginAssembly.GetType(this.ConfigurationHandlerTypeName, true, true);
if (!string.IsNullOrEmpty(this.WebHandlerTypeName) && this.WebHandlerType == null)
this.WebHandlerType = this.PluginAssembly.GetType(this.WebHandlerTypeName, true, true);
// Update non-static values
this.StorageLocation = Path.Combine(dbContext.DiscoConfiguration.PluginStorageLocation, this.Id);
// Initialize Plugin
using (var pluginInstance = this.CreateInstance())
{
pluginInstance.Initalize(dbContext);
}
PluginsLog.LogInitializedPlugin(this);
// Initialize Plugin Features
if (Features != null)
{
foreach (var feature in Features)
{
feature.Initialize(dbContext, this);
}
}
else
{
Features = new List<PluginFeatureManifest>();
}
return true;
}
public PluginConfigurationHandler CreateConfigurationHandler()
{
// Configuration Handler is Required
if (this.ConfigurationHandlerType == null)
throw new ArgumentNullException("ConfigurationType");
if (!typeof(PluginConfigurationHandler).IsAssignableFrom(this.ConfigurationHandlerType))
throw new ArgumentException("The Plugin ConfigurationHandlerType must inherit Disco.Services.Plugins.PluginConfigurationHandler", "ConfigurationHandlerType");
var handler = (PluginConfigurationHandler)Activator.CreateInstance(this.ConfigurationHandlerType);
handler.Manifest = this;
return handler;
}
[JsonIgnore]
public bool HasWebHandler
{
get
{
return this.WebHandlerType != null;
}
}
public PluginWebHandler CreateWebHandler(Controller HostController)
{
// Web Handler is Not Required
if (this.WebHandlerType == null)
return null;
if (!typeof(PluginWebHandler).IsAssignableFrom(this.WebHandlerType))
throw new ArgumentException("The Plugin WebHandlerType must inherit Disco.Services.Plugins.PluginWebHandler", "WebHandlerType");
var handler = (PluginWebHandler)Activator.CreateInstance(this.WebHandlerType);
handler.Manifest = this;
handler.HostController = HostController;
return handler;
}
public Tuple<string, string> WebResourcePath(string Resource)
{
if (string.IsNullOrWhiteSpace(Resource))
throw new ArgumentNullException("Resource");
if (Resource.Contains(".."))
throw new ArgumentException("Resource Paths cannot navigate to the parent", "Resource");
var resourcePath = Path.Combine(this.PluginLocation, "WebResources", Resource.Replace(@"/", @"\"));
Tuple<string, DateTime> resourceHash;
string resourceKey = string.Format("{0}://{1}", this.Name, Resource);
if (WebResourceHashes.TryGetValue(resourceKey, out resourceHash))
{
#if DEBUG
var fileDateCheck = System.IO.File.GetLastWriteTime(resourcePath);
if (fileDateCheck == resourceHash.Item2)
#endif
return new Tuple<string, string>(resourcePath, resourceHash.Item1);
}
if (!File.Exists(resourcePath))
throw new FileNotFoundException(string.Format("Resource [{0}] not found", Resource), resourcePath);
var fileDate = System.IO.File.GetLastWriteTime(resourcePath);
var fileBytes = System.IO.File.ReadAllBytes(resourcePath);
if (fileBytes.Length > 0)
{
using (SHA256 sha = SHA256.Create())
{
byte[] hash = sha.ComputeHash(fileBytes);
resourceHash = new Tuple<string, DateTime>(HttpServerUtility.UrlTokenEncode(hash), fileDate);
}
}
WebResourceHashes[resourceKey] = resourceHash;
return new Tuple<string, string>(resourcePath, resourceHash.Item1);
}
}
}
+229
View File
@@ -0,0 +1,229 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.Routing;
using RazorGenerator.Mvc;
namespace Disco.Services.Plugins
{
public abstract class PluginWebHandler : IDisposable
{
public PluginManifest Manifest { get; set; }
public Controller HostController { get; set; }
public abstract ActionResult ExecuteAction(string ActionName);
public virtual void Dispose()
{
// Nothing in Base Class
}
#region Action Results
#region Compiled View
private static string[] _viewFileNames = new string[] { "cshtml" };
public ActionResult CompiledView(Type CompiledViewType, object Model, bool UseDiscoLayout)
{
string layoutPath = UseDiscoLayout ? "~/Views/Shared/_Layout.cshtml" : null;
IView v = new PrecompiledMvcView(this.HostController.Request.Path, layoutPath, CompiledViewType, false, _viewFileNames);
if (Model != null)
this.HostController.ViewData.Model = Model;
return new ViewResult { View = v, ViewData = this.HostController.ViewData, TempData = this.HostController.TempData };
}
public ActionResult CompiledView(Type CompiledViewType, bool UseDiscoLayout)
{
return this.CompiledView(CompiledViewType, null, UseDiscoLayout);
}
public ActionResult CompiledView(Type CompiledViewType, object Model)
{
return this.CompiledView(CompiledViewType, Model, true);
}
public ActionResult CompiledView(Type CompiledViewType)
{
return this.CompiledView(CompiledViewType, false, true);
}
public ActionResult CompiledPartialView(Type PartialCompiledViewType, object Model)
{
IView v = new PrecompiledMvcView(this.HostController.Request.Path, PartialCompiledViewType, false, _viewFileNames);
if (Model != null)
this.HostController.ViewData.Model = Model;
return new PartialViewResult { View = v, ViewData = this.HostController.ViewData, TempData = this.HostController.TempData };
}
public ActionResult CompiledPartialView(Type PartialCompiledViewType)
{
return this.CompiledView(PartialCompiledViewType, null);
}
#endregion
#region Content
public ActionResult Content(string content, string contentType, Encoding contentEncoding)
{
return new ContentResult { Content = content, ContentType = contentType, ContentEncoding = contentEncoding };
}
public ActionResult Content(string content, string contentType)
{
return this.Content(content, null, null);
}
public ActionResult Content(string content)
{
return this.Content(content, null);
}
#endregion
#region Json
public ActionResult Json(object data, JsonRequestBehavior behavior)
{
return new JsonResult { Data = data, ContentType = null, ContentEncoding = null, JsonRequestBehavior = behavior };
}
#endregion
#region File
public ActionResult File(Stream fileStream, string contentType)
{
return this.File(fileStream, contentType, null);
}
public ActionResult File(Stream fileStream, string contentType, string fileDownloadName)
{
return new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName };
}
public ActionResult File(byte[] fileContents, string contentType)
{
return this.File(fileContents, contentType, null);
}
public ActionResult File(byte[] fileContents, string contentType, string fileDownloadName)
{
return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };
}
#endregion
#region HttpNotFound
public ActionResult HttpNotFound(string statusDescription)
{
return new HttpNotFoundResult(statusDescription);
}
public ActionResult HttpNotFound()
{
return this.HttpNotFound(null);
}
#endregion
#region Redirect
public ActionResult RedirectToScheduledTaskStatus(string SessionId)
{
if (string.IsNullOrEmpty(SessionId))
throw new ArgumentNullException(SessionId);
return this.RedirectToAction("TaskStatus", "Logging", "Config", new { id = SessionId });
}
public ActionResult Redirect(string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException("url");
return new RedirectResult(url);
}
public ActionResult RedirectPermanent(string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException("url");
return new RedirectResult(url, true);
}
public ActionResult RedirectToPluginAction(string PluginAction)
{
if (string.IsNullOrEmpty(PluginAction))
throw new ArgumentNullException("PluginAction");
var routeValues = new RouteValueDictionary(new { PluginId = this.Manifest.Id, PluginAction = PluginAction });
string pluginActionUrl = UrlHelper.GenerateUrl("Plugin", null, null, routeValues, RouteTable.Routes, this.HostController.Request.RequestContext, false);
return new RedirectResult(pluginActionUrl, false);
}
public ActionResult RedirectToPluginResource(string Resource, bool? Download)
{
var resourcePath = this.Manifest.WebResourcePath(Resource);
var routeValues = new RouteValueDictionary(new { PluginId = this.Manifest.Id, res = Resource });
string pluginActionUrl = UrlHelper.GenerateUrl("Plugin_Resources", null, null, routeValues, RouteTable.Routes, this.HostController.Request.RequestContext, false);
pluginActionUrl += string.Format("?v={0}", resourcePath.Item2);
if (Download.HasValue && Download.Value)
{
pluginActionUrl += "&Download=true";
}
return new RedirectResult(pluginActionUrl, false);
}
public ActionResult RedirectToPluginResource(string Resource)
{
return this.RedirectToPluginResource(Resource, null);
}
public ActionResult RedirectToRoute(string routeName, object routeValues)
{
RouteValueDictionary routeValueDictionary;
if (routeValues != null)
routeValueDictionary = new RouteValueDictionary(routeValues);
else
routeValueDictionary = new RouteValueDictionary();
return new RedirectToRouteResult(routeName, routeValueDictionary);
}
public ActionResult RedirectToRoute(string routeName)
{
return this.RedirectToRoute(routeName, null);
}
public ActionResult RedirectToAction(string actionName, string controller, string areaName, object routeValues)
{
RouteValueDictionary routeValueDictionary;
if (routeValues != null)
routeValueDictionary = new RouteValueDictionary(routeValues);
else
routeValueDictionary = new RouteValueDictionary();
routeValueDictionary["action"] = actionName;
routeValueDictionary["controller"] = controller;
if (areaName != null)
routeValueDictionary["area"] = areaName;
return new RedirectToRouteResult(routeValueDictionary);
}
public ActionResult RedirectToAction(string actionName, string controller, string areaName)
{
return this.RedirectToAction(actionName, controller, areaName, null);
}
public ActionResult RedirectToAction(string actionName, string controller, object routeValues)
{
return this.RedirectToAction(actionName, controller, null, routeValues);
}
public ActionResult RedirectToAction(string actionName, string controller)
{
return this.RedirectToAction(actionName, controller, null, null);
}
public ActionResult RedirectToDiscoJob(int jobId)
{
return this.RedirectToAction("Show", "Job", null, new { id = jobId.ToString() });
}
public ActionResult RedirectToDiscoDevice(string DeviceSerialNumber)
{
return this.RedirectToAction("Show", "Device", null, new { id = DeviceSerialNumber });
}
public ActionResult RedirectToDiscoUser(string UserId)
{
return this.RedirectToAction("Show", "User", null, new { id = UserId });
}
#endregion
#endregion
}
}
@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace Disco.Services.Plugins
{
public abstract class PluginWebHandlerController : PluginWebHandler
{
public override ActionResult ExecuteAction(string ActionName)
{
var handlerType = this.GetType();
var methodDescriptor = FindControllerMethod(handlerType, ActionName);
if (methodDescriptor == null)
return this.HttpNotFound("Unknown Plugin Method");
var methodParams = BuildMethodParameters(handlerType, methodDescriptor.MethodInfo, ActionName, this.HostController);
return (ActionResult)methodDescriptor.MethodInfo.Invoke(this, methodParams);
}
private static WebHandlerCachedItem FindControllerMethod(Type Handler, string ActionName)
{
var descriptors = CacheWebHandler(Handler);
WebHandlerCachedItem method;
if (descriptors.TryGetValue(ActionName.ToLower(), out method))
return method; // Not Found
else
return null; // Not Found
}
private static object[] BuildMethodParameters(Type Handler, MethodInfo methodInfo, string ActionName, Controller HostController)
{
var methodParams = methodInfo.GetParameters();
var result = new object[methodParams.Length];
for (int i = 0; i < methodParams.Length; i++)
{
var methodParam = methodParams[i];
Type parameterType = methodParam.ParameterType;
IModelBinder modelBinder = ModelBinders.Binders.GetBinder(parameterType);
IValueProvider valueProvider = HostController.ValueProvider;
string parameterName = methodParam.Name;
ModelBindingContext bindingContext = new ModelBindingContext()
{
FallbackToEmptyPrefix = true,
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),
ModelName = parameterName,
ModelState = HostController.ViewData.ModelState,
PropertyFilter = (p) => true,
ValueProvider = valueProvider
};
var parameterValue = modelBinder.BindModel(HostController.ControllerContext, bindingContext);
if (parameterValue == null && methodParam.HasDefaultValue)
parameterValue = methodParam.DefaultValue;
result[i] = parameterValue;
//var paramInstance = Activator.CreateInstance(methodParam.ParameterType);
//IModelBinder binder = ModelBinders.Binders.GetBinder(methodParam.ParameterType);
//ModelBindingContext bindingContext = new ModelBindingContext
//{
// ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => paramInstance, methodParam.ParameterType),
// ModelName = methodParam.Name,
// ModelState = HostController.ModelState,
// PropertyFilter = (p) => true,
// ValueProvider = HostController.ValueProvider
//};
//binder.BindModel(HostController.ControllerContext, bindingContext);
//if (methodParam.HasDefaultValue && paramInstance == null)
// paramInstance = methodParam.DefaultValue;
//result[i] = paramInstance;
}
return result;
}
#region Method Cache
private static Dictionary<Type, Dictionary<string, WebHandlerCachedItem>> WebHandlerCachedItems = new Dictionary<Type, Dictionary<string, WebHandlerCachedItem>>();
private static Dictionary<string, WebHandlerCachedItem> CacheWebHandler(Type Handler)
{
Dictionary<string, WebHandlerCachedItem> result;
if (!WebHandlerCachedItems.TryGetValue(Handler, out result))
{
// Cache Miss
result = new Dictionary<string, WebHandlerCachedItem>();
var methods = Array.FindAll<MethodInfo>(Handler.GetMethods(BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), mi => { return !mi.IsSpecialName && typeof(ActionResult).IsAssignableFrom(mi.ReturnType); });
foreach (var method in methods)
{
var item = new WebHandlerCachedItem()
{
Method = method.Name,
MethodInfo = method
};
result.Add(item.Method.ToLower(), item);
}
WebHandlerCachedItems[Handler] = result;
}
return result;
}
private class WebHandlerCachedItem
{
public string Method { get; set; }
public MethodInfo MethodInfo { get; set; }
}
#endregion
}
}
+363
View File
@@ -0,0 +1,363 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Disco.Data.Repository;
using System.IO.Compression;
namespace Disco.Services.Plugins
{
public static class Plugins
{
private static Dictionary<Assembly, PluginManifest> _PluginAssemblyManifests;
private static Dictionary<string, PluginManifest> _PluginManifests;
internal static Dictionary<Type, string> FeatureCategoryDisplayNames;
private static object _PluginLock = new object();
public static string PluginPath { get; private set; }
public static PluginManifest GetPlugin(string PluginId, Type ContainsCategoryType)
{
if (_PluginManifests == null)
throw new InvalidOperationException("Plugins have not been initialized");
PluginManifest manifest;
if (_PluginManifests.TryGetValue(PluginId, out manifest))
{
if (ContainsCategoryType == null)
return manifest;
else
{
foreach (var featureManifest in manifest.Features)
{
if (ContainsCategoryType.IsAssignableFrom(featureManifest.CategoryType))
return manifest;
}
throw new InvalidFeatureCategoryTypeException(ContainsCategoryType, PluginId);
}
}
else
{
throw new UnknownPluginException(PluginId);
}
}
public static PluginManifest GetPlugin(string PluginId)
{
return GetPlugin(PluginId, null);
}
public static PluginManifest GetPlugin(Assembly PluginAssembly)
{
if (_PluginAssemblyManifests == null)
throw new InvalidOperationException("Plugins have not been initialized");
PluginManifest manifest;
if (_PluginAssemblyManifests.TryGetValue(PluginAssembly, out manifest))
{
return manifest;
}
else
{
throw new UnknownPluginException(PluginAssembly.FullName);
}
}
public static List<PluginManifest> GetPlugins()
{
if (_PluginManifests == null)
throw new InvalidOperationException("Plugins have not been initialized");
return _PluginManifests.Values.ToList();
}
public static PluginFeatureManifest GetPluginFeature(string PluginFeatureId, Type CategoryType)
{
if (_PluginManifests == null)
throw new InvalidOperationException("Plugins have not been initialized");
var featureManifest = _PluginManifests.Values.SelectMany(pm => pm.Features).Where(fm => fm.Id == PluginFeatureId).FirstOrDefault();
if (featureManifest == null)
throw new UnknownPluginException(PluginFeatureId, "Unknown Feature");
if (CategoryType == null)
return featureManifest;
else
if (CategoryType.IsAssignableFrom(featureManifest.CategoryType))
return featureManifest;
else
throw new InvalidFeatureCategoryTypeException(CategoryType, PluginFeatureId);
}
public static PluginFeatureManifest GetPluginFeature(string PluginFeatureId)
{
return GetPluginFeature(PluginFeatureId, null);
}
public static List<PluginFeatureManifest> GetPluginFeatures(Type FeatureCategoryType)
{
if (_PluginManifests == null)
throw new InvalidOperationException("Plugins have not been initialized");
return _PluginManifests.Values.SelectMany(pm => pm.Features).Where(fm => fm.CategoryType.IsAssignableFrom(FeatureCategoryType)).OrderBy(fm => fm.PluginManifest.Name).ToList();
}
public static List<PluginFeatureManifest> GetPluginFeatures()
{
if (_PluginManifests == null)
throw new InvalidOperationException("Plugins have not been initialized");
return _PluginManifests.Values.SelectMany(pm => pm.Features).ToList();
}
public static string PluginFeatureCategoryDisplayName(Type FeatureCategoryType)
{
if (FeatureCategoryType == null)
throw new ArgumentNullException("FeatureType");
string displayName;
if (FeatureCategoryDisplayNames.TryGetValue(FeatureCategoryType, out displayName))
return displayName;
else
throw new InvalidOperationException(string.Format("Unknown Plugin Feature Category Type: [{0}]", FeatureCategoryType.Name));
}
public static void InitalizePlugins(DiscoDataContext dbContext)
{
if (_PluginManifests == null)
{
lock (_PluginLock)
{
if (_PluginManifests == null)
{
Dictionary<string, PluginManifest> loadedPlugins = new Dictionary<string, PluginManifest>();
PluginPath = dbContext.DiscoConfiguration.PluginsLocation;
AppDomain appDomain = AppDomain.CurrentDomain;
// Subscribe to Assembly Resolving
appDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
DirectoryInfo pluginDirectoryRoot = new DirectoryInfo(PluginPath);
if (pluginDirectoryRoot.Exists)
{
foreach (DirectoryInfo pluginDirectory in pluginDirectoryRoot.EnumerateDirectories())
{
string pluginManifestFilename = Path.Combine(pluginDirectory.FullName, "manifest.json");
if (File.Exists(pluginManifestFilename))
{
PluginManifest pluginManifest = null;
try
{
pluginManifest = PluginManifest.FromPluginManifestFile(pluginManifestFilename);
if (pluginManifest != null)
{
if (loadedPlugins.ContainsKey(pluginManifest.Id))
throw new InvalidOperationException(string.Format("The plugin [{0}] is already initialized", pluginManifest.Id));
pluginManifest.InitializePlugin(dbContext);
loadedPlugins[pluginManifest.Id] = pluginManifest;
}
}
catch (Exception ex) { PluginsLog.LogInitializeException(pluginManifestFilename, ex); }
}
}
}
_PluginManifests = loadedPlugins;
ReinitializePluginEnvironment();
// Install Plugins - TEMPORARY? Workaround until UI in place? Or Useful for 'built-in' plugins?
if (pluginDirectoryRoot.Exists)
{
foreach (FileInfo pluginPackageFile in pluginDirectoryRoot.EnumerateFiles("*.discoPlugin", SearchOption.TopDirectoryOnly))
{
// Install Plugin
InstallPlugin(dbContext, pluginPackageFile.FullName);
// Delete Package File
pluginPackageFile.Delete();
}
}
}
}
}
}
private static void ReinitializePluginEnvironment()
{
FeatureCategoryDisplayNames = InitializeFeatureCategoryDetails(_PluginManifests.Values);
_PluginAssemblyManifests = _PluginManifests.Values.ToDictionary(p => p.PluginAssembly, p => p);
}
public static void InstallPlugin(DiscoDataContext dbContext, String PackageFilePath)
{
using (var packageStream = File.OpenRead(PackageFilePath))
{
InstallPlugin(dbContext, packageStream);
}
}
public static void InstallPlugin(DiscoDataContext dbContext, Stream PluginPackage)
{
if (_PluginManifests == null)
throw new InvalidOperationException("Plugins have not been initialized");
using (MemoryStream packageStream = new MemoryStream())
{
PluginPackage.CopyTo(packageStream);
packageStream.Position = 0;
using (ZipArchive packageArchive = new ZipArchive(packageStream, ZipArchiveMode.Read, false))
{
ZipArchiveEntry packageManifestEntry = packageArchive.GetEntry("manifest.json");
if (packageManifestEntry == null)
throw new InvalidDataException("The plugin package does not contain the 'manifest.json' entry");
PluginManifest packageManifest;
using (Stream packageManifestStream = packageManifestEntry.Open())
{
packageManifest = PluginManifest.FromPluginManifestFile(packageManifestStream);
}
lock (_PluginLock)
{
if (_PluginManifests == null)
throw new InvalidOperationException("Plugins have not been initialized");
// Ensure not already installed
if (_PluginManifests.ContainsKey(packageManifest.Id))
throw new InvalidOperationException(string.Format("The '{0} [{1}]' Plugin is already installed, please uninstall any existing versions before trying again", packageManifest.Name, packageManifest.Id));
string packagePath = Path.Combine(dbContext.DiscoConfiguration.PluginsLocation, packageManifest.Id);
// Force Delete of Existing Folder
if (Directory.Exists(packagePath))
Directory.Delete(packagePath, true);
Directory.CreateDirectory(packagePath);
// Extract Package Contents
foreach (var packageEntry in packageArchive.Entries)
{
// Determine Extraction Path
var packageEntryTarget = Path.Combine(packagePath, packageEntry.FullName);
// Create Sub Directories
Directory.CreateDirectory(Path.GetDirectoryName(packageEntryTarget));
using (var packageEntryStream = packageEntry.Open())
{
using (var packageTargetStream = File.Open(packageEntryTarget, FileMode.Create, FileAccess.Write, FileShare.None))
{
packageEntryStream.CopyTo(packageTargetStream);
}
}
}
// Reload Manifest
packageManifest = PluginManifest.FromPluginManifestFile(Path.Combine(packagePath, "manifest.json"));
// Initialize Plugin
packageManifest.InitializePlugin(dbContext);
// Add Plugin Manifest to Environment
_PluginManifests[packageManifest.Id] = packageManifest;
// Reinitialize Plugin Environment
ReinitializePluginEnvironment();
}
}
}
}
private static Dictionary<Type, string> InitializeFeatureCategoryDetails(IEnumerable<PluginManifest> pluginManifests)
{
Dictionary<Type, string> categoryDisplayNames = new Dictionary<Type, string>();
// Always add 'Other'
var otherFeatureType = typeof(Features.Other.OtherFeature);
categoryDisplayNames.Add(otherFeatureType, ((PluginFeatureCategoryAttribute)otherFeatureType.GetCustomAttributes(typeof(PluginFeatureCategoryAttribute), false).FirstOrDefault()).DisplayName);
foreach (var pluginManifest in pluginManifests)
{
foreach (var featureManifest in pluginManifest.Features)
{
if (!categoryDisplayNames.ContainsKey(featureManifest.CategoryType))
{
string displayName = null;
var displayAttributes = featureManifest.CategoryType.GetCustomAttributes(typeof(PluginFeatureCategoryAttribute), true);
if (displayAttributes != null && displayAttributes.Length > 0)
displayName = ((PluginFeatureCategoryAttribute)(displayAttributes[0])).DisplayName;
if (string.IsNullOrWhiteSpace(displayName))
displayName = featureManifest.CategoryType.Name;
categoryDisplayNames[featureManifest.CategoryType] = displayName;
}
}
}
return categoryDisplayNames;
}
#region Plugin Referenced Assemblies Resolving
public static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.RequestingAssembly.Location.StartsWith(PluginPath, StringComparison.InvariantCultureIgnoreCase) && _PluginManifests != null)
{
// Try best guess first
PluginManifest requestingPlugin = _PluginManifests.Values.Where(p => p.Type.Assembly == args.RequestingAssembly).FirstOrDefault();
if (requestingPlugin != null)
{
Assembly loadedAssembly = CurrentDomain_AssemblyResolve_ByPlugin(requestingPlugin, args);
if (loadedAssembly != null)
return loadedAssembly;
}
// Try all Plugin References
foreach (var pluginDef in _PluginManifests.Values)
{
Assembly loadedAssembly = CurrentDomain_AssemblyResolve_ByPlugin(pluginDef, args);
if (loadedAssembly != null)
return loadedAssembly;
}
}
return null;
}
private static Assembly CurrentDomain_AssemblyResolve_ByPlugin(PluginManifest pluginManifest, ResolveEventArgs args)
{
if (pluginManifest.AssemblyReferences != null)
{
string assemblyPath;
if (pluginManifest.AssemblyReferences.TryGetValue(args.Name, out assemblyPath))
{
var resolvedAssemblyPath = Path.Combine(pluginManifest.PluginLocation, assemblyPath);
try
{
Assembly loadedAssembly = Assembly.LoadFile(resolvedAssemblyPath);
PluginsLog.LogPluginReferenceAssemblyLoaded(args.Name, resolvedAssemblyPath, args.RequestingAssembly.FullName);
return loadedAssembly;
}
catch (Exception ex)
{
PluginsLog.LogPluginException(string.Format("Resolving Plugin Reference Assembly: '{0}' [{1}]; Requested by: '{2}' [{3}]; Disco.Plugins.DiscoPlugins.CurrentDomain_AssemblyResolve()", args.Name, resolvedAssemblyPath, args.RequestingAssembly.FullName, args.RequestingAssembly.Location), ex);
}
}
}
return null;
}
#endregion
}
}
+275
View File
@@ -0,0 +1,275 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Services.Logging;
using Disco.Services.Logging.Models;
using System.Reflection;
namespace Disco.Services.Plugins
{
public class PluginsLog : LogBase
{
private const int _ModuleId = 10;
public override string ModuleDescription { get { return "Plugins"; } }
public override int ModuleId { get { return _ModuleId; } }
public override string ModuleName { get { return "Plugins"; } }
public enum EventTypeIds
{
InitializingPlugins = 10,
InitializingPluginAssembly,
InitializedPlugin,
InitializedPluginFeature,
InitializeWarning = 15,
InitializeError,
InitializeException,
InitializeExceptionWithInner,
PluginException = 20,
PluginExceptionWithInner,
PluginReferenceAssemblyLoaded = 50,
PluginConfigurationLoaded = 100,
PluginConfigurationSaved = 104,
PluginWebControllerAccessed = 200
}
public static PluginsLog Current
{
get
{
return (PluginsLog)LogContext.LogModules[_ModuleId];
}
}
private static void Log(EventTypeIds EventTypeId, params object[] Args)
{
Current.Log((int)EventTypeId, Args);
}
public static void LogInitializingPlugins(string PluginDirectory)
{
Current.Log((int)EventTypeIds.InitializingPlugins, PluginDirectory);
}
public static void LogInitializingPluginAssembly(Assembly PluginAssembly)
{
Current.Log((int)EventTypeIds.InitializingPluginAssembly, PluginAssembly.FullName, PluginAssembly.Location);
}
public static void LogInitializedPlugin(PluginManifest Menifest)
{
Current.Log((int)EventTypeIds.InitializedPlugin, Menifest.Id, Menifest.Version.ToString(3), Menifest.Type.Name, Menifest.Type.Assembly.Location);
}
public static void LogInitializedPluginFeature(PluginManifest PluginMenifest, PluginFeatureManifest FeatureManifest)
{
Current.Log((int)EventTypeIds.InitializedPluginFeature, PluginMenifest.Id, FeatureManifest.Type.Name);
}
public static void LogInitializeWarning(string Warning)
{
Current.Log((int)EventTypeIds.InitializeWarning, Warning);
}
public static void LogInitializeError(string Error)
{
Current.Log((int)EventTypeIds.InitializeError, Error);
}
public static void LogPluginReferenceAssemblyLoaded(string AssemblyFullName, string AssemblyPath, string RequestedBy)
{
Current.Log((int)EventTypeIds.PluginReferenceAssemblyLoaded, AssemblyFullName, AssemblyPath, RequestedBy);
}
public static void LogPluginConfigurationLoaded(string PluginId, string UserId)
{
Current.Log((int)EventTypeIds.PluginConfigurationLoaded, PluginId, UserId);
}
public static void LogPluginConfigurationSaved(string PluginId, string UserId)
{
Current.Log((int)EventTypeIds.PluginConfigurationSaved, PluginId, UserId);
}
public static void LogPluginWebControllerAccessed(string PluginId, string PluginAction, string UserId)
{
Current.Log((int)EventTypeIds.PluginWebControllerAccessed, PluginId, PluginAction, UserId);
}
public static void LogInitializeException(string PluginFilename, Exception ex)
{
if (ex.InnerException != null)
{
Log(EventTypeIds.InitializeExceptionWithInner, PluginFilename, ex.GetType().Name, ex.Message, ex.StackTrace, ex.InnerException.GetType().Name, ex.InnerException.Message, ex.InnerException.StackTrace);
}
else
{
Log(EventTypeIds.InitializeException, PluginFilename, ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
public static void LogPluginException(string Component, Exception ex)
{
if (ex.InnerException != null)
{
Log(EventTypeIds.PluginExceptionWithInner, Component, ex.GetType().Name, ex.Message, ex.StackTrace, ex.InnerException.GetType().Name, ex.InnerException.Message, ex.InnerException.StackTrace);
}
else
{
Log(EventTypeIds.PluginException, Component, ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
protected override List<Logging.Models.LogEventType> LoadEventTypes()
{
return new System.Collections.Generic.List<LogEventType>
{
new LogEventType
{
Id = (int)EventTypeIds.InitializingPlugins,
ModuleId = _ModuleId,
Name = "Initializing Plugins",
Format = "Starting plugin discovery and initialization from: {0}",
Severity = (int)LogEventType.Severities.Information,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializingPluginAssembly,
ModuleId = _ModuleId,
Name = "Initializing Plugin Assembly",
Format = "Initializing Plugin Assembly: [{0}] From '{1}'",
Severity = (int)LogEventType.Severities.Information,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializedPlugin,
ModuleId = _ModuleId,
Name = "Initialized Plugin",
Format = "Initialized Plugin: '{0} (v{1})' [{2}] From '{3}'",
Severity = (int)LogEventType.Severities.Information,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializedPluginFeature,
ModuleId = _ModuleId,
Name = "Initialized Plugin Feature",
Format = "Initialized Plugin Feature: '{1}' From '{0}'",
Severity = (int)LogEventType.Severities.Information,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeWarning,
ModuleId = _ModuleId,
Name = "Initialize Warning",
Format = "Initialize Warning: {0}",
Severity = (int)LogEventType.Severities.Warning,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeError,
ModuleId = _ModuleId,
Name = "Initialize Error",
Format = "Initialize Error: {0}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeException,
ModuleId = _ModuleId,
Name = "Initialize Exception",
Format = "Exception: {0}; {1}: {2}; {3}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeExceptionWithInner,
ModuleId = _ModuleId,
Name = "Initialize Exception with Inner Exception",
Format = "Exception: {0}; {1}: {2}; {3}; Inner: {4}: {5}; {6}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginException,
ModuleId = _ModuleId,
Name = "Plugin Exception",
Format = "Exception: {0}; {1}: {2}; {3}",
Severity = (int)LogEventType.Severities.Error,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginExceptionWithInner,
ModuleId = _ModuleId,
Name = "Plugin Exception with Inner Exception",
Format = "Exception: {0}; {1}: {2}; {3}; Inner: {4}: {5}; {6}",
Severity = (int)LogEventType.Severities.Error,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginReferenceAssemblyLoaded,
ModuleId = _ModuleId,
Name = "Plugin Reference Assembly Loaded",
Format = "Loaded Plugin Reference Assembly: [{0}] From: '{1}'; Requested by: [{2}]",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginConfigurationLoaded,
ModuleId = _ModuleId,
Name = "Plugin Configuration Loaded",
Format = "Plugin Configuration Loaded: [{0}] by [{1}]",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginConfigurationSaved,
ModuleId = _ModuleId,
Name = "Plugin Configuration Saved",
Format = "Plugin Configuration Saved: [{0}] by [{1}]",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginWebControllerAccessed,
ModuleId = _ModuleId,
Name = "Plugin Web Controller Accessed",
Format = "Plugin Web Controller Accessed: Plugin [{0}], Action [{1}], By [{2}]",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
}
};
}
}
}
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Plugins
{
public class UnknownPluginException : Exception
{
private string _pluginRequested;
public string PluginRequested
{
get
{
return _pluginRequested;
}
}
public UnknownPluginException(string PluginRequested)
{
this._pluginRequested = PluginRequested;
}
public UnknownPluginException(string PluginRequested, string Message) : base(Message)
{
this._pluginRequested = PluginRequested;
}
public override string Message
{
get
{
return string.Format("Unknown Plugin Id: [{0}]", _pluginRequested);
}
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Disco.Services")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Disco.Services")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3f4b432d-2abd-4bc2-86cd-f90650b73930")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.2.0131.2002")]
[assembly: AssemblyFileVersion("1.2.0131.2002")]
+108
View File
@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;
using Disco.Data.Repository;
namespace Disco.Services.Tasks
{
public abstract class ScheduledTask : IJob
{
public abstract void InitalizeScheduledTask(DiscoDataContext dbContext);
internal protected ScheduledTaskStatus Status { get; private set; }
internal protected IJobExecutionContext ExecutionContext { get; private set; }
public abstract bool CancelInitiallySupported { get; }
public abstract bool SingleInstanceTask { get; }
public virtual bool IsSilent { get { return false; } }
public virtual bool LogExceptionsOnly { get { return false; } }
public abstract string TaskName { get; }
protected abstract void ExecuteTask();
#region Protected Triggers
/// <summary>
/// Schedules the Task to Begin Immediately
/// </summary>
protected ScheduledTaskStatus ScheduleTask()
{
return ScheduleTask(null, null);
}
/// <summary>
/// Schedules the Task to Begin Immediately
/// </summary>
/// <param name="DataMap">DataMap passed into the executing Task</param>
/// <returns></returns>
protected ScheduledTaskStatus ScheduleTask(JobDataMap DataMap)
{
return ScheduleTask(null, DataMap);
}
/// <summary>
/// Schedules the Task to Begin based on the Trigger
/// </summary>
/// <param name="Trigger">Trigger for the Task</param>
protected ScheduledTaskStatus ScheduleTask(TriggerBuilder Trigger)
{
return ScheduleTask(Trigger, null);
}
/// <summary>
/// Schedules the Task to Begin based on the Trigger including the DataMap
/// </summary>
/// <param name="Trigger">Trigger for the Task</param>
/// <param name="DataMap">DataMap passed into the executing Task</param>
/// <returns></returns>
protected ScheduledTaskStatus ScheduleTask(TriggerBuilder Trigger, JobDataMap DataMap)
{
if (Trigger == null)
Trigger = TriggerBuilder.Create(); // Defaults to Start Immediately
if (DataMap != null)
Trigger = Trigger.UsingJobData(DataMap);
return ScheduledTasks.RegisterTask(this, Trigger);
}
#endregion
public void Execute(IJobExecutionContext context)
{
// Task Status
this.ExecutionContext = context;
this.Status = context.GetDiscoScheduledTaskStatus();
if (this.Status == null)
this.Status = ScheduledTasks.RegisterTask(this);
try
{
if (!this.LogExceptionsOnly)
ScheduledTasksLog.LogScheduledTaskExecuted(this.Status.TaskName, this.Status.SessionId);
this.Status.Started();
this.ExecuteTask();
}
catch (Exception ex)
{
ScheduledTasksLog.LogScheduledTaskException(this.Status.TaskName, this.Status.SessionId, this.GetType(), ex);
this.Status.SetTaskException(ex);
}
finally
{
if (!this.Status.FinishedTimestamp.HasValue) // Scheduled Task Didn't Trigger 'Finished'
this.Status.Finished();
var nextTriggerTime = context.NextFireTimeUtc;
if (nextTriggerTime.HasValue)
{ // Continuous Task
this.Status.Reset(nextTriggerTime.Value.LocalDateTime);
}
else
{
this.UnregisterTask();
}
if (!this.LogExceptionsOnly)
ScheduledTasksLog.LogScheduledTaskFinished(this.Status.TaskName, this.Status.SessionId);
}
}
}
}
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;
namespace Disco.Services.Tasks
{
}
+351
View File
@@ -0,0 +1,351 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;
using System.Web.Script.Serialization;
namespace Disco.Services.Tasks
{
public class ScheduledTaskStatus
{
#region Backing Fields
private string _sessionId;
private string _triggerKey;
private string _taskName;
private Type _taskType;
private bool _isSilent;
private byte _progress;
private string _currentProcess;
private string _currentDescription;
private Exception _taskException;
private bool _cancelInitiallySupported;
private bool _cancelSupported;
private bool _isCanceling;
private DateTime? _startedTimestamp;
private DateTime? _nextScheduledTimestamp;
private DateTime? _finishedTimestamp;
private string _finishedMessage;
private string _finishedUrl;
private int _statusVersion = 0;
#endregion
#region Properties
public string SessionId { get { return this._sessionId; } }
public string TriggerKey { get { return this._triggerKey; } }
public string TaskName { get { return this._taskName; } }
public Type TaskType { get { return this._taskType; } }
public bool IsSilent { get { return this._isSilent; } }
public byte Progress { get { return this._progress; } }
public string CurrentProcess { get { return this._currentProcess; } }
public string CurrentDescription { get { return this._currentDescription; } }
public Exception TaskException { get { return this._taskException; } }
public bool CancelSupported { get { return this._cancelSupported; } }
public bool IsCanceling { get { return this._isCanceling; } }
public DateTime? StartedTimestamp { get { return this._startedTimestamp; } }
public DateTime? FinishedTimestamp { get { return this._finishedTimestamp; } }
public DateTime? NextScheduledTimestamp { get { return this._nextScheduledTimestamp; } }
public string FinishedMessage { get { return this._finishedMessage; } }
public string FinishedUrl { get { return this._finishedUrl; } }
public int StatusVersion { get { return this._statusVersion; } }
public bool IsRunning
{
get
{
return _startedTimestamp.HasValue && !_finishedTimestamp.HasValue;
}
}
#endregion
#region Events
public delegate void UpdatedEvent(ScheduledTaskStatus sender, string[] ChangedProperties);
public delegate void CancelingEvent(ScheduledTaskStatus sender);
public event UpdatedEvent Updated;
public event CancelingEvent Canceling;
#endregion
public ScheduledTaskStatus(ScheduledTask Task, string SessionId, string TriggerKey, string FinishedUrl = null)
{
this._taskName = Task.TaskName;
this._taskType = Task.GetType();
this._sessionId = SessionId;
this._triggerKey = TriggerKey;
this._cancelInitiallySupported = Task.CancelInitiallySupported;
this._cancelSupported = this._cancelInitiallySupported;
this._finishedUrl = FinishedUrl;
this._currentProcess = "Scheduled";
this._currentDescription = "Scheduled Task for Execution";
this._progress = 0;
}
#region Progress Actions
public void UpdateStatus(byte Progress)
{
this._progress = Progress;
UpdateTriggered(new string[] { "Progress" });
}
public void UpdateStatus(double Progress)
{
UpdateStatus((byte)Progress);
}
public void UpdateStatus(string CurrentDescription)
{
this._currentDescription = CurrentDescription;
UpdateTriggered(new string[] { "CurrentDescription" });
}
public void UpdateStatus(byte Progress, string CurrentDescription)
{
this._progress = Progress;
this._currentDescription = CurrentDescription;
UpdateTriggered(new string[] { "Progress", "CurrentDescription" });
}
public void UpdateStatus(double Progress, string CurrentDescription)
{
UpdateStatus((byte)Progress, CurrentDescription);
}
public void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription)
{
this._progress = Progress;
this._currentProcess = CurrentProcess;
this._currentDescription = CurrentDescription;
UpdateTriggered(new string[] { "Progress", "CurrentProcess", "CurrentDescription" });
}
public void UpdateStatus(double Progress, string CurrentProcess, string CurrentDescription)
{
UpdateStatus((byte)Progress, CurrentProcess, CurrentDescription);
}
#endregion
#region State Actions
public bool Canceled()
{
if (!this._isCanceling)
{
if (_cancelSupported)
{ // Cancelling
this._isCanceling = true;
UpdateTriggered(new string[] { "IsCancelling" });
if (this.Canceling != null)
Canceling(this);
return true;
}
else
{ // Cancelling not supported
return false;
}
}
else
{ // Already Cancelling
return true;
}
}
public void SetCancelSupported(bool CancelSupported)
{
if (this._cancelSupported != CancelSupported)
{
this._cancelSupported = CancelSupported;
UpdateTriggered(new string[] { "CancelSupported" });
}
}
public void SetTaskException(Exception TaskException)
{
if (this._taskException != TaskException)
{
this._taskException = TaskException;
UpdateTriggered(new string[] { "TaskException" });
}
}
public void SetIsSilent(bool IsSilent)
{
if (this._isSilent != IsSilent)
this._isSilent = IsSilent;
}
public void SetFinishedUrl(string FinishedUrl)
{
if (this._finishedUrl != FinishedUrl)
{
this._finishedUrl = FinishedUrl;
UpdateTriggered(new string[] { "FinishedUrl" });
}
}
public void SetFinishedMessage(string FinishedMessage)
{
if (this._finishedMessage != FinishedMessage)
{
this._finishedMessage = FinishedMessage;
UpdateTriggered(new string[] { "FinishedMessage" });
}
}
public void SetNextScheduledTimestamp(DateTime? NextScheduledTimestamp)
{
if (this._nextScheduledTimestamp != NextScheduledTimestamp)
{
this._nextScheduledTimestamp = NextScheduledTimestamp;
UpdateTriggered(new string[] { "NextScheduledTimestamp" });
}
}
public void Started()
{
List<string> changedProperties = new List<string>() { "IsRunning", "StartedTimestamp" };
this._startedTimestamp = DateTime.Now;
if (this._nextScheduledTimestamp != null)
{
this._nextScheduledTimestamp = null;
changedProperties.Add("NextScheduledTimestamp");
}
if (this._finishedTimestamp != null)
{
this._finishedTimestamp = null;
changedProperties.Add("FinishedTimestamp");
}
if (this._progress != 0)
{
this._progress = 0;
changedProperties.Add("Progress");
}
if (this._currentProcess != "Starting")
{
this._currentProcess = "Starting";
changedProperties.Add("CurrentProcess");
}
if (this._currentDescription != "Initializing Task for Execution")
{
this._currentDescription = "Initializing Task for Execution";
changedProperties.Add("CurrentDescription");
}
if (this._taskException != null)
{
this._taskException = null;
changedProperties.Add("TaskException");
}
if (this._cancelSupported != this._cancelInitiallySupported)
{
this._cancelSupported = this._cancelInitiallySupported;
changedProperties.Add("CancelSupported");
}
{
this._isCanceling = false;
changedProperties.Add("IsCanceling");
}
if (this._isCanceling)
{
this._isCanceling = false;
changedProperties.Add("IsCanceling");
}
UpdateTriggered(changedProperties.ToArray());
}
public void Finished()
{
Finished(this._finishedMessage, this._finishedUrl);
}
public void Finished(string FinishedMessage, string FinishedUrl)
{
List<string> changedProperties = new List<string>() { "IsRunning", "FinishedTimestamp" };
this._finishedTimestamp = DateTime.Now;
if (FinishedMessage != this._finishedMessage)
{
this._finishedMessage = FinishedMessage;
changedProperties.Add("FinishedMessage");
}
if (FinishedUrl != this._finishedUrl)
{
this._finishedUrl = FinishedUrl;
changedProperties.Add("FinishedUrl");
}
if (this._isCanceling)
{
this._isCanceling = false;
changedProperties.Add("IsCanceling");
}
UpdateTriggered(changedProperties.ToArray());
}
public void Reset(DateTime? NextScheduledTimestamp)
{
List<string> changedProperties = new List<string>();
if (this._nextScheduledTimestamp != NextScheduledTimestamp)
{
this._nextScheduledTimestamp = NextScheduledTimestamp;
changedProperties.Add("NextScheduledTimestamp");
}
if (this._startedTimestamp != null)
{
this._startedTimestamp = null;
changedProperties.Add("StartedTimestamp");
}
if (this._finishedTimestamp != null)
{
this._finishedTimestamp = null;
changedProperties.Add("FinishedTimestamp");
}
if (this._finishedMessage != null)
{
this._finishedMessage = null;
changedProperties.Add("FinishedMessage");
}
if (this._finishedUrl != null)
{
this._finishedUrl = null;
changedProperties.Add("FinishedUrl");
}
if (this._progress != 0)
{
this._progress = 0;
changedProperties.Add("Progress");
}
if (this._currentProcess != "Scheduled")
{
this._currentProcess = "Scheduled";
changedProperties.Add("CurrentProcess");
}
if (this._currentDescription != "Scheduled Task for Execution")
{
this._currentDescription = "Scheduled Task for Execution";
changedProperties.Add("CurrentDescription");
}
if (this._isCanceling)
{
this._isCanceling = false;
changedProperties.Add("IsCanceling");
}
UpdateTriggered(changedProperties.ToArray());
}
#endregion
private void UpdateTriggered(string[] ChangedProperties)
{
this._statusVersion++;
if (Updated != null)
Updated(this, ChangedProperties);
if (!_isSilent)
ScheduledTasksLiveStatusService.Broadcast(ScheduledTaskStatusLive.FromScheduledTaskStatus(this, ChangedProperties));
}
}
}
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Tasks
{
public class ScheduledTaskStatusLive
{
public string TaskName { get; set; }
public string SessionId { get; set; }
public byte Progress { get; set; }
public string CurrentProcess { get; set; }
public string CurrentDescription { get; set; }
public string TaskExceptionMessage { get; set; }
public bool CancelSupported { get; set; }
public bool IsCancelling { get; set; }
public bool IsRunning { get; set; }
public DateTime? StartedTimestamp { get; set; }
public DateTime? FinishedTimestamp { get; set; }
public DateTime? NextScheduledTimestamp { get; set; }
public string FinishedMessage { get; set; }
public string FinishedUrl { get; set; }
public int StatusVersion { get; set; }
public string[] ChangedProperties { get; set; }
public static ScheduledTaskStatusLive FromScheduledTaskStatus(ScheduledTaskStatus Status, string[] ChangedProperties)
{
return new ScheduledTaskStatusLive()
{
TaskName = Status.TaskName,
SessionId = Status.SessionId,
Progress = Status.Progress,
CurrentProcess = Status.CurrentProcess,
CurrentDescription = Status.CurrentDescription,
CancelSupported = Status.CancelSupported,
TaskExceptionMessage = (Status.TaskException == null ? null : Status.TaskException.Message),
IsCancelling = Status.IsCanceling,
IsRunning = Status.IsRunning,
StartedTimestamp = Status.StartedTimestamp,
FinishedTimestamp = Status.FinishedTimestamp,
NextScheduledTimestamp = Status.NextScheduledTimestamp,
FinishedMessage = Status.FinishedMessage,
FinishedUrl = Status.FinishedUrl,
StatusVersion = Status.StatusVersion,
ChangedProperties = ChangedProperties
};
}
}
}
+190
View File
@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;
using Quartz.Impl;
using Disco.Data.Repository;
namespace Disco.Services.Tasks
{
public static class ScheduledTasks
{
internal const string SchedulerGroupName = "DiscoScheduledTasks";
private static IScheduler _TaskScheduler;
private static object _RunningTasksLock = new object();
private static List<ScheduledTaskStatus> _RunningTasks = new List<ScheduledTaskStatus>();
public static void InitalizeScheduledTasks(DiscoDataContext dbContext, ISchedulerFactory SchedulerFactory)
{
ScheduledTasksLog.LogInitializingScheduledTasks();
try
{
_TaskScheduler = SchedulerFactory.GetScheduler();
_TaskScheduler.Start();
// Scheduled Cleanup
ScheduledTaskCleanup.Schedule(_TaskScheduler);
// Discover DiscoScheduledTask
var appDomain = AppDomain.CurrentDomain;
var scheduledTaskTypes = (from a in appDomain.GetAssemblies()
where !a.GlobalAssemblyCache && !a.IsDynamic
from type in a.GetTypes()
where typeof(ScheduledTask).IsAssignableFrom(type) && !type.IsAbstract
select type);
foreach (Type scheduledTaskType in scheduledTaskTypes)
{
ScheduledTask instance = (ScheduledTask)Activator.CreateInstance(scheduledTaskType);
try
{
instance.InitalizeScheduledTask(dbContext);
}
catch (Exception ex)
{
ScheduledTasksLog.LogInitializeException(ex, scheduledTaskType);
}
}
}
catch (Exception ex)
{
ScheduledTasksLog.LogInitializeException(ex);
}
}
public static ScheduledTaskStatus GetTaskStatus(string TaskSessionId)
{
return _RunningTasks.Where(t => t.SessionId == TaskSessionId).FirstOrDefault();
}
public static List<ScheduledTaskStatus> GetTaskStatuses(Type TaskType)
{
return _RunningTasks.Where(t => t.TaskType == TaskType).ToList();
}
public static List<ScheduledTaskStatus> GetTaskStatuses()
{
return _RunningTasks.ToList();
}
public static ScheduledTaskStatus RegisterTask(ScheduledTask Task)
{
return RegisterTask(Task, null);
}
public static ScheduledTaskStatus RegisterTask(ScheduledTask Task, TriggerBuilder TaskBuilder)
{
var sessionId = Guid.NewGuid().ToString("D");
var triggerKey = GenerateTriggerKey();
var taskType = Task.GetType();
var taskStatus = new ScheduledTaskStatus(Task, sessionId, triggerKey.Name);
lock (_RunningTasksLock)
{
if (Task.SingleInstanceTask)
{
var existingGuid = _RunningTasks.Where(t => t.IsRunning && t.TaskType == taskType).Select(t => t.SessionId).FirstOrDefault();
if (existingGuid != null)
throw new InvalidOperationException(string.Format("This Single-Instance Task is already running, SessionId: {0}", existingGuid));
}
_RunningTasks.Add(taskStatus);
}
if (TaskBuilder != null)
{
ITrigger trigger = TaskBuilder.WithIdentity(triggerKey).Build();
IJobDetail jobDetails = new JobDetailImpl(sessionId, taskType)
{
Description = Task.TaskName,
JobDataMap = trigger.JobDataMap
};
_TaskScheduler.ScheduleJob(jobDetails, trigger);
var nextTriggerTime = trigger.GetNextFireTimeUtc();
if (nextTriggerTime.HasValue)
taskStatus.SetNextScheduledTimestamp(nextTriggerTime.Value.LocalDateTime);
}
return taskStatus;
}
public static bool UnregisterTask(this ScheduledTask Task)
{
lock (_RunningTasksLock)
{
if (_RunningTasks.Contains(Task.Status))
{
//_RunningTasks.Remove(Task.Status);
_TaskScheduler.UnscheduleJob(Task.ExecutionContext.Trigger.Key);
return true;
}
}
return false;
}
public static bool UnregisterTask(this ScheduledTaskStatus TaskStatus)
{
lock (_RunningTasksLock)
{
if (_RunningTasks.Contains(TaskStatus))
{
//_RunningTasks.Remove(Task.Status);
_TaskScheduler.UnscheduleJob(new TriggerKey(TaskStatus.TriggerKey, SchedulerGroupName));
return true;
}
}
return false;
}
public static TriggerKey GenerateTriggerKey()
{
return new TriggerKey(Guid.NewGuid().ToString("D"), SchedulerGroupName);
}
public static ScheduledTaskStatus GetDiscoScheduledTaskStatus(this IJobExecutionContext context)
{
return GetTaskStatus(context.JobDetail.Key.Name);
}
private class ScheduledTaskCleanup : IJob
{
public void Execute(IJobExecutionContext context)
{
lock (ScheduledTasks._RunningTasksLock)
{
// Lifetime = 5mins
var expiredTime = DateTime.Now.AddMinutes(-1);
var expiredTasks = ScheduledTasks._RunningTasks.Where(
t => !t.IsRunning &&
!t.NextScheduledTimestamp.HasValue &&
t.FinishedTimestamp < expiredTime
).ToArray();
foreach (var expiredTask in expiredTasks)
ScheduledTasks._RunningTasks.Remove(expiredTask);
}
}
public static void Schedule(IScheduler TaskScheduler)
{
// Next 10min interval
DateTime now = DateTime.Now;
int mins = (10 - (now.Minute % 10));
if (mins < 2)
mins += 10;
DateTimeOffset startAt = new DateTimeOffset(now).AddMinutes(mins).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
ITrigger trigger = TriggerBuilder.Create()
.StartAt(startAt)
.WithSchedule(SimpleScheduleBuilder.RepeatMinutelyForever(10))
.WithIdentity("ScheduledTaskCleanupTrigger", ScheduledTasks.SchedulerGroupName + "_System")
.Build();
IJobDetail job = JobBuilder.Create<ScheduledTaskCleanup>()
.WithIdentity("ScheduledTaskCleanupJob", ScheduledTasks.SchedulerGroupName + "_System")
.Build();
_TaskScheduler.ScheduleJob(job, trigger);
}
}
}
}
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SignalR;
using SignalR.Hosting.AspNet;
using SignalR.Infrastructure;
namespace Disco.Services.Tasks
{
public class ScheduledTasksLiveStatusService : PersistentConnection
{
protected override System.Threading.Tasks.Task OnReceivedAsync(IRequest request, string connectionId, string data)
{
// Add to Group
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
{
var groups = data.Substring(13).Split(',');
foreach (var g in groups)
{
this.Groups.Add(connectionId, g);
}
}
return base.OnReceivedAsync(request, connectionId, data);
}
internal static void Broadcast(ScheduledTaskStatusLive SessionStatus)
{
//var message = Models.LogLiveEvent.Create(logModule, eventType, Timestamp, Arguments);
var connectionManager = GlobalHost.ConnectionManager; //AspNetHost.DependencyResolver.Resolve<IConnectionManager>();
var connectionContext = connectionManager.GetConnectionContext<ScheduledTasksLiveStatusService>();
connectionContext.Groups.Send(_GroupNameAll, SessionStatus);
connectionContext.Groups.Send(SessionStatus.SessionId, SessionStatus);
}
private const string _GroupNameAll = "__All";
//private static string _QualifiedSessionName = typeof(ScheduledTasksLiveStatusService).FullName + ".";
//private static string _QualifiedSessionNameAll = _QualifiedSessionName + "__All";
//private static string LiveStatusGroup(string SessionId)
//{
// return string.Concat(_QualifiedSessionName, SessionId);
//}
public static string LiveStatusAll
{
get
{
//return _QualifiedTypeNameAll;
return _GroupNameAll;
}
}
}
}
+196
View File
@@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Services.Logging;
using Disco.Services.Logging.Models;
namespace Disco.Services.Tasks
{
public class ScheduledTasksLog : LogBase
{
private const int _ModuleId = 20;
public override string ModuleDescription { get { return "Scheduled Tasks"; } }
public override int ModuleId { get { return _ModuleId; } }
public override string ModuleName { get { return "ScheduledTasks"; } }
public enum EventTypeIds
{
InitializingScheduledTasks = 10,
InitializeException = 15,
InitializeExceptionWithInner,
InitializeScheduledTasksException,
InitializeScheduledTasksExceptionWithInner,
ScheduledTasksException = 30,
ScheduledTasksExceptionWithInner,
ScheduledTaskExecuted = 50,
ScheduledTaskFinished = 80,
}
public static ScheduledTasksLog Current
{
get
{
return (ScheduledTasksLog)LogContext.LogModules[_ModuleId];
}
}
private static void Log(EventTypeIds EventTypeId, params object[] Args)
{
Current.Log((int)EventTypeId, Args);
}
public static void LogInitializingScheduledTasks()
{
Current.Log((int)EventTypeIds.InitializingScheduledTasks);
}
public static void LogScheduledTaskExecuted(string TaskName, string SessionId)
{
Current.Log((int)EventTypeIds.ScheduledTaskExecuted, TaskName, SessionId);
}
public static void LogScheduledTaskFinished(string TaskName, string SessionId)
{
Current.Log((int)EventTypeIds.ScheduledTaskFinished, TaskName, SessionId);
}
public static void LogInitializeException(Exception ex)
{
if (ex.InnerException != null)
{
Log(EventTypeIds.InitializeExceptionWithInner, ex.GetType().Name, ex.Message, ex.StackTrace, ex.InnerException.GetType().Name, ex.InnerException.Message, ex.InnerException.StackTrace);
}
else
{
Log(EventTypeIds.InitializeException, ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
public static void LogInitializeException(Exception ex, Type ScheduledTaskType)
{
if (ex.InnerException != null)
{
Log(EventTypeIds.InitializeScheduledTasksExceptionWithInner, ScheduledTaskType.Name, ScheduledTaskType.Assembly.Location, ex.GetType().Name, ex.Message, ex.StackTrace, ex.InnerException.GetType().Name, ex.InnerException.Message, ex.InnerException.StackTrace);
}
else
{
Log(EventTypeIds.InitializeScheduledTasksException, ScheduledTaskType.Name, ScheduledTaskType.Assembly.Location, ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
public static void LogScheduledTaskException(string ScheduledTaskName, string SessionId, Type ScheduledTaskType, Exception ex)
{
if (ex.InnerException != null)
{
Log(EventTypeIds.ScheduledTasksExceptionWithInner, ScheduledTaskName, SessionId, ScheduledTaskType.Assembly.Location, ex.GetType().Name, ex.Message, ex.StackTrace, ex.InnerException.GetType().Name, ex.InnerException.Message, ex.InnerException.StackTrace);
}
else
{
Log(EventTypeIds.ScheduledTasksException, ScheduledTaskName, SessionId, ScheduledTaskType.Assembly.Location, ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
protected override List<Logging.Models.LogEventType> LoadEventTypes()
{
return new System.Collections.Generic.List<LogEventType>
{
new LogEventType
{
Id = (int)EventTypeIds.InitializingScheduledTasks,
ModuleId = _ModuleId,
Name = "Initializing Scheduled Tasks",
Format = "Starting Scheduled Task discovery and initialization",
Severity = (int)LogEventType.Severities.Information,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeException,
ModuleId = _ModuleId,
Name = "Initialize Exception",
Format = "Exception: {0}: {1}; {2}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeExceptionWithInner,
ModuleId = _ModuleId,
Name = "Initialize Exception with Inner Exception",
Format = "Exception: {0}: {1}; {2}; Inner: {3}: {4}; {5}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeScheduledTasksException,
ModuleId = _ModuleId,
Name = "Initialize Task Exception",
Format = "[{0}] At '{1}'; Exception: {2}: {3}; {4}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeScheduledTasksExceptionWithInner,
ModuleId = _ModuleId,
Name = "Initialize Task Exception with Inner Exception",
Format = "[{0}] At '{1}'; Exception: {2}: {3}; {4}; Inner: {5}: {6}; {7}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.ScheduledTasksException,
ModuleId = _ModuleId,
Name = "Scheduled Task Exception",
Format = "Task Name: {0}; SessionId: {1}; At: '{2}'; Exception: {3}: {4}; {5}",
Severity = (int)LogEventType.Severities.Error,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.ScheduledTasksExceptionWithInner,
ModuleId = _ModuleId,
Name = "Scheduled Task Exception with Inner Exception",
Format = "Task Name: {0}; SessionId: {1}; At: '{2}'; Exception: {3}: {4}; {5}; Inner: {6}: {7}; {8}",
Severity = (int)LogEventType.Severities.Error,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.ScheduledTaskExecuted,
ModuleId = _ModuleId,
Name = "Scheduled Task Started",
Format = "Scheduled Task Started: {0}; Session Id: {1}",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.ScheduledTaskFinished,
ModuleId = _ModuleId,
Name = "Scheduled Task Finished",
Format = "Scheduled Task Finished: {0}; Session Id: {1}",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
}
};
}
}
}
@@ -0,0 +1,304 @@
using Disco.Services.Logging;
using Disco.Services.Logging.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Disco.Services.Plugins.Categories.CertificateProvider
{
public class CertificateProvidersLog : LogBase
{
public enum EventTypeIds
{
RetrievalStarting = 10,
RetrievalProgress,
RetrievalFinished,
RetrievalWarning = 15,
RetrievalError,
RetrievalCertificateStarting = 20,
RetrievalCertificateFinished = 22,
RetrievalCertificateWarning = 25,
RetrievalCertificateError,
Allocated = 40,
AllocationFailed = 50
}
private const int _ModuleId = 60;
private static bool _IsCertificateRetrievalProcessing;
private static string _CertificateRetrievalStatus;
private static int _CertificateRetrievalProgress;
public static CertificateProvidersLog Current
{
get
{
return (CertificateProvidersLog)LogContext.LogModules[60];
}
}
public static bool IsCertificateRetrievalProcessing
{
get
{
return CertificateProvidersLog._IsCertificateRetrievalProcessing;
}
}
public override string ModuleDescription
{
get
{
return "Certificate Providers";
}
}
public override int ModuleId
{
get
{
return 60;
}
}
public override string ModuleName
{
get
{
return "CertificateProviders";
}
}
[System.Diagnostics.DebuggerNonUserCode]
public CertificateProvidersLog()
{
}
private static void Log(CertificateProvidersLog.EventTypeIds EventTypeId, params object[] Args)
{
CertificateProvidersLog.Current.Log((int)EventTypeId, Args);
}
public static void LogRetrievalStarting(int CertificateCount, int CertificateIdFrom, int CertificateIdTo)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalStarting, new object[]
{
CertificateCount,
CertificateIdFrom,
CertificateIdTo
});
}
public static void LogRetrievalFinished()
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalFinished, new object[0]);
}
public static void LogRetrievalWarning(string Message)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalWarning, new object[]
{
Message
});
}
public static void LogRetrievalError(string Message)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalError, new object[]
{
Message
});
}
public static void LogRetrievalCertificateStarting(string CertificateId)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalCertificateStarting, new object[]
{
CertificateId
});
}
public static void LogRetrievalCertificateFinished(string CertificateId)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalCertificateFinished, new object[]
{
CertificateId
});
}
public static void LogRetrievalCertificateWarning(string CertificateId, string Message)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalCertificateWarning, new object[]
{
CertificateId,
Message
});
}
public static void LogRetrievalCertificateError(string CertificateId, string Message)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalCertificateError, new object[]
{
CertificateId,
Message
});
}
public static void LogAllocated(string CertificateId, string DeviceSerialNumber)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.Allocated, new object[]
{
CertificateId,
DeviceSerialNumber
});
}
public static void LogAllocationFailed(string DeviceSerialNumber)
{
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.AllocationFailed, new object[]
{
DeviceSerialNumber
});
}
public static void LogCertificateRetrievalProgress(bool? IsProcessing, int? Progress, string Status)
{
bool flag = IsProcessing.HasValue;
if (flag)
{
CertificateProvidersLog._IsCertificateRetrievalProcessing = IsProcessing.Value;
}
flag = CertificateProvidersLog._IsCertificateRetrievalProcessing;
if (flag)
{
bool flag2 = Status != null;
if (flag2)
{
CertificateProvidersLog._CertificateRetrievalStatus = Status;
}
flag2 = Progress.HasValue;
if (flag2)
{
CertificateProvidersLog._CertificateRetrievalProgress = Progress.Value;
}
}
else
{
CertificateProvidersLog._CertificateRetrievalStatus = null;
CertificateProvidersLog._CertificateRetrievalProgress = 0;
}
CertificateProvidersLog.Log(CertificateProvidersLog.EventTypeIds.RetrievalProgress, new object[]
{
CertificateProvidersLog._IsCertificateRetrievalProcessing,
CertificateProvidersLog._CertificateRetrievalProgress,
CertificateProvidersLog._CertificateRetrievalStatus
});
}
protected override System.Collections.Generic.List<LogEventType> LoadEventTypes()
{
return new System.Collections.Generic.List<LogEventType>
{
new LogEventType
{
Id = 10,
ModuleId = 60,
Name = "Retrieval Starting",
Format = "Starting retrieval of {0} certificate/s ({1} to {2})",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 11,
ModuleId = 60,
Name = "Retrieval Progress",
Format = "Processing: {0}; {1}% Complete; Status: {2}",
Severity = 0,
UseLive = true,
UsePersist = false,
UseDisplay = false
},
new LogEventType
{
Id = 12,
ModuleId = 60,
Name = "Retrieval Finished",
Format = "Retrieval of Certificates Complete",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 15,
ModuleId = 60,
Name = "Retrieval Warning",
Format = "Retrieval Warning: {0}",
Severity = 1,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 16,
ModuleId = 60,
Name = "Retrieval Error",
Format = "Retrieval Error: {0}",
Severity = 2,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 20,
ModuleId = 60,
Name = "Retrieval Certificate Starting",
Format = "Retrieving Certificate: {0}",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 22,
ModuleId = 60,
Name = "Retrieval Certificate Finished",
Format = "Certificate Retrieved: {0}",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 25,
ModuleId = 60,
Name = "Retrieval Certificate Warning",
Format = "{0} Certificate Warning: {1}",
Severity = 1,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 26,
ModuleId = 60,
Name = "Retrieval Certificate Error",
Format = "{0} Certificate Error: {1}",
Severity = 2,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 40,
ModuleId = 60,
Name = "Allocated",
Format = "Certificate {0} allocated to {1}",
Severity = 0,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = 50,
ModuleId = 60,
Name = "Allocation Failed",
Format = "No certificates available for Device: {0}",
Severity = 2,
UseLive = true,
UsePersist = true,
UseDisplay = true
}
};
}
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Data.Repository;
using Disco.Models.Repository;
namespace Disco.Services.Plugins.Categories.CertificateProvider
{
[PluginCategory(DisplayName = "Certificate Providers")]
public abstract class CertificateProviderPlugin : Plugin
{
public override sealed Type PluginCategoryType
{
get { return typeof(CertificateProviderPlugin); }
}
// Certificate Plugin Requirements
public abstract string CertificateProviderId { get; }
public abstract Tuple<DeviceCertificate, List<string>> AllocateCertificate(DiscoDataContext dbContext, Device Device);
}
}
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Plugins.Categories.InteroperabilityProvider
{
[PluginCategory(DisplayName = "Interoperability Providers")]
public abstract class InteroperabilityProviderPlugin : Plugin
{
public override sealed Type PluginCategoryType
{
get { return typeof(InteroperabilityProviderPlugin); }
}
}
}
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Disco.Data.Repository;
using Disco.Models.BI.Config;
using Disco.Models.Repository;
namespace Disco.Services.Plugins.Categories.WarrantyProvider
{
[PluginCategory(DisplayName = "Warranty Providers")]
public abstract class WarrantyProviderPlugin : Plugin
{
public override sealed Type PluginCategoryType
{
get { return typeof(WarrantyProviderPlugin); }
}
// Warranty Plugin Requirements
public abstract string WarrantyProviderId { get; }
public abstract Type SubmitJobViewType { get; }
public abstract dynamic SubmitJobViewModel(DiscoDataContext dbContext, Controller controller, Job Job, OrganisationAddress Address, User TechUser);
public abstract Dictionary<string, string> SubmitJobParseProperties(DiscoDataContext dbContext, FormCollection form, Controller controller, Job Job, OrganisationAddress Address, User TechUser, string FaultDescription);
public abstract Dictionary<string, string> SubmitJobDiscloseInfo(DiscoDataContext dbContext, Job Job, OrganisationAddress Address, User TechUser, string FaultDescription, Dictionary<string, string> WarrantyProviderProperties);
public abstract string SubmitJob(DiscoDataContext dbContext, Job Job, OrganisationAddress Address, User TechUser, string FaultDescription, Dictionary<string, string> WarrantyProviderProperties);
public abstract Type JobDetailsViewType { get; }
public bool JobDetailsSupported { get { return this.JobDetailsViewType != null; } }
public abstract dynamic JobDetailsViewModel(DiscoDataContext dbContext, Controller controller, Job Job);
public static PluginDefinition FindPlugin(string PlugIdOrWarrantyProviderId)
{
var defs = Plugins.GetPlugins(typeof(WarrantyProviderPlugin));
var def = defs.FirstOrDefault(d => d.Id.Equals(PlugIdOrWarrantyProviderId, StringComparison.InvariantCultureIgnoreCase));
if (def != null)
return def;
else
foreach (var d in defs)
{
using (var providerInstance = d.CreateInstance<WarrantyProviderPlugin>())
{
if (providerInstance.WarrantyProviderId != null && providerInstance.WarrantyProviderId.Equals(PlugIdOrWarrantyProviderId, StringComparison.InvariantCultureIgnoreCase))
{
return d;
}
}
}
return null;
}
}
}
@@ -0,0 +1,12 @@
using System;
namespace Disco.Services.Plugins.Categories.WarrantyProvider
{
public class WarrantyProviderSubmitJobException : Exception
{
public WarrantyProviderSubmitJobException(string Message)
: base(Message)
{
}
}
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Data.Repository;
using System.Web.Mvc;
namespace Disco.Services.Plugins
{
public interface IPluginConfiguration
{
Type ConfigurationViewType { get; }
dynamic ConfigurationViewModel(DiscoDataContext dbContext, Controller controller);
bool ConfigurationSave(DiscoDataContext dbContext, FormCollection form, Controller controller);
}
}
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
namespace Disco.Services.Plugins
{
public interface IPluginWebController
{
ActionResult ExecuteAction(string ActionName, Controller HostController);
}
}
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Plugins
{
public class InvalidCategoryTypeException : Exception
{
private string _pluginRequested;
private Type _categoryType;
public string PluginRequested
{
get
{
return _pluginRequested;
}
}
public Type CategoryType
{
get
{
return _categoryType;
}
}
public InvalidCategoryTypeException(Type CategoryType)
: this(CategoryType, null)
{
}
public InvalidCategoryTypeException(Type CategoryType, string PluginRequested)
{
this._categoryType = CategoryType;
this._pluginRequested = PluginRequested;
}
public override string Message
{
get
{
if (string.IsNullOrEmpty(_pluginRequested))
return string.Format("Invalid Category Type [{0}]", _categoryType.Name);
else
return string.Format("Plugin [{1}] is not of the correct Category Type [{0}]", _categoryType.Name, _pluginRequested);
}
}
}
}
+28
View File
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Data.Repository;
using System.Web.Mvc;
namespace Disco.Services.Plugins
{
public abstract class Plugin : IDisposable
{
public string Id { get { return this.GetType().Name; } }
public abstract string Name { get; }
public abstract string Author { get; }
public abstract Version Version { get; }
public abstract Type PluginCategoryType { get; }
public abstract bool Initalize(DiscoDataContext dbContext);
public abstract void Dispose();
public override sealed string ToString()
{
return string.Format("{0} ({1}) - v{2}", this.Name, this.Id, this.Version.ToString(3));
}
}
}
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Plugins
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class PluginCategoryAttribute : Attribute
{
public string DisplayName { get; set; }
}
}
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web.Mvc;
namespace Disco.Services.Plugins
{
public class PluginDefinition
{
public string Id { get; private set; }
public string Name { get; private set; }
public string Author { get; private set; }
public Version Version { get; private set; }
public Type PluginType { get; private set; }
public Type PluginCategoryType { get; private set; }
public Dictionary<string, string> PluginReferenceAssemblies { get; private set; }
public string PluginHostDirectory { get; private set; }
public bool HasConfiguration { get; private set; }
public bool HasWebController { get; private set; }
public PluginDefinition(Plugin PluginInstance, string HostDirectory, Dictionary<string, string> ReferencedAssemblies = null)
{
Type pluginType = PluginInstance.GetType();
if (string.IsNullOrWhiteSpace(PluginInstance.Id))
throw new ArgumentNullException("PluginInstance.Id");
if (string.IsNullOrWhiteSpace(PluginInstance.Name))
throw new ArgumentNullException("PluginInstance.Name");
if (string.IsNullOrWhiteSpace(PluginInstance.Author))
throw new ArgumentNullException("PluginInstance.Author");
if (string.IsNullOrWhiteSpace(HostDirectory))
throw new ArgumentNullException("HostDirectory");
if (PluginInstance.Version == null)
throw new ArgumentNullException("PluginInstance.Version");
if (PluginInstance.PluginCategoryType == null)
throw new ArgumentNullException("PluginInstance.PluginCategoryType");
if (!PluginInstance.PluginCategoryType.IsAssignableFrom(pluginType))
throw new ArgumentException(string.Format("The plugin [{0}] does not inherit the Category [{1}]", pluginType.Name, PluginInstance.PluginCategoryType.Name), "PluginInstance.PluginCategoryType");
this.Id = PluginInstance.Id;
this.Name = PluginInstance.Name;
this.Author = PluginInstance.Author;
this.Version = PluginInstance.Version;
this.PluginType = pluginType;
this.PluginCategoryType = PluginInstance.PluginCategoryType;
this.PluginHostDirectory = HostDirectory;
if (ReferencedAssemblies != null && ReferencedAssemblies.Count > 0)
this.PluginReferenceAssemblies = ReferencedAssemblies;
// Determine (and Validate) if has Configuration
IPluginConfiguration pluginConfiguration = PluginInstance as IPluginConfiguration;
if (pluginConfiguration != null)
{
if (pluginConfiguration.ConfigurationViewType == null)
throw new ArgumentNullException("PluginInstance.ConfigurationViewType");
if (!typeof(WebViewPage).IsAssignableFrom(pluginConfiguration.ConfigurationViewType))
throw new ArgumentException(string.Format("The plugin [{0}] ConfigurationViewType must inherit System.Web.Mvc.WebViewPage", pluginType.Name), "PluginInstance.ConfigurationViewType");
this.HasConfiguration = true;
}
// Determine if has Web Controller
IPluginWebController pluginWebController = PluginInstance as IPluginWebController;
this.HasWebController = (pluginWebController != null);
}
public Plugin CreateInstance()
{
return (Plugin)Activator.CreateInstance(PluginType);
}
public PluginType CreateInstance<PluginType>()
{
if (typeof(PluginType).IsAssignableFrom(this.PluginType))
return (PluginType)Activator.CreateInstance(this.PluginType);
else
throw new InvalidOperationException(string.Format("The plugin [{0}] cannot be cast into type [{1}]", this.PluginType.Name, typeof(PluginType).Name));
}
}
}
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Data.Repository;
using System.IO;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web;
namespace Disco.Services.Plugins
{
public static class PluginExtensions
{
public static string PluginStorage(this Plugin plugin, DiscoDataContext dbContext)
{
string pluginStorageLocationRoot = dbContext.DiscoConfiguration.PluginStorageLocation;
string storageLocation = Path.Combine(pluginStorageLocationRoot, plugin.Id);
if (!Directory.Exists(storageLocation))
Directory.CreateDirectory(storageLocation);
return storageLocation;
}
public static string PluginCategoryDisplayName(this Plugin plugin)
{
if (plugin == null)
throw new ArgumentNullException("plugin");
return Plugins.CategoryDisplayNames[plugin.PluginCategoryType];
}
#region Model Binding from Controller
public static bool TryUpdateModel<TModel>(this Controller controller, TModel model) where TModel : class
{
return controller.TryUpdateModel<TModel>(model, null, controller.ValueProvider);
}
public static bool TryUpdateModel<TModel>(this Controller controller, TModel model, IValueProvider valueProvider) where TModel : class
{
return controller.TryUpdateModel<TModel>(model, null, valueProvider);
}
public static bool TryUpdateModel<TModel>(this Controller controller, TModel model, string prefix) where TModel : class
{
return controller.TryUpdateModel<TModel>(model, prefix, controller.ValueProvider);
}
public static bool TryUpdateModel<TModel>(this Controller controller, TModel model, string prefix, IValueProvider valueProvider) where TModel : class
{
if (model == null)
throw new ArgumentNullException("model");
if (valueProvider == null)
throw new ArgumentNullException("valueProvider");
Predicate<string> predicate = propertyName => true;
IModelBinder binder = ModelBinders.Binders.GetBinder(typeof(TModel));
ModelBindingContext context2 = new ModelBindingContext
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(TModel)),
ModelName = prefix,
ModelState = controller.ModelState,
PropertyFilter = predicate,
ValueProvider = valueProvider
};
ModelBindingContext bindingContext = context2;
binder.BindModel(controller.ControllerContext, bindingContext);
return controller.ModelState.IsValid;
}
#endregion
}
}
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Plugins
{
public class PluginWebControllerException : Exception
{
public PluginWebControllerException(string PluginId, string PluginAction, Exception InnerException)
: base(string.Format("An error occurred executing the Disco Plugin [{0}] Web Controller Action: [{0}]", PluginId, PluginAction), InnerException)
{
}
}
}
@@ -0,0 +1,210 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Web.Mvc;
using RazorGenerator.Mvc;
using System.IO;
namespace Disco.Services.Plugins
{
public static class PluginWebControllerExtensions
{
#region Virtual Directories
public static string WebControllerRootUrl(this IPluginWebController plugin, RequestContext requestContext)
{
var tempPath = plugin.WebControllerActionUrl(requestContext, "_");
return tempPath.Substring(0, tempPath.LastIndexOf(@"/") + 1);
}
public static string WebControllerActionUrl(this IPluginWebController plugin, RequestContext requestContext, string PluginAction)
{
//return string.Format("~/Config/Plugins/{0}/{1}", HttpUtility.UrlEncode(((IDiscoPlugin)plugin).Id), HttpUtility.UrlEncode(PluginAction));
var routeValues = new RouteValueDictionary(new { PluginId = ((Plugin)plugin).Id, PluginAction = PluginAction });
return UrlHelper.GenerateUrl("Config_Plugins_PluginWebControllerActions", "PluginAction", "Plugins", routeValues, RouteTable.Routes, requestContext, true);
}
#endregion
#region Action Results
#region Compiled View
private static string[] _viewFileNames = new string[] { "cshtml" };
public static ActionResult CompiledView(this Controller HostController, Type CompiledViewType, object Model, bool UseDiscoLayout)
{
string layoutPath = UseDiscoLayout ? "~/Views/Shared/_Layout.cshtml" : null;
IView v = new PrecompiledMvcView(HostController.Request.Path, layoutPath, CompiledViewType, false, _viewFileNames);
if (Model != null)
HostController.ViewData.Model = Model;
return new ViewResult { View = v, ViewData = HostController.ViewData, TempData = HostController.TempData };
}
public static ActionResult CompiledView(this Controller HostController, Type CompiledViewType, bool UseDiscoLayout)
{
return HostController.CompiledView(CompiledViewType, null, UseDiscoLayout);
}
public static ActionResult CompiledView(this Controller HostController, Type CompiledViewType, object Model)
{
return HostController.CompiledView(CompiledViewType, Model, true);
}
public static ActionResult CompiledView(this Controller HostController, Type CompiledViewType)
{
return HostController.CompiledView(CompiledViewType, false, true);
}
public static ActionResult CompiledPartialView(this Controller HostController, Type PartialCompiledViewType, object Model)
{
IView v = new PrecompiledMvcView(HostController.Request.Path, PartialCompiledViewType, false, _viewFileNames);
if (Model != null)
HostController.ViewData.Model = Model;
return new PartialViewResult { View = v, ViewData = HostController.ViewData, TempData = HostController.TempData };
}
public static ActionResult CompiledPartialView(this Controller HostController, Type PartialCompiledViewType)
{
return HostController.CompiledView(PartialCompiledViewType, null);
}
#endregion
#region Content
public static ActionResult Content(this Controller HostController, string content, string contentType, Encoding contentEncoding)
{
return new ContentResult { Content = content, ContentType = contentType, ContentEncoding = contentEncoding };
}
public static ActionResult Content(this Controller HostController, string content, string contentType)
{
return HostController.Content(content, null, null);
}
public static ActionResult Content(this Controller HostController, string content)
{
return HostController.Content(content, null);
}
#endregion
#region Json
public static ActionResult Json(this Controller HostController, object data, JsonRequestBehavior behavior)
{
return new JsonResult { Data = data, ContentType = null, ContentEncoding = null, JsonRequestBehavior = behavior };
}
#endregion
#region File
public static ActionResult File(this Controller HostController, Stream fileStream, string contentType)
{
return HostController.File(fileStream, contentType, null);
}
public static ActionResult File(this Controller HostController, Stream fileStream, string contentType, string fileDownloadName)
{
return new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName };
}
public static ActionResult File(this Controller HostController, byte[] fileContents, string contentType)
{
return HostController.File(fileContents, contentType, null);
}
public static ActionResult File(this Controller HostController, byte[] fileContents, string contentType, string fileDownloadName)
{
return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };
}
#endregion
#region HttpNotFound
public static ActionResult HttpNotFound(this Controller HostController, string statusDescription)
{
return new HttpNotFoundResult(statusDescription);
}
public static ActionResult HttpNotFound(this Controller HostController)
{
return HostController.HttpNotFound(null);
}
#endregion
#region Redirect
public static ActionResult RedirectToScheduledTaskStatus(this Controller HostController, string SessionId)
{
if (string.IsNullOrEmpty(SessionId))
throw new ArgumentNullException(SessionId);
return HostController.RedirectToAction("TaskStatus", "Logging", "Config", new { id = SessionId });
}
public static ActionResult Redirect(this Controller HostController, string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException("url");
return new RedirectResult(url);
}
public static ActionResult RedirectPermanent(this Controller HostController, string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException("url");
return new RedirectResult(url, true);
}
public static ActionResult RedirectToAction(this Controller HostController, IPluginWebController Plugin, string PluginAction)
{
if (string.IsNullOrEmpty(PluginAction))
throw new ArgumentNullException("PluginAction");
string pluginActionUrl = Plugin.WebControllerActionUrl(HostController.Request.RequestContext, PluginAction);
return new RedirectResult(pluginActionUrl, false);
}
public static ActionResult RedirectToRoute(this Controller HostController, string routeName, object routeValues)
{
RouteValueDictionary routeValueDictionary;
if (routeValues != null)
routeValueDictionary = new RouteValueDictionary(routeValues);
else
routeValueDictionary = new RouteValueDictionary();
return new RedirectToRouteResult(routeName, routeValueDictionary);
}
public static ActionResult RedirectToRoute(this Controller HostController, string routeName)
{
return HostController.RedirectToRoute(routeName, null);
}
public static ActionResult RedirectToAction(this Controller HostController, string actionName, string controllerName, string areaName, object routeValues)
{
RouteValueDictionary routeValueDictionary;
if (routeValues != null)
routeValueDictionary = new RouteValueDictionary(routeValues);
else
routeValueDictionary = new RouteValueDictionary();
routeValueDictionary["action"] = actionName;
routeValueDictionary["controller"] = controllerName;
if (areaName != null)
routeValueDictionary["area"] = areaName;
return new RedirectToRouteResult(routeValueDictionary);
}
public static ActionResult RedirectToAction(this Controller HostController, string actionName, string controllerName, string areaName)
{
return HostController.RedirectToAction(actionName, controllerName, areaName, null);
}
public static ActionResult RedirectToAction(this Controller HostController, string actionName, string controllerName, object routeValues)
{
return HostController.RedirectToAction(actionName, controllerName, null, routeValues);
}
public static ActionResult RedirectToAction(this Controller HostController, string actionName, string controllerName)
{
return HostController.RedirectToAction(actionName, controllerName, null, null);
}
public static ActionResult RedirectToDiscoJob(this Controller HostController, int jobId)
{
return HostController.RedirectToAction("Show", "Job", null, new { id = jobId.ToString() });
}
public static ActionResult RedirectToDiscoDevice(this Controller HostController, string DeviceSerialNumber)
{
return HostController.RedirectToAction("Show", "Device", null, new { id = DeviceSerialNumber });
}
public static ActionResult RedirectToDiscoUser(this Controller HostController, string UserId)
{
return HostController.RedirectToAction("Show", "User", null, new { id = UserId });
}
#endregion
#endregion
}
}
+290
View File
@@ -0,0 +1,290 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Disco.Data.Repository;
using System.IO;
using System.ComponentModel.DataAnnotations;
using System.Web;
using System.Web.Mvc;
using RazorGenerator.Mvc;
using System.Web.WebPages;
namespace Disco.Services.Plugins
{
public static class Plugins
{
private static Dictionary<string, PluginDefinition> _LoadedPlugins;
internal static Dictionary<Type, string> CategoryDisplayNames;
private static object _PluginLock = new object();
public static string PluginPath { get; private set; }
public static PluginDefinition GetPlugin(string PluginId, Type CategoryType = null)
{
if (_LoadedPlugins == null)
throw new InvalidOperationException("Plugins have not been initialized");
PluginDefinition def;
if (_LoadedPlugins.TryGetValue(PluginId, out def))
{
if (CategoryType == null)
return def;
else
{
if (CategoryType.IsAssignableFrom(def.PluginCategoryType))
return def;
else
throw new InvalidCategoryTypeException(CategoryType, PluginId);
}
}
else
{
throw new UnknownPluginException(PluginId);
}
}
public static List<PluginDefinition> GetPlugins(Type CategoryType)
{
if (_LoadedPlugins == null)
throw new InvalidOperationException("Plugins have not been initialized");
return _LoadedPlugins.Values.Where(p => p.PluginCategoryType.IsAssignableFrom(CategoryType)).OrderBy(p => p.Name).ToList();
}
public static List<PluginDefinition> GetPlugins()
{
if (_LoadedPlugins == null)
throw new InvalidOperationException("Plugins have not been initialized");
return _LoadedPlugins.Values.ToList();
}
public static string PluginCategoryDisplayName(Type CategoryType)
{
if (CategoryType == null)
throw new ArgumentNullException("CategoryType");
string displayName;
if (CategoryDisplayNames.TryGetValue(CategoryType, out displayName))
return displayName;
else
throw new InvalidOperationException(string.Format("Unknown Plugin Category Type: [{0}]", CategoryType.Name));
}
#region Initalizing
public static void InitalizePlugins(DiscoDataContext dbContext)
{
if (_LoadedPlugins == null)
{
lock (_PluginLock)
{
if (_LoadedPlugins == null)
{
Dictionary<string, PluginDefinition> loadedPlugins = new Dictionary<string, PluginDefinition>();
PluginPath = dbContext.DiscoConfiguration.PluginsLocation;
AppDomain appDomain = AppDomain.CurrentDomain;
// Subscribe to Assembly Resolving
appDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
// Load Internal (Default?) Plugins
IEnumerable<Assembly> discoAssemblies = (from a in appDomain.GetAssemblies()
where !a.GlobalAssemblyCache && !a.IsDynamic &&
a.FullName.StartsWith("Disco.", StringComparison.InvariantCultureIgnoreCase)
select a);
foreach (var discoAssembly in discoAssemblies)
{
List<PluginDefinition> assemblyPluginDefinitions = InitializePluginAssembly(dbContext, discoAssembly, false);
foreach (PluginDefinition definition in assemblyPluginDefinitions)
loadedPlugins[definition.Id] = definition;
}
// Load External (DataStore) Plugins
DirectoryInfo pluginDirectoryRoot = new DirectoryInfo(PluginPath);
if (pluginDirectoryRoot.Exists)
{
foreach (DirectoryInfo pluginDirectory in pluginDirectoryRoot.EnumerateDirectories())
{
string pluginAssemblyFilename = Path.Combine(pluginDirectory.FullName, string.Format("{0}.dll", pluginDirectory.Name));
if (File.Exists(pluginAssemblyFilename))
{
Assembly pluginAssembly = null;
try
{
pluginAssembly = Assembly.LoadFile(pluginAssemblyFilename);
if (pluginAssembly != null)
{
PluginsLog.LogInitializingPluginAssembly(pluginAssembly);
List<PluginDefinition> assemblyPluginDefinitions = InitializePluginAssembly(dbContext, pluginAssembly, true);
foreach (PluginDefinition definition in assemblyPluginDefinitions)
loadedPlugins[definition.Id] = definition;
}
}
catch (Exception ex) { PluginsLog.LogInitializeException(pluginAssemblyFilename, ex); }
}
}
}
// Determine Category Information
CategoryDisplayNames = InitializeCategoryDetails(loadedPlugins.Values);
_LoadedPlugins = loadedPlugins;
}
}
}
}
private static Dictionary<Type, string> InitializeCategoryDetails(IEnumerable<PluginDefinition> plugins)
{
Dictionary<Type, string> categoryDisplayNames = new Dictionary<Type, string>();
foreach (var pluginDefinition in plugins)
{
if (!categoryDisplayNames.ContainsKey(pluginDefinition.PluginCategoryType))
{
string displayName = null;
var displayAttributes = pluginDefinition.PluginCategoryType.GetCustomAttributes(typeof(PluginCategoryAttribute), true);
if (displayAttributes != null && displayAttributes.Length > 0)
displayName = ((PluginCategoryAttribute)(displayAttributes[0])).DisplayName;
if (string.IsNullOrWhiteSpace(displayName))
displayName = pluginDefinition.PluginCategoryType.Name;
categoryDisplayNames[pluginDefinition.PluginCategoryType] = displayName;
}
}
return categoryDisplayNames;
}
private static List<PluginDefinition> InitializePluginAssembly(DiscoDataContext dbContext, Assembly PluginAssembly, bool ResolveReferences)
{
List<PluginDefinition> pluginDefinitions = new List<PluginDefinition>();
var pluginTypes = (from type in PluginAssembly.GetTypes()
where typeof(Plugin).IsAssignableFrom(type) && !type.IsAbstract
select type).ToList();
if (pluginTypes.Count > 0)
{
Dictionary<string, string> referencedAssemblies = null;
string hostDirectory = Path.GetDirectoryName(PluginAssembly.Location);
if (ResolveReferences)
referencedAssemblies = ImportReferencedAssemblies(PluginAssembly, hostDirectory);
foreach (Type t in pluginTypes)
{
var p = InitializePlugin(dbContext, t, hostDirectory, referencedAssemblies);
if (p != null)
pluginDefinitions.Add(p);
}
}
return pluginDefinitions;
}
private static Dictionary<string, string> ImportReferencedAssemblies(Assembly PluginAssembly, string HostDirectory)
{
Dictionary<string, string> referencedAssemblies = new Dictionary<string, string>();
foreach (string referenceFilename in Directory.EnumerateFiles(HostDirectory, "*.dll", SearchOption.TopDirectoryOnly))
{
if (!referenceFilename.Equals(PluginAssembly.Location, StringComparison.InvariantCultureIgnoreCase))
{
try
{
Assembly pluginRefAssembly = Assembly.ReflectionOnlyLoadFrom(referenceFilename);
referencedAssemblies[pluginRefAssembly.FullName] = referenceFilename;
}
catch (Exception) { } // Ignore Load Exceptions
}
}
return referencedAssemblies;
}
private static PluginDefinition InitializePlugin(DiscoDataContext dbContext, Type PluginType, string HostDirectory, Dictionary<string, string> ReferencedAssemblies = null)
{
if (!typeof(Plugin).IsAssignableFrom(PluginType))
throw new ArgumentException(string.Format("Plugins [{0}] does not inherit from [IDiscoPlugin]", PluginType.Name));
using (Plugin instance = (Plugin)Activator.CreateInstance(PluginType))
{
try
{
PluginDefinition definition = new PluginDefinition(instance, HostDirectory, ReferencedAssemblies);
PluginsLog.LogInitializingPlugin(definition);
instance.Initalize(dbContext);
return definition;
}
catch (Exception ex)
{
PluginsLog.LogInitializeException(PluginType.Assembly.Location, ex);
return null;
}
}
}
#endregion
#region Plugin Referenced Assemblies Resolving
public static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.RequestingAssembly.Location.StartsWith(PluginPath, StringComparison.InvariantCultureIgnoreCase) && _LoadedPlugins != null)
{
// Try best guess first
PluginDefinition requestingPlugin = _LoadedPlugins.Values.Where(p => p.PluginType.Assembly == args.RequestingAssembly).FirstOrDefault();
if (requestingPlugin != null)
{
Assembly loadedAssembly = CurrentDomain_AssemblyResolve_ByPlugin(requestingPlugin, args);
if (loadedAssembly != null)
return loadedAssembly;
}
// Try all Plugin References
foreach (var pluginDef in _LoadedPlugins.Values)
{
Assembly loadedAssembly = CurrentDomain_AssemblyResolve_ByPlugin(pluginDef, args);
if (loadedAssembly != null)
return loadedAssembly;
}
}
return null;
}
private static Assembly CurrentDomain_AssemblyResolve_ByPlugin(PluginDefinition PluginDefinition, ResolveEventArgs args)
{
if (PluginDefinition.PluginReferenceAssemblies != null)
{
string assemblyPath;
if (PluginDefinition.PluginReferenceAssemblies.TryGetValue(args.Name, out assemblyPath))
{
try
{
Assembly loadedAssembly = Assembly.LoadFile(assemblyPath);
PluginsLog.LogPluginReferenceAssemblyLoaded(args.Name, assemblyPath, args.RequestingAssembly.FullName);
return loadedAssembly;
}
catch (Exception ex)
{
PluginsLog.LogPluginException(string.Format("Resolving Plugin Reference Assembly: '{0}' [{1}]; Requested by: '{2}' [{3}]; Disco.Plugins.DiscoPlugins.CurrentDomain_AssemblyResolve()", args.Name, assemblyPath, args.RequestingAssembly.FullName, args.RequestingAssembly.Location), ex);
}
}
}
return null;
}
#endregion
}
}
+259
View File
@@ -0,0 +1,259 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Services.Logging;
using Disco.Services.Logging.Models;
using System.Reflection;
namespace Disco.Services.Plugins
{
public class PluginsLog : LogBase
{
private const int _ModuleId = 10;
public override string ModuleDescription { get { return "Plugins"; } }
public override int ModuleId { get { return _ModuleId; } }
public override string ModuleName { get { return "Plugins"; } }
public enum EventTypeIds
{
InitializingPlugins = 10,
InitializingPluginAssembly,
InitializedPlugin,
InitializeWarning = 15,
InitializeError,
InitializeException,
InitializeExceptionWithInner,
PluginException = 20,
PluginExceptionWithInner,
PluginReferenceAssemblyLoaded = 50,
PluginConfigurationLoaded = 100,
PluginConfigurationSaved = 104,
PluginWebControllerAccessed = 200
}
public static PluginsLog Current
{
get
{
return (PluginsLog)LogContext.LogModules[_ModuleId];
}
}
private static void Log(EventTypeIds EventTypeId, params object[] Args)
{
Current.Log((int)EventTypeId, Args);
}
public static void LogInitializingPlugins(string PluginDirectory)
{
Current.Log((int)EventTypeIds.InitializingPlugins, PluginDirectory);
}
public static void LogInitializingPluginAssembly(Assembly PluginAssembly)
{
Current.Log((int)EventTypeIds.InitializingPluginAssembly, PluginAssembly.FullName, PluginAssembly.Location);
}
public static void LogInitializingPlugin(PluginDefinition Definition)
{
Current.Log((int)EventTypeIds.InitializedPlugin, Definition.Id, Definition.Version.ToString(3), Definition.PluginType.Name, Definition.PluginType.Assembly.Location);
}
public static void LogInitializeWarning(string Warning)
{
Current.Log((int)EventTypeIds.InitializeWarning, Warning);
}
public static void LogInitializeError(string Error)
{
Current.Log((int)EventTypeIds.InitializeError, Error);
}
public static void LogPluginReferenceAssemblyLoaded(string AssemblyFullName, string AssemblyPath, string RequestedBy)
{
Current.Log((int)EventTypeIds.PluginReferenceAssemblyLoaded, AssemblyFullName, AssemblyPath, RequestedBy);
}
public static void LogPluginConfigurationLoaded(string PluginId, string UserId)
{
Current.Log((int)EventTypeIds.PluginConfigurationLoaded, PluginId, UserId);
}
public static void LogPluginConfigurationSaved(string PluginId, string UserId)
{
Current.Log((int)EventTypeIds.PluginConfigurationSaved, PluginId, UserId);
}
public static void LogPluginWebControllerAccessed(string PluginId, string PluginAction, string UserId)
{
Current.Log((int)EventTypeIds.PluginWebControllerAccessed, PluginId, PluginAction, UserId);
}
public static void LogInitializeException(string PluginFilename, Exception ex)
{
if (ex.InnerException != null)
{
Log(EventTypeIds.InitializeExceptionWithInner, PluginFilename, ex.GetType().Name, ex.Message, ex.StackTrace, ex.InnerException.GetType().Name, ex.InnerException.Message, ex.InnerException.StackTrace);
}
else
{
Log(EventTypeIds.InitializeException, PluginFilename, ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
public static void LogPluginException(string Component, Exception ex)
{
if (ex.InnerException != null)
{
Log(EventTypeIds.PluginExceptionWithInner, Component, ex.GetType().Name, ex.Message, ex.StackTrace, ex.InnerException.GetType().Name, ex.InnerException.Message, ex.InnerException.StackTrace);
}
else
{
Log(EventTypeIds.PluginException, Component, ex.GetType().Name, ex.Message, ex.StackTrace);
}
}
protected override List<Logging.Models.LogEventType> LoadEventTypes()
{
return new System.Collections.Generic.List<LogEventType>
{
new LogEventType
{
Id = (int)EventTypeIds.InitializingPlugins,
ModuleId = _ModuleId,
Name = "Initializing Plugins",
Format = "Starting plugin discovery and initialization from: {0}",
Severity = (int)LogEventType.Severities.Information,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializingPluginAssembly,
ModuleId = _ModuleId,
Name = "Initializing Plugin Assembly",
Format = "Initializing Plugin Assembly: [{0}] From '{1}'",
Severity = (int)LogEventType.Severities.Information,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializedPlugin,
ModuleId = _ModuleId,
Name = "Initialized Plugin",
Format = "Initialized Plugin: '{0} (v{1})' [{2}] From '{3}'",
Severity = (int)LogEventType.Severities.Information,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeWarning,
ModuleId = _ModuleId,
Name = "Initialize Warning",
Format = "Initialize Warning: {0}",
Severity = (int)LogEventType.Severities.Warning,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeError,
ModuleId = _ModuleId,
Name = "Initialize Error",
Format = "Initialize Error: {0}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeException,
ModuleId = _ModuleId,
Name = "Initialize Exception",
Format = "Exception: {0}; {1}: {2}; {3}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.InitializeExceptionWithInner,
ModuleId = _ModuleId,
Name = "Initialize Exception with Inner Exception",
Format = "Exception: {0}; {1}: {2}; {3}; Inner: {4}: {5}; {6}",
Severity = (int)LogEventType.Severities.Error,
UseLive = false,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginException,
ModuleId = _ModuleId,
Name = "Plugin Exception",
Format = "Exception: {0}; {1}: {2}; {3}",
Severity = (int)LogEventType.Severities.Error,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginExceptionWithInner,
ModuleId = _ModuleId,
Name = "Plugin Exception with Inner Exception",
Format = "Exception: {0}; {1}: {2}; {3}; Inner: {4}: {5}; {6}",
Severity = (int)LogEventType.Severities.Error,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginReferenceAssemblyLoaded,
ModuleId = _ModuleId,
Name = "Plugin Reference Assembly Loaded",
Format = "Loaded Plugin Reference Assembly: [{0}] From: '{1}'; Requested by: [{2}]",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginConfigurationLoaded,
ModuleId = _ModuleId,
Name = "Plugin Configuration Loaded",
Format = "Plugin Configuration Loaded: [{0}] by [{1}]",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginConfigurationSaved,
ModuleId = _ModuleId,
Name = "Plugin Configuration Saved",
Format = "Plugin Configuration Saved: [{0}] by [{1}]",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
},
new LogEventType
{
Id = (int)EventTypeIds.PluginWebControllerAccessed,
ModuleId = _ModuleId,
Name = "Plugin Web Controller Accessed",
Format = "Plugin Web Controller Accessed: Plugin [{0}], Action [{1}], By [{2}]",
Severity = (int)LogEventType.Severities.Information,
UseLive = true,
UsePersist = true,
UseDisplay = true
}
};
}
}
}
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Plugins
{
public class UnknownPluginException : Exception
{
private string _pluginRequested;
public string PluginRequested
{
get
{
return _pluginRequested;
}
}
public UnknownPluginException(string PluginRequested)
{
this._pluginRequested = PluginRequested;
}
public UnknownPluginException(string PluginRequested, string Message) : base(Message)
{
this._pluginRequested = PluginRequested;
}
public override string Message
{
get
{
return string.Format("Unknown Plugin Id: [{0}]", _pluginRequested);
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.SqlServer.Compact" version="4.0.8876.1" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
<package id="RazorGenerator.Mvc" version="1.5.0.0" targetFramework="net45" />
<package id="SignalR.Hosting.AspNet" version="0.5.3" targetFramework="net45" />
<package id="SignalR.Hosting.Common" version="0.5.3" targetFramework="net45" />
<package id="SignalR.Server" version="0.5.3" targetFramework="net45" />
<package id="SqlServerCompact" version="4.0.8854.1" targetFramework="net40" />
<package id="WebActivator" version="1.5.3" targetFramework="net45" />
</packages>