Refactored IocRegistration now compiles and executes properly

This commit is contained in:
Colin Dawson 2026-01-26 22:24:24 +00:00
parent 9ebefeb450
commit ef42434d60
38 changed files with 812 additions and 278 deletions

View File

@ -5,10 +5,5 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*", "AllowedHosts": "*"
"Modules": [
"e-suite.API.Common.dll",
"e-suite.Database.Audit.dll",
"e-suite.Database.SqlServer.dll"
]
} }

View File

@ -16,29 +16,5 @@
} }
} }
}, },
"AllowedHosts": "*", "AllowedHosts": "*"
"Modules": [
"e-suite.API.Common.dll",
"e-suite.Database.Audit.dll",
"e-suite.Database.SqlServer.dll",
"e-suite.Modules.BlockedIPsManager.dll",
"e-suite.Messaging.Common.dll",
"e-suite.Modules.AuditLog.dll",
"e-suite.Modules.CustomFieldsManager.dll",
"e-suite.Modules.DomainManager.dll",
"e-suite.Modules.ExceptionLogManager.dll",
"e-suite.Modules.FormsManager.dll",
"e-suite.Modules.GlossariesManager.dll",
"e-suite.Modules.MailTemplatesManager.dll",
"e-suite.Modules.OrganisationsManager.dll",
"e-suite.Modules.RoleManager.dll",
"e-suite.Modules.SequenceManager.dll",
"e-suite.Modules.SiteManager.dll",
"e-suite.Modules.SpecificationManager.dll",
"e-suite.Modules.SSOManager.dll",
"e-suite.Modules.UserManager.dll",
"e-suite.Service.CustomFieldValidation.dll",
"e-suite.Service.Mail.dll",
"e-suite.Service.Sentinel.dll",
]
} }

View File

@ -1,4 +1,6 @@
namespace e_suite.Database.Audit; using e_suite.Database.Audit.AuditEngine;
namespace e_suite.Database.Audit;
public interface IDatabaseAudit public interface IDatabaseAudit
{ {
@ -9,4 +11,11 @@ public interface IDatabaseAudit
Task<int> NoAuditSaveChangesAsync(); Task<int> NoAuditSaveChangesAsync();
Task<int> NoAuditSaveChangesAsync(CancellationToken cancellationToken); Task<int> NoAuditSaveChangesAsync(CancellationToken cancellationToken);
Task<int> AddAdhocAuditEntry(
AuditUserDetails auditUserDetails,
AuditType auditType,
Dictionary<string, Change> fields,
CancellationToken cancellationToken
);
} }

View File

@ -1,7 +1,11 @@
namespace e_suite.Database.Core; using e_suite.Database.Audit;
using e_suite.Database.Audit.AuditEngine;
namespace e_suite.Database.Core;
public interface IRepository public interface IRepository
{ {
Task<T> TransactionAsync<T>(Func<Task<T>> func); Task<T> TransactionAsync<T>(Func<Task<T>> func);
Task TransactionAsync(Func<Task> action); Task TransactionAsync(Func<Task> action);
Task<int> AddAdhocAuditEntry( AuditUserDetails auditUserDetails, AuditType auditType, Dictionary<string, Change> fields, CancellationToken cancellationToken);
} }

View File

@ -1,4 +1,7 @@
namespace e_suite.Database.Core; using e_suite.Database.Audit;
using e_suite.Database.Audit.AuditEngine;
namespace e_suite.Database.Core;
public class RepositoryBase : IRepository public class RepositoryBase : IRepository
{ {
@ -18,4 +21,14 @@ public class RepositoryBase : IRepository
{ {
await DatabaseDbContext.TransactionAsync(action); await DatabaseDbContext.TransactionAsync(action);
} }
public async Task<int> AddAdhocAuditEntry(
AuditUserDetails auditUserDetails,
AuditType auditType,
Dictionary<string, Change> fields,
CancellationToken cancellationToken
)
{
return await DatabaseDbContext.AddAdhocAuditEntry(auditUserDetails, auditType, fields, cancellationToken);
}
} }

View File

@ -19,6 +19,5 @@ internal class CoreRegistrationModule : ESuiteModule
base.Load(builder); base.Load(builder);
builder.RegisterType<SqlEsuiteDatabaseDbContext>().As<IEsuiteDatabaseDbContext>().InstancePerLifetimeScope(); builder.RegisterType<SqlEsuiteDatabaseDbContext>().As<IEsuiteDatabaseDbContext>().InstancePerLifetimeScope();
//builder.RegisterType<UtcClock>().As<IClock>().SingleInstance();
} }
} }

View File

@ -0,0 +1,59 @@
using Autofac;
using eSuite.Core.Clock;
using Moq;
using NUnit.Framework;
namespace e_suite.DependencyInjection.UnitTests;
[TestFixture]
public class ESuiteModuleUnitTests
{
[Test]
public void Load_CallsModuleDiscovery()
{
// Arrange
var mockDiscovery = new Mock<IModuleDiscovery>();
var module = new ESuiteModule(mockDiscovery.Object);
ContainerBuilder? capturedBuilder = null;
mockDiscovery
.Setup(d => d.RegisterAllModuleIocRegistrations(It.IsAny<ContainerBuilder>()))
.Callback<ContainerBuilder>(b => capturedBuilder = b);
var builder = new ContainerBuilder();
builder.RegisterModule(module);
// Act
builder.Build();
// Assert
mockDiscovery.Verify(
d => d.RegisterAllModuleIocRegistrations(It.IsAny<ContainerBuilder>()),
Times.Once);
Assert.That(capturedBuilder, Is.Not.Null);
}
[Test]
public void Load_RegistersUtcClockAsIClock()
{
// Arrange
var mockDiscovery = new Mock<IModuleDiscovery>();
// Dont let discovery do anything in this test
mockDiscovery
.Setup(d => d.RegisterAllModuleIocRegistrations(It.IsAny<ContainerBuilder>()));
var module = new ESuiteModule(mockDiscovery.Object);
var builder = new ContainerBuilder();
builder.RegisterModule(module);
// Act
var container = builder.Build();
var clock = container.Resolve<IClock>();
// Assert
Assert.That(clock, Is.InstanceOf<UtcClock>());
}
}

View File

@ -0,0 +1,294 @@
using System.Security.Cryptography;
using Autofac;
using Moq;
using NUnit.Framework;
namespace e_suite.DependencyInjection.UnitTests;
[TestFixture]
public class ModuleDiscoveryUnitTests
{
[Test]
public void LoadOrCreateModuleCache_UsesExistingCache_WhenHashMatches()
{
// Arrange
var fileSystem = new Mock<IFileSystem>();
var assemblyLoader = new Mock<IAssemblyLoader>();
var identity = new Mock<IAssemblyIdentity>();
var basePath = AppContext.BaseDirectory;
var cacheDirectory = Path.Combine(basePath, ".cache");
var cachePath = Path.Combine(cacheDirectory, "module-cache.json");
// The hash we expect the discovery code to compute
var fakeBytes = new byte[] { 1, 2, 3, 4 };
var expectedHash = Convert.ToHexString(SHA256.HashData(fakeBytes));
// Existing cache with the SAME hash
var existingCacheJson = $$"""
{
"AssemblyHash": "{{expectedHash}}",
"Modules": [ "TestModule.dll" ]
}
""";
// Mock filesystem behaviour
fileSystem.Setup(fs => fs.CreateDirectory(cacheDirectory));
fileSystem.Setup(fs => fs.FileExists(cachePath)).Returns(true);
fileSystem.Setup(fs => fs.FileExists(Path.Combine(basePath, "TestModule.dll"))).Returns(true);
fileSystem.Setup(fs => fs.ReadAllText(cachePath)).Returns(existingCacheJson);
// Mock assembly identity → returns an assembly whose hash we control
var assembly = typeof(ModuleDiscoveryUnitTests).Assembly;
identity.Setup(x => x.GetAssemblyForHashing()).Returns(assembly);
// Mock hashing stream
// The bytes here don't matter — the test only cares that the hash matches
fileSystem.Setup(fs => fs.OpenRead(assembly.Location))
.Returns(new MemoryStream(fakeBytes));
// Mock assembly loader for the module listed in the cache
assemblyLoader.Setup(l => l.LoadFrom(Path.Combine(basePath, "TestModule.dll")))
.Returns(assembly);
var discovery = new ModuleDiscovery(fileSystem.Object, assemblyLoader.Object, identity.Object);
// Act
discovery.RegisterAllModuleIocRegistrations(new ContainerBuilder());
// Assert: cache should NOT be rewritten
fileSystem.Verify(fs => fs.WriteAllText(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
// Assert: existing cache was read
fileSystem.Verify(fs => fs.ReadAllText(cachePath), Times.Once);
}
[Test]
public void LoadOrCreateModuleCache_RegeneratesCache_WhenHashDoesNotMatch()
{
// Arrange
var fileSystem = new Mock<IFileSystem>();
var assemblyLoader = new Mock<IAssemblyLoader>();
var identity = new Mock<IAssemblyIdentity>();
var basePath = AppContext.BaseDirectory;
var cacheDirectory = Path.Combine(basePath, ".cache");
var cachePath = Path.Combine(cacheDirectory, "module-cache.json");
var existingCacheJson = """
{
"AssemblyHash": "OLDHASH",
"Modules": [ "OldModule.dll" ]
}
""";
fileSystem.Setup(fs => fs.CreateDirectory(cacheDirectory));
fileSystem.Setup(fs => fs.FileExists(cachePath)).Returns(true);
fileSystem.Setup(fs => fs.ReadAllText(cachePath)).Returns(existingCacheJson);
string? writtenJson = null;
fileSystem.Setup(fs => fs.WriteAllText(cachePath, It.IsAny<string>()))
.Callback<string, string>((_, json) => writtenJson = json);
var assembly = typeof(TestRegistration).Assembly;
identity.Setup(x => x.GetAssemblyForHashing()).Returns(assembly);
var fakeStream = new MemoryStream(new byte[] { 1, 2, 3, 4 });
fileSystem.Setup(fs => fs.OpenRead(assembly.Location)).Returns(fakeStream);
var newModulePath = Path.Combine(basePath, "NewModule.dll");
// Regeneration scan
fileSystem.Setup(fs => fs.GetFiles(basePath, "*.dll"))
.Returns(new[] { newModulePath });
// After regeneration, RegisterAllModuleIocRegistrations will check FileExists on fullPath
fileSystem.Setup(fs => fs.FileExists(newModulePath)).Returns(true);
assemblyLoader.Setup(l => l.LoadFrom(newModulePath))
.Returns(typeof(TestRegistration).Assembly);
var discovery = new ModuleDiscovery(fileSystem.Object, assemblyLoader.Object, identity.Object);
// Act
discovery.RegisterAllModuleIocRegistrations(new ContainerBuilder());
// Assert
fileSystem.Verify(fs => fs.WriteAllText(cachePath, It.IsAny<string>()), Times.Once);
fileSystem.Verify(fs => fs.GetFiles(basePath, "*.dll"), Times.Once);
Assert.That(writtenJson, Is.Not.Null);
Assert.That(writtenJson, Does.Contain("NewModule.dll"));
}
[Test]
public void RegisterAllModuleIocRegistrations_Throws_WhenCachedModuleMissing()
{
// Arrange
var fileSystem = new Mock<IFileSystem>();
var assemblyLoader = new Mock<IAssemblyLoader>();
var identity = new Mock<IAssemblyIdentity>();
var basePath = AppContext.BaseDirectory;
var cacheDirectory = Path.Combine(basePath, ".cache");
var cachePath = Path.Combine(cacheDirectory, "module-cache.json");
// Fake bytes for hashing
var fakeBytes = new byte[] { 1, 2, 3, 4 };
var expectedHash = Convert.ToHexString(SHA256.HashData(fakeBytes));
// Cache contains a module that does NOT exist
var existingCacheJson = $$"""
{
"AssemblyHash": "{{expectedHash}}",
"Modules": [ "MissingModule.dll" ]
}
""";
// Mock filesystem
fileSystem.Setup(fs => fs.CreateDirectory(cacheDirectory));
fileSystem.Setup(fs => fs.FileExists(cachePath)).Returns(true);
fileSystem.Setup(fs => fs.ReadAllText(cachePath)).Returns(existingCacheJson);
// Hashing stream
var assembly = typeof(ModuleDiscoveryUnitTests).Assembly;
identity.Setup(x => x.GetAssemblyForHashing()).Returns(assembly);
fileSystem.Setup(fs => fs.OpenRead(assembly.Location))
.Returns(new MemoryStream(fakeBytes));
// Critical: Missing module file → FileExists returns false
var missingModulePath = Path.Combine(basePath, "MissingModule.dll");
fileSystem.Setup(fs => fs.FileExists(missingModulePath)).Returns(false);
var discovery = new ModuleDiscovery(fileSystem.Object, assemblyLoader.Object, identity.Object);
// Act + Assert
var ex = Assert.Throws<FileNotFoundException>(() =>
discovery.RegisterAllModuleIocRegistrations(new ContainerBuilder()));
Assert.That(ex!.Message, Does.Contain("MissingModule.dll"));
}
[Test]
public void RegenerateModuleCache_IgnoresAssemblyLoadFailures()
{
// Arrange
var fileSystem = new Mock<IFileSystem>();
var assemblyLoader = new Mock<IAssemblyLoader>();
var identity = new Mock<IAssemblyIdentity>();
var basePath = AppContext.BaseDirectory;
var cacheDirectory = Path.Combine(basePath, ".cache");
var cachePath = Path.Combine(cacheDirectory, "module-cache.json");
// Existing cache with WRONG hash → forces regeneration
var existingCacheJson = """
{
"AssemblyHash": "OLDHASH",
"Modules": [ "OldModule.dll" ]
}
""";
fileSystem.Setup(fs => fs.CreateDirectory(cacheDirectory));
fileSystem.Setup(fs => fs.FileExists(cachePath)).Returns(true);
fileSystem.Setup(fs => fs.ReadAllText(cachePath)).Returns(existingCacheJson);
// Capture regenerated JSON
string? writtenJson = null;
fileSystem.Setup(fs => fs.WriteAllText(cachePath, It.IsAny<string>()))
.Callback<string, string>((_, json) => writtenJson = json);
// Hashing setup
var assembly = typeof(TestRegistration).Assembly;
identity.Setup(x => x.GetAssemblyForHashing()).Returns(assembly);
var fakeStream = new MemoryStream(new byte[] { 1, 2, 3, 4 });
fileSystem.Setup(fs => fs.OpenRead(assembly.Location)).Returns(fakeStream);
// Regeneration scan finds a DLL
var badDllPath = Path.Combine(basePath, "BadModule.dll");
fileSystem.Setup(fs => fs.GetFiles(basePath, "*.dll"))
.Returns(new[] { badDllPath });
// Critical: assembly load fails
assemblyLoader.Setup(l => l.LoadFrom(badDllPath))
.Throws(new BadImageFormatException("Not a .NET assembly"));
// After regeneration, RegisterAllModuleIocRegistrations will check FileExists
// but since no modules are added, this path is never hit.
// Still safe to mock it as false.
fileSystem.Setup(fs => fs.FileExists(It.IsAny<string>())).Returns(false);
var discovery = new ModuleDiscovery(fileSystem.Object, assemblyLoader.Object, identity.Object);
// Act
discovery.RegisterAllModuleIocRegistrations(new ContainerBuilder());
// Assert: regeneration happened
fileSystem.Verify(fs => fs.GetFiles(basePath, "*.dll"), Times.Once);
// Assert: cache was rewritten
fileSystem.Verify(fs => fs.WriteAllText(cachePath, It.IsAny<string>()), Times.Once);
// Assert: regenerated cache contains NO modules
Assert.That(writtenJson, Is.Not.Null);
Assert.That(writtenJson, Does.Not.Contain("BadModule.dll"));
}
[Test]
public void RegisterAllModuleIocRegistrations_InvokesRegistrationTypes()
{
// Arrange
TestRegistration.WasCalled = false;
var fileSystem = new Mock<IFileSystem>();
var assemblyLoader = new Mock<IAssemblyLoader>();
var identity = new Mock<IAssemblyIdentity>();
var basePath = AppContext.BaseDirectory;
var cacheDirectory = Path.Combine(basePath, ".cache");
var cachePath = Path.Combine(cacheDirectory, "module-cache.json");
// Fake hash bytes
var fakeBytes = new byte[] { 1, 2, 3, 4 };
var expectedHash = Convert.ToHexString(SHA256.HashData(fakeBytes));
// Cache contains our test module
var existingCacheJson = $$"""
{
"AssemblyHash": "{{expectedHash}}",
"Modules": [ "TestModule.dll" ]
}
""";
// Filesystem mocks
fileSystem.Setup(fs => fs.CreateDirectory(cacheDirectory));
fileSystem.Setup(fs => fs.FileExists(cachePath)).Returns(true);
fileSystem.Setup(fs => fs.ReadAllText(cachePath)).Returns(existingCacheJson);
// Hashing stream
var assembly = typeof(TestRegistration).Assembly;
identity.Setup(x => x.GetAssemblyForHashing()).Returns(assembly);
fileSystem.Setup(fs => fs.OpenRead(assembly.Location))
.Returns(new MemoryStream(fakeBytes));
// Module file exists
var modulePath = Path.Combine(basePath, "TestModule.dll");
fileSystem.Setup(fs => fs.FileExists(modulePath)).Returns(true);
// Assembly loader returns assembly containing TestRegistration
assemblyLoader.Setup(l => l.LoadFrom(modulePath))
.Returns(typeof(TestRegistration).Assembly);
var discovery = new ModuleDiscovery(fileSystem.Object, assemblyLoader.Object, identity.Object);
var builder = new ContainerBuilder();
// Act
discovery.RegisterAllModuleIocRegistrations(builder);
// Assert
Assert.That(TestRegistration.WasCalled, Is.True);
}
}

View File

@ -0,0 +1,13 @@
using Autofac;
namespace e_suite.DependencyInjection.UnitTests;
public class TestRegistration : IIocRegistration
{
public static bool WasCalled;
public void RegisterTypes(ContainerBuilder builder)
{
WasCalled = true;
}
}

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>e_suite.DependencyInjection.UnitTests</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\e-suite.DependencyInjection\e-suite.DependencyInjection.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,8 @@
using System.Reflection;
namespace e_suite.DependencyInjection;
public class DefaultAssemblyLoader : IAssemblyLoader
{
public Assembly LoadFrom(string path) => Assembly.LoadFrom(path);
}

View File

@ -1,59 +1,34 @@
using Autofac; using Autofac;
using eSuite.Core.Clock; using eSuite.Core.Clock;
using Microsoft.Extensions.Configuration;
using System.Reflection;
namespace e_suite.DependencyInjection; namespace e_suite.DependencyInjection;
public sealed class ModuleConfig
{
public List<string> Modules { get; set; } = new();
}
public class ESuiteModule : Autofac.Module public class ESuiteModule : Autofac.Module
{ {
private readonly IModuleDiscovery _moduleDiscovery;
public ESuiteModule()
: this(CreateDefaultDiscovery())
{
}
public ESuiteModule(IModuleDiscovery moduleDiscovery)
{
_moduleDiscovery = moduleDiscovery;
}
private static IModuleDiscovery CreateDefaultDiscovery() =>
new ModuleDiscovery(
new RealFileSystem(),
new DefaultAssemblyLoader(),
new EntryAssemblyIdentity()
);
protected override void Load(ContainerBuilder builder) protected override void Load(ContainerBuilder builder)
{ {
base.Load(builder); base.Load(builder);
builder.RegisterType<UtcClock>().As<IClock>().SingleInstance(); builder.RegisterType<UtcClock>().As<IClock>().SingleInstance();
RegisterAllModuleIocRegistrations(builder); _moduleDiscovery.RegisterAllModuleIocRegistrations(builder);
} }
protected static void RegisterAllModuleIocRegistrations(ContainerBuilder builder)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
.Build();
var moduleConfig = configuration.Get<ModuleConfig>();
var basePath = AppContext.BaseDirectory;
var assemblies = new List<Assembly>();
foreach (var module in moduleConfig.Modules)
{
var fullPath = Path.Combine(basePath, module);
if (!File.Exists(fullPath))
throw new FileNotFoundException($"Configured module not found: {fullPath}");
assemblies.Add(Assembly.LoadFrom(fullPath));
}
var registrationTypes = assemblies
.SelectMany(a => a.GetTypes())
.Where(t => typeof(IIocRegistration).IsAssignableFrom(t)
&& !t.IsAbstract
&& !t.IsInterface).ToList();
foreach (var type in registrationTypes)
{
var instance = (IIocRegistration)Activator.CreateInstance(type)!;
instance.RegisterTypes(builder);
}
}
} }

View File

@ -0,0 +1,9 @@
using System.Reflection;
namespace e_suite.DependencyInjection;
public class EntryAssemblyIdentity : IAssemblyIdentity
{
public Assembly GetAssemblyForHashing() =>
Assembly.GetEntryAssembly()!;
}

View File

@ -0,0 +1,8 @@
using System.Reflection;
namespace e_suite.DependencyInjection;
public interface IAssemblyIdentity
{
Assembly GetAssemblyForHashing();
}

View File

@ -0,0 +1,8 @@
using System.Reflection;
namespace e_suite.DependencyInjection;
public interface IAssemblyLoader
{
Assembly LoadFrom(string path);
}

View File

@ -0,0 +1,11 @@
namespace e_suite.DependencyInjection;
public interface IFileSystem
{
bool FileExists(string path);
void CreateDirectory(string path);
string[] GetFiles(string path, string searchPattern);
string ReadAllText(string path);
void WriteAllText(string path, string contents);
Stream OpenRead(string path);
}

View File

@ -0,0 +1,8 @@
using Autofac;
namespace e_suite.DependencyInjection;
public interface IModuleDiscovery
{
void RegisterAllModuleIocRegistrations(ContainerBuilder builder);
}

View File

@ -0,0 +1,7 @@
namespace e_suite.DependencyInjection;
public sealed class ModuleCache
{
public string AssemblyHash { get; set; } = string.Empty;
public List<string> Modules { get; set; } = new();
}

View File

@ -0,0 +1,125 @@
using System.Reflection;
using Autofac;
namespace e_suite.DependencyInjection;
public class ModuleDiscovery : IModuleDiscovery
{
private readonly IFileSystem _fileSystem;
private readonly IAssemblyLoader _assemblyLoader;
private readonly IAssemblyIdentity _assemblyIdentity;
public ModuleDiscovery(IFileSystem fileSystem, IAssemblyLoader assemblyLoader, IAssemblyIdentity assemblyIdentity)
{
_fileSystem = fileSystem;
_assemblyLoader = assemblyLoader;
_assemblyIdentity = assemblyIdentity;
}
public void RegisterAllModuleIocRegistrations(ContainerBuilder builder)
{
var cacheDirectory = Path.Combine(AppContext.BaseDirectory, ".cache");
_fileSystem.CreateDirectory(cacheDirectory);
var cachePath = Path.Combine(cacheDirectory, "module-cache.json");
var cache = LoadOrCreateModuleCache(cachePath);
var basePath = AppContext.BaseDirectory;
var assemblies = new List<Assembly>();
foreach (var module in cache.Modules)
{
var fullPath = Path.Combine(basePath, module);
if (!_fileSystem.FileExists(fullPath))
throw new FileNotFoundException($"Cached module not found: {fullPath}");
assemblies.Add(_assemblyLoader.LoadFrom(fullPath));
}
var registrationTypes = assemblies
.SelectMany(a => a.GetTypes())
.Where(t => typeof(IIocRegistration).IsAssignableFrom(t)
&& t is { IsAbstract: false, IsInterface: false })
.ToList();
foreach (var type in registrationTypes)
{
var instance = (IIocRegistration)Activator.CreateInstance(type)!;
instance.RegisterTypes(builder);
}
}
private ModuleCache LoadOrCreateModuleCache(string cachePath)
{
var currentHash = ComputeAssemblyHash();
if (_fileSystem.FileExists(cachePath))
{
var json = _fileSystem.ReadAllText(cachePath);
var cache = System.Text.Json.JsonSerializer.Deserialize<ModuleCache>(json);
if (cache is not null && cache.AssemblyHash == currentHash)
return cache;
}
// Cache missing or invalid → regenerate
var regenerated = RegenerateModuleCache(currentHash);
var output = System.Text.Json.JsonSerializer.Serialize(regenerated, new System.Text.Json.JsonSerializerOptions
{
WriteIndented = true
});
_fileSystem.WriteAllText(cachePath, output);
return regenerated;
}
private ModuleCache RegenerateModuleCache(string assemblyHash)
{
var basePath = AppContext.BaseDirectory;
var dlls = _fileSystem.GetFiles(basePath, "*.dll");
var modules = new List<string>();
foreach (var dll in dlls)
{
try
{
var asm = _assemblyLoader.LoadFrom(dll);
var hasRegistration = asm.GetTypes().Any(t =>
typeof(IIocRegistration).IsAssignableFrom(t) &&
!t.IsAbstract &&
!t.IsInterface);
if (hasRegistration)
modules.Add(Path.GetFileName(dll));
}
catch
{
// Ignore non-.NET DLLs or load failures
}
}
return new ModuleCache
{
AssemblyHash = assemblyHash,
Modules = modules
};
}
private string ComputeAssemblyHash()
{
var mainAssembly = _assemblyIdentity.GetAssemblyForHashing();
var path = mainAssembly.Location;
using var stream = _fileSystem.OpenRead(path);
using var sha = System.Security.Cryptography.SHA256.Create();
var hash = sha.ComputeHash(stream);
return Convert.ToHexString(hash);
}
}

View File

@ -0,0 +1,11 @@
namespace e_suite.DependencyInjection;
public class RealFileSystem : IFileSystem
{
public bool FileExists(string path) => File.Exists(path);
public void CreateDirectory(string path) => Directory.CreateDirectory(path);
public string[] GetFiles(string path, string searchPattern) => Directory.GetFiles(path, searchPattern);
public string ReadAllText(string path) => File.ReadAllText(path);
public void WriteAllText(string path, string contents) => File.WriteAllText(path, contents);
public Stream OpenRead(string path) => File.OpenRead(path);
}

View File

@ -16,7 +16,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="10.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -26,9 +26,6 @@ public class CoreRegistrationModule : ESuiteModule
var loggerFactory = LoggerFactory.Create(loggingBuilder => loggingBuilder.AddConsole()); var loggerFactory = LoggerFactory.Create(loggingBuilder => loggingBuilder.AddConsole());
builder.Register(x => loggerFactory.CreateLogger("e-Suite.MessageProcessor")).As<ILogger>().SingleInstance(); builder.Register(x => loggerFactory.CreateLogger("e-Suite.MessageProcessor")).As<ILogger>().SingleInstance();
//IClock clock = new UtcClock();
//builder.RegisterInstance(clock).As<IClock>().SingleInstance();
builder.RegisterInstance(ESuiteDatabaseExtension.BuildConfiguration()).As<IConfiguration>().SingleInstance(); builder.RegisterInstance(ESuiteDatabaseExtension.BuildConfiguration()).As<IConfiguration>().SingleInstance();
builder.Register(c => builder.Register(c =>
{ {
@ -40,33 +37,9 @@ public class CoreRegistrationModule : ESuiteModule
.As<IEsuiteDatabaseDbContext>() .As<IEsuiteDatabaseDbContext>()
.InstancePerLifetimeScope(); .InstancePerLifetimeScope();
//builder.Register(c => ESuiteDatabaseExtension.CreateDatabase(clock).GetAwaiter().GetResult())
// .As<IEsuiteDatabaseDbContext>()
// .InstancePerLifetimeScope();
builder.RegisterType<QueueProcessorService>().InstancePerLifetimeScope(); builder.RegisterType<QueueProcessorService>().InstancePerLifetimeScope();
builder.RegisterType<DatabaseQueueHandler>().InstancePerLifetimeScope(); builder.RegisterType<DatabaseQueueHandler>().InstancePerLifetimeScope();
builder.RegisterType<SigmaImportQueueHandler>().InstancePerLifetimeScope(); builder.RegisterType<SigmaImportQueueHandler>().InstancePerLifetimeScope();
builder.RegisterType<EFlowImportQueueHandler>().InstancePerLifetimeScope(); builder.RegisterType<EFlowImportQueueHandler>().InstancePerLifetimeScope();
//Service.Sentinel.IocRegistration.RegisterTypes(builder);
//Service.Performance.IocRegistration.RegisterTypes(builder);
//Modules.UserManager.IocRegistration.RegisterTypes(builder);
//Messaging.Common.DependencyInjection.CoreRegistrationModule.Load(builder);
//Modules.ExceptionLogManager.IocRegistration.RegisterTypes(builder);
//Service.SigmaImporter.IocRegistration.RegisterTypes(builder);
//Modules.GlossariesManager.IocRegistration.RegisterTypes(builder);
//Modules.DomainManager.IocRegistration.RegisterTypes(builder);
//Modules.CustomFieldsManager.IocRegistration.RegisterTypes(builder);
//Service.CustomFieldValidation.IocRegistration.RegisterTypes(builder);
//Modules.SequenceManager.IocRegistration.RegisterTypes(builder);
//Modules.FormsManager.IocRegistration.RegisterTypes(builder);
//Modules.SiteManager.IocRegistration.RegisterTypes(builder);
//Modules.SpecificationManager.IocRegistration.RegisterTypes(builder);
//Modules.OrganisationsManager.IocRegistration.RegisterTypes(builder);
//Modules.DomainManager.IocRegistration.RegisterTypes(builder);
//Modules.SSOManager.IocRegistration.RegisterTypes(builder);
//Service.EFlowSync.IocRegistration.RegisterTypes(builder);
} }
} }

View File

@ -28,27 +28,5 @@
}, },
"EflowAPI": { "EflowAPI": {
"Server": "https://sunrise-test-api-we.azurewebsites.net/" "Server": "https://sunrise-test-api-we.azurewebsites.net/"
}, }
"Modules": [
"e-suite.API.Common.dll",
"e-suite.Database.Audit.dll",
"e-suite.Database.SqlServer.dll",
"e-suite.Messaging.Common.dll",
"e-suite.Modules.CustomFieldsManager.dll",
"e-suite.Modules.DomainManager.dll",
"e-suite.Modules.ExceptionLogManager.dll",
"e-suite.Modules.FormsManager.dll",
"e-suite.Modules.GlossariesManager.dll",
"e-suite.Modules.OrganisationsManager.dll",
"e-suite.Modules.SequenceManager.dll",
"e-suite.Modules.SiteManager.dll",
"e-suite.Modules.SpecificationManager.dll",
"e-suite.Modules.SSOManager.dll",
"e-suite.Modules.UserManager.dll",
"e-suite.Service.CustomFieldValidation.dll",
"e-suite.Service.EFlowSync.dll",
"e-suite.Service.Performance.dll",
"e-suite.Service.Sentinel.dll",
"e-suite.Service.SigmaImporter.dll"
]
} }

View File

@ -1,37 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<RootNamespace>e_suite.MessageProcessor</RootNamespace> <RootNamespace>e_suite.MessageProcessor</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="appsettings.Development.json" /> <None Remove="appsettings.Development.json" />
<None Remove="appsettings.json" /> <None Remove="appsettings.json" />
<None Remove="appsettings.Production.json" /> <None Remove="appsettings.Production.json" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="appsettings.Production.json"> <Content Include="appsettings.Production.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
<Content Include="appsettings.Development.json"> <Content Include="appsettings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
<Content Include="appsettings.json"> <Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Autofac" Version="9.0.0" /> <PackageReference Include="Autofac" Version="9.0.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" /> <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" /> <PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj" /> <ProjectReference Include="..\..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj" />
<ProjectReference Include="..\..\e-suite.Database.Audit\e-suite.Database.Audit\e-suite.Database.Audit.csproj" /> <ProjectReference Include="..\..\e-suite.Database.Audit\e-suite.Database.Audit\e-suite.Database.Audit.csproj" />
@ -54,12 +54,12 @@
<ProjectReference Include="..\..\e-suite.Service.Performance\e-suite.Service.Performance\e-suite.Service.Performance.csproj" /> <ProjectReference Include="..\..\e-suite.Service.Performance\e-suite.Service.Performance\e-suite.Service.Performance.csproj" />
<ProjectReference Include="..\..\e-suite.Service.Sentinel\e-suite.Service.Sentinel\e-suite.Service.Sentinel.csproj" /> <ProjectReference Include="..\..\e-suite.Service.Sentinel\e-suite.Service.Sentinel\e-suite.Service.Sentinel.csproj" />
<ProjectReference Include="..\..\e-suite.Service.SigmaImporter\e-suite.Service.SigmaImporter\e-suite.Service.SigmaImporter.csproj" /> <ProjectReference Include="..\..\e-suite.Service.SigmaImporter\e-suite.Service.SigmaImporter\e-suite.Service.SigmaImporter.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="Dockerfile.Azure"> <None Update="Dockerfile.Azure">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,13 +1,14 @@
using Autofac; using Autofac;
using e_suite.API.Common; using e_suite.API.Common;
using e_suite.API.Common.repository; using e_suite.API.Common.repository;
using e_suite.DependencyInjection;
using e_suite.Modules.DomainManager.Repository; using e_suite.Modules.DomainManager.Repository;
namespace e_suite.Modules.DomainManager; namespace e_suite.Modules.DomainManager;
public class IocRegistration public class IocRegistration : IIocRegistration
{ {
public static void RegisterTypes(ContainerBuilder builder) public void RegisterTypes(ContainerBuilder builder)
{ {
builder.RegisterType<DomainRepository>().As<IDomainRepository>().InstancePerLifetimeScope(); builder.RegisterType<DomainRepository>().As<IDomainRepository>().InstancePerLifetimeScope();
builder.RegisterType<DomainManager>().As<IDomainManager>().InstancePerLifetimeScope(); builder.RegisterType<DomainManager>().As<IDomainManager>().InstancePerLifetimeScope();

View File

@ -13,5 +13,6 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj" /> <ProjectReference Include="..\..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj" />
<ProjectReference Include="..\..\e-suite.DependencyInjection\e-suite.DependencyInjection.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,13 +1,14 @@
using Autofac; using Autofac;
using e_suite.API.Common; using e_suite.API.Common;
using e_suite.API.Common.repository; using e_suite.API.Common.repository;
using e_suite.DependencyInjection;
using e_suite.Modules.FormsManager.Repository; using e_suite.Modules.FormsManager.Repository;
namespace e_suite.Modules.FormsManager; namespace e_suite.Modules.FormsManager;
public class IocRegistration public class IocRegistration : IIocRegistration
{ {
public static void RegisterTypes(ContainerBuilder builder) public void RegisterTypes(ContainerBuilder builder)
{ {
builder.RegisterType<FormRepository>().As<IFormRepository>().InstancePerLifetimeScope(); builder.RegisterType<FormRepository>().As<IFormRepository>().InstancePerLifetimeScope();
builder.RegisterType<FormsManager>().As<IFormsManager>().InstancePerLifetimeScope(); builder.RegisterType<FormsManager>().As<IFormsManager>().InstancePerLifetimeScope();

View File

@ -14,6 +14,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj" /> <ProjectReference Include="..\..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj" />
<ProjectReference Include="..\..\e-suite.DependencyInjection\e-suite.DependencyInjection.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,13 +1,14 @@
using Autofac; using Autofac;
using e_suite.API.Common; using e_suite.API.Common;
using e_suite.API.Common.repository; using e_suite.API.Common.repository;
using e_suite.DependencyInjection;
using e_suite.Modules.MailTemplatesManager.repository; using e_suite.Modules.MailTemplatesManager.repository;
namespace e_suite.Modules.MailTemplatesManager; namespace e_suite.Modules.MailTemplatesManager;
public class IocRegistration public class IocRegistration : IIocRegistration
{ {
public static void RegisterTypes(ContainerBuilder builder) public void RegisterTypes(ContainerBuilder builder)
{ {
builder.RegisterType<MailTemplatesManagerRepository>().As<IMailTemplatesManagerRepository>().InstancePerLifetimeScope(); builder.RegisterType<MailTemplatesManagerRepository>().As<IMailTemplatesManagerRepository>().InstancePerLifetimeScope();
builder.RegisterType<MailTemplateManager>().As<IMailTemplateManager>().InstancePerLifetimeScope(); builder.RegisterType<MailTemplateManager>().As<IMailTemplateManager>().InstancePerLifetimeScope();

View File

@ -14,6 +14,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj" /> <ProjectReference Include="..\..\e-suite.API.Common\e-suite.API.Common\e-suite.API.Common.csproj" />
<ProjectReference Include="..\..\e-suite.DependencyInjection\e-suite.DependencyInjection.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,13 +1,14 @@
using Autofac; using Autofac;
using e_suite.API.Common; using e_suite.API.Common;
using e_suite.API.Common.repository; using e_suite.API.Common.repository;
using e_suite.DependencyInjection;
using e_suite.Modules.OrganisationsManager.Repository; using e_suite.Modules.OrganisationsManager.Repository;
namespace e_suite.Modules.OrganisationsManager; namespace e_suite.Modules.OrganisationsManager;
public class IocRegistration public class IocRegistration : IIocRegistration
{ {
public static void RegisterTypes(ContainerBuilder builder) public void RegisterTypes(ContainerBuilder builder)
{ {
builder.RegisterType<OrganisationsManagerRepository>().As<IOrganisationsManagerRepository>().InstancePerLifetimeScope(); builder.RegisterType<OrganisationsManagerRepository>().As<IOrganisationsManagerRepository>().InstancePerLifetimeScope();
builder.RegisterType<OrganisationsManager>().As<IOrganisationsManager>().InstancePerLifetimeScope(); builder.RegisterType<OrganisationsManager>().As<IOrganisationsManager>().InstancePerLifetimeScope();

View File

@ -1475,11 +1475,11 @@
}, },
"Microsoft.Extensions.Configuration.FileExtensions": { "Microsoft.Extensions.Configuration.FileExtensions": {
"target": "Package", "target": "Package",
"version": "[8.0.0, )" "version": "[10.0.2, )"
}, },
"Microsoft.Extensions.Configuration.Json": { "Microsoft.Extensions.Configuration.Json": {
"target": "Package", "target": "Package",
"version": "[8.0.0, )" "version": "[10.0.2, )"
} }
}, },
"imports": [ "imports": [

View File

@ -154,49 +154,49 @@
"buildTransitive/netstandard2.0/Microsoft.Extensions.Configuration.Binder.targets": {} "buildTransitive/netstandard2.0/Microsoft.Extensions.Configuration.Binder.targets": {}
} }
}, },
"Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { "Microsoft.Extensions.Configuration.FileExtensions/10.0.2": {
"type": "package", "type": "package",
"dependencies": { "dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0", "Microsoft.Extensions.Configuration": "10.0.2",
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0", "Microsoft.Extensions.Configuration.Abstractions": "10.0.2",
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", "Microsoft.Extensions.FileProviders.Abstractions": "10.0.2",
"Microsoft.Extensions.FileProviders.Physical": "8.0.0", "Microsoft.Extensions.FileProviders.Physical": "10.0.2",
"Microsoft.Extensions.Primitives": "8.0.0" "Microsoft.Extensions.Primitives": "10.0.2"
}, },
"compile": { "compile": {
"lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { "lib/net10.0/Microsoft.Extensions.Configuration.FileExtensions.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"runtime": { "runtime": {
"lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { "lib/net10.0/Microsoft.Extensions.Configuration.FileExtensions.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"build": { "build": {
"buildTransitive/net6.0/_._": {} "buildTransitive/net8.0/_._": {}
} }
}, },
"Microsoft.Extensions.Configuration.Json/8.0.0": { "Microsoft.Extensions.Configuration.Json/10.0.2": {
"type": "package", "type": "package",
"dependencies": { "dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0", "Microsoft.Extensions.Configuration": "10.0.2",
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0", "Microsoft.Extensions.Configuration.Abstractions": "10.0.2",
"Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", "Microsoft.Extensions.Configuration.FileExtensions": "10.0.2",
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0" "Microsoft.Extensions.FileProviders.Abstractions": "10.0.2"
}, },
"compile": { "compile": {
"lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { "lib/net10.0/Microsoft.Extensions.Configuration.Json.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"runtime": { "runtime": {
"lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { "lib/net10.0/Microsoft.Extensions.Configuration.Json.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"build": { "build": {
"buildTransitive/net6.0/_._": {} "buildTransitive/net8.0/_._": {}
} }
}, },
"Microsoft.Extensions.DependencyInjection/10.0.2": { "Microsoft.Extensions.DependencyInjection/10.0.2": {
@ -234,60 +234,60 @@
"buildTransitive/net8.0/_._": {} "buildTransitive/net8.0/_._": {}
} }
}, },
"Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { "Microsoft.Extensions.FileProviders.Abstractions/10.0.2": {
"type": "package", "type": "package",
"dependencies": { "dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0" "Microsoft.Extensions.Primitives": "10.0.2"
}, },
"compile": { "compile": {
"lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { "lib/net10.0/Microsoft.Extensions.FileProviders.Abstractions.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"runtime": { "runtime": {
"lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { "lib/net10.0/Microsoft.Extensions.FileProviders.Abstractions.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"build": { "build": {
"buildTransitive/net6.0/_._": {} "buildTransitive/net8.0/_._": {}
} }
}, },
"Microsoft.Extensions.FileProviders.Physical/8.0.0": { "Microsoft.Extensions.FileProviders.Physical/10.0.2": {
"type": "package", "type": "package",
"dependencies": { "dependencies": {
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", "Microsoft.Extensions.FileProviders.Abstractions": "10.0.2",
"Microsoft.Extensions.FileSystemGlobbing": "8.0.0", "Microsoft.Extensions.FileSystemGlobbing": "10.0.2",
"Microsoft.Extensions.Primitives": "8.0.0" "Microsoft.Extensions.Primitives": "10.0.2"
}, },
"compile": { "compile": {
"lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { "lib/net10.0/Microsoft.Extensions.FileProviders.Physical.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"runtime": { "runtime": {
"lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { "lib/net10.0/Microsoft.Extensions.FileProviders.Physical.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"build": { "build": {
"buildTransitive/net6.0/_._": {} "buildTransitive/net8.0/_._": {}
} }
}, },
"Microsoft.Extensions.FileSystemGlobbing/8.0.0": { "Microsoft.Extensions.FileSystemGlobbing/10.0.2": {
"type": "package", "type": "package",
"compile": { "compile": {
"lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { "lib/net10.0/Microsoft.Extensions.FileSystemGlobbing.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"runtime": { "runtime": {
"lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { "lib/net10.0/Microsoft.Extensions.FileSystemGlobbing.dll": {
"related": ".xml" "related": ".xml"
} }
}, },
"build": { "build": {
"buildTransitive/net6.0/_._": {} "buildTransitive/net8.0/_._": {}
} }
}, },
"Microsoft.Extensions.Logging/10.0.2": { "Microsoft.Extensions.Logging/10.0.2": {
@ -443,8 +443,8 @@
"framework": ".NETCoreApp,Version=v10.0", "framework": ".NETCoreApp,Version=v10.0",
"dependencies": { "dependencies": {
"Autofac": "9.0.0", "Autofac": "9.0.0",
"Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", "Microsoft.Extensions.Configuration.FileExtensions": "10.0.2",
"Microsoft.Extensions.Configuration.Json": "8.0.0", "Microsoft.Extensions.Configuration.Json": "10.0.2",
"eSuite.Core": "1.0.0" "eSuite.Core": "1.0.0"
}, },
"compile": { "compile": {
@ -719,64 +719,62 @@
"useSharedDesignerContext.txt" "useSharedDesignerContext.txt"
] ]
}, },
"Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { "Microsoft.Extensions.Configuration.FileExtensions/10.0.2": {
"sha512": "McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", "sha512": "6vStNVa/7hcT6VrYvVMGCWUl/QIKwNeQaSGnKw1E4RPpZbQbOjDsATCbrQUa0sFUs7LW8T9aZ2NBKttMz1+WuA==",
"type": "package", "type": "package",
"path": "microsoft.extensions.configuration.fileextensions/8.0.0", "path": "microsoft.extensions.configuration.fileextensions/10.0.2",
"files": [ "files": [
".nupkg.metadata", ".nupkg.metadata",
".signature.p7s", ".signature.p7s",
"Icon.png", "Icon.png",
"LICENSE.TXT",
"PACKAGE.md", "PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT", "THIRD-PARTY-NOTICES.TXT",
"buildTransitive/net461/Microsoft.Extensions.Configuration.FileExtensions.targets", "buildTransitive/net461/Microsoft.Extensions.Configuration.FileExtensions.targets",
"buildTransitive/net462/_._", "buildTransitive/net462/_._",
"buildTransitive/net6.0/_._", "buildTransitive/net8.0/_._",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.FileExtensions.targets", "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.FileExtensions.targets",
"lib/net10.0/Microsoft.Extensions.Configuration.FileExtensions.dll",
"lib/net10.0/Microsoft.Extensions.Configuration.FileExtensions.xml",
"lib/net462/Microsoft.Extensions.Configuration.FileExtensions.dll", "lib/net462/Microsoft.Extensions.Configuration.FileExtensions.dll",
"lib/net462/Microsoft.Extensions.Configuration.FileExtensions.xml", "lib/net462/Microsoft.Extensions.Configuration.FileExtensions.xml",
"lib/net6.0/Microsoft.Extensions.Configuration.FileExtensions.dll",
"lib/net6.0/Microsoft.Extensions.Configuration.FileExtensions.xml",
"lib/net7.0/Microsoft.Extensions.Configuration.FileExtensions.dll",
"lib/net7.0/Microsoft.Extensions.Configuration.FileExtensions.xml",
"lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll", "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll",
"lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.xml", "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.xml",
"lib/net9.0/Microsoft.Extensions.Configuration.FileExtensions.dll",
"lib/net9.0/Microsoft.Extensions.Configuration.FileExtensions.xml",
"lib/netstandard2.0/Microsoft.Extensions.Configuration.FileExtensions.dll", "lib/netstandard2.0/Microsoft.Extensions.Configuration.FileExtensions.dll",
"lib/netstandard2.0/Microsoft.Extensions.Configuration.FileExtensions.xml", "lib/netstandard2.0/Microsoft.Extensions.Configuration.FileExtensions.xml",
"microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512", "microsoft.extensions.configuration.fileextensions.10.0.2.nupkg.sha512",
"microsoft.extensions.configuration.fileextensions.nuspec", "microsoft.extensions.configuration.fileextensions.nuspec",
"useSharedDesignerContext.txt" "useSharedDesignerContext.txt"
] ]
}, },
"Microsoft.Extensions.Configuration.Json/8.0.0": { "Microsoft.Extensions.Configuration.Json/10.0.2": {
"sha512": "C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", "sha512": "ovjOVr+rNxOT249iezwihlPNMaIJdBC6PMGeMnzhkm5EoKJWFjp3mmvtndfHY6A88X4wulXlidMhmjX8v6V/aw==",
"type": "package", "type": "package",
"path": "microsoft.extensions.configuration.json/8.0.0", "path": "microsoft.extensions.configuration.json/10.0.2",
"files": [ "files": [
".nupkg.metadata", ".nupkg.metadata",
".signature.p7s", ".signature.p7s",
"Icon.png", "Icon.png",
"LICENSE.TXT",
"PACKAGE.md", "PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT", "THIRD-PARTY-NOTICES.TXT",
"buildTransitive/net461/Microsoft.Extensions.Configuration.Json.targets", "buildTransitive/net461/Microsoft.Extensions.Configuration.Json.targets",
"buildTransitive/net462/_._", "buildTransitive/net462/_._",
"buildTransitive/net6.0/_._", "buildTransitive/net8.0/_._",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.Json.targets", "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.Json.targets",
"lib/net10.0/Microsoft.Extensions.Configuration.Json.dll",
"lib/net10.0/Microsoft.Extensions.Configuration.Json.xml",
"lib/net462/Microsoft.Extensions.Configuration.Json.dll", "lib/net462/Microsoft.Extensions.Configuration.Json.dll",
"lib/net462/Microsoft.Extensions.Configuration.Json.xml", "lib/net462/Microsoft.Extensions.Configuration.Json.xml",
"lib/net6.0/Microsoft.Extensions.Configuration.Json.dll",
"lib/net6.0/Microsoft.Extensions.Configuration.Json.xml",
"lib/net7.0/Microsoft.Extensions.Configuration.Json.dll",
"lib/net7.0/Microsoft.Extensions.Configuration.Json.xml",
"lib/net8.0/Microsoft.Extensions.Configuration.Json.dll", "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll",
"lib/net8.0/Microsoft.Extensions.Configuration.Json.xml", "lib/net8.0/Microsoft.Extensions.Configuration.Json.xml",
"lib/net9.0/Microsoft.Extensions.Configuration.Json.dll",
"lib/net9.0/Microsoft.Extensions.Configuration.Json.xml",
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Json.dll", "lib/netstandard2.0/Microsoft.Extensions.Configuration.Json.dll",
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Json.xml", "lib/netstandard2.0/Microsoft.Extensions.Configuration.Json.xml",
"lib/netstandard2.1/Microsoft.Extensions.Configuration.Json.dll", "lib/netstandard2.1/Microsoft.Extensions.Configuration.Json.dll",
"lib/netstandard2.1/Microsoft.Extensions.Configuration.Json.xml", "lib/netstandard2.1/Microsoft.Extensions.Configuration.Json.xml",
"microsoft.extensions.configuration.json.8.0.0.nupkg.sha512", "microsoft.extensions.configuration.json.10.0.2.nupkg.sha512",
"microsoft.extensions.configuration.json.nuspec", "microsoft.extensions.configuration.json.nuspec",
"useSharedDesignerContext.txt" "useSharedDesignerContext.txt"
] ]
@ -843,90 +841,89 @@
"useSharedDesignerContext.txt" "useSharedDesignerContext.txt"
] ]
}, },
"Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { "Microsoft.Extensions.FileProviders.Abstractions/10.0.2": {
"sha512": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", "sha512": "+r/eJ+slW/EmwWmH3En4gzRg1k6+yTqexoHBrMuz5fxsIKJA8MDiSGepjw/ko3XyNqg+w3dxQe+huoVXs5XDJw==",
"type": "package", "type": "package",
"path": "microsoft.extensions.fileproviders.abstractions/8.0.0", "path": "microsoft.extensions.fileproviders.abstractions/10.0.2",
"files": [ "files": [
".nupkg.metadata", ".nupkg.metadata",
".signature.p7s", ".signature.p7s",
"Icon.png", "Icon.png",
"LICENSE.TXT",
"PACKAGE.md", "PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT", "THIRD-PARTY-NOTICES.TXT",
"buildTransitive/net461/Microsoft.Extensions.FileProviders.Abstractions.targets", "buildTransitive/net461/Microsoft.Extensions.FileProviders.Abstractions.targets",
"buildTransitive/net462/_._", "buildTransitive/net462/_._",
"buildTransitive/net6.0/_._", "buildTransitive/net8.0/_._",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileProviders.Abstractions.targets", "buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileProviders.Abstractions.targets",
"lib/net10.0/Microsoft.Extensions.FileProviders.Abstractions.dll",
"lib/net10.0/Microsoft.Extensions.FileProviders.Abstractions.xml",
"lib/net462/Microsoft.Extensions.FileProviders.Abstractions.dll", "lib/net462/Microsoft.Extensions.FileProviders.Abstractions.dll",
"lib/net462/Microsoft.Extensions.FileProviders.Abstractions.xml", "lib/net462/Microsoft.Extensions.FileProviders.Abstractions.xml",
"lib/net6.0/Microsoft.Extensions.FileProviders.Abstractions.dll",
"lib/net6.0/Microsoft.Extensions.FileProviders.Abstractions.xml",
"lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll", "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll",
"lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.xml", "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.xml",
"lib/net9.0/Microsoft.Extensions.FileProviders.Abstractions.dll",
"lib/net9.0/Microsoft.Extensions.FileProviders.Abstractions.xml",
"lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll", "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll",
"lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.xml", "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.xml",
"microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512", "microsoft.extensions.fileproviders.abstractions.10.0.2.nupkg.sha512",
"microsoft.extensions.fileproviders.abstractions.nuspec", "microsoft.extensions.fileproviders.abstractions.nuspec",
"useSharedDesignerContext.txt" "useSharedDesignerContext.txt"
] ]
}, },
"Microsoft.Extensions.FileProviders.Physical/8.0.0": { "Microsoft.Extensions.FileProviders.Physical/10.0.2": {
"sha512": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", "sha512": "4+ypApaugtHIz5Q2Z3oC4+erDbOgy0HrMFYS3Nm3qmTXyqK7sU7LJWY9gci99Wcx6j7ivgk8kdCkgmvsA4t0Ow==",
"type": "package", "type": "package",
"path": "microsoft.extensions.fileproviders.physical/8.0.0", "path": "microsoft.extensions.fileproviders.physical/10.0.2",
"files": [ "files": [
".nupkg.metadata", ".nupkg.metadata",
".signature.p7s", ".signature.p7s",
"Icon.png", "Icon.png",
"LICENSE.TXT",
"PACKAGE.md", "PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT", "THIRD-PARTY-NOTICES.TXT",
"buildTransitive/net461/Microsoft.Extensions.FileProviders.Physical.targets", "buildTransitive/net461/Microsoft.Extensions.FileProviders.Physical.targets",
"buildTransitive/net462/_._", "buildTransitive/net462/_._",
"buildTransitive/net6.0/_._", "buildTransitive/net8.0/_._",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileProviders.Physical.targets", "buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileProviders.Physical.targets",
"lib/net10.0/Microsoft.Extensions.FileProviders.Physical.dll",
"lib/net10.0/Microsoft.Extensions.FileProviders.Physical.xml",
"lib/net462/Microsoft.Extensions.FileProviders.Physical.dll", "lib/net462/Microsoft.Extensions.FileProviders.Physical.dll",
"lib/net462/Microsoft.Extensions.FileProviders.Physical.xml", "lib/net462/Microsoft.Extensions.FileProviders.Physical.xml",
"lib/net6.0/Microsoft.Extensions.FileProviders.Physical.dll",
"lib/net6.0/Microsoft.Extensions.FileProviders.Physical.xml",
"lib/net7.0/Microsoft.Extensions.FileProviders.Physical.dll",
"lib/net7.0/Microsoft.Extensions.FileProviders.Physical.xml",
"lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll", "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll",
"lib/net8.0/Microsoft.Extensions.FileProviders.Physical.xml", "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.xml",
"lib/net9.0/Microsoft.Extensions.FileProviders.Physical.dll",
"lib/net9.0/Microsoft.Extensions.FileProviders.Physical.xml",
"lib/netstandard2.0/Microsoft.Extensions.FileProviders.Physical.dll", "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Physical.dll",
"lib/netstandard2.0/Microsoft.Extensions.FileProviders.Physical.xml", "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Physical.xml",
"microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512", "microsoft.extensions.fileproviders.physical.10.0.2.nupkg.sha512",
"microsoft.extensions.fileproviders.physical.nuspec", "microsoft.extensions.fileproviders.physical.nuspec",
"useSharedDesignerContext.txt" "useSharedDesignerContext.txt"
] ]
}, },
"Microsoft.Extensions.FileSystemGlobbing/8.0.0": { "Microsoft.Extensions.FileSystemGlobbing/10.0.2": {
"sha512": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", "sha512": "XozoMaWcFIv1tv0LDF+YMeZYjiNiNIewpNdZ3TEoVGf8ROrp0hVoEdUyUBsI8oYGM5U3Z5hiNEv0j2Z5COnMgg==",
"type": "package", "type": "package",
"path": "microsoft.extensions.filesystemglobbing/8.0.0", "path": "microsoft.extensions.filesystemglobbing/10.0.2",
"files": [ "files": [
".nupkg.metadata", ".nupkg.metadata",
".signature.p7s", ".signature.p7s",
"Icon.png", "Icon.png",
"LICENSE.TXT",
"PACKAGE.md", "PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT", "THIRD-PARTY-NOTICES.TXT",
"buildTransitive/net461/Microsoft.Extensions.FileSystemGlobbing.targets", "buildTransitive/net461/Microsoft.Extensions.FileSystemGlobbing.targets",
"buildTransitive/net462/_._", "buildTransitive/net462/_._",
"buildTransitive/net6.0/_._", "buildTransitive/net8.0/_._",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileSystemGlobbing.targets", "buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileSystemGlobbing.targets",
"lib/net10.0/Microsoft.Extensions.FileSystemGlobbing.dll",
"lib/net10.0/Microsoft.Extensions.FileSystemGlobbing.xml",
"lib/net462/Microsoft.Extensions.FileSystemGlobbing.dll", "lib/net462/Microsoft.Extensions.FileSystemGlobbing.dll",
"lib/net462/Microsoft.Extensions.FileSystemGlobbing.xml", "lib/net462/Microsoft.Extensions.FileSystemGlobbing.xml",
"lib/net6.0/Microsoft.Extensions.FileSystemGlobbing.dll",
"lib/net6.0/Microsoft.Extensions.FileSystemGlobbing.xml",
"lib/net7.0/Microsoft.Extensions.FileSystemGlobbing.dll",
"lib/net7.0/Microsoft.Extensions.FileSystemGlobbing.xml",
"lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll", "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll",
"lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.xml", "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.xml",
"lib/net9.0/Microsoft.Extensions.FileSystemGlobbing.dll",
"lib/net9.0/Microsoft.Extensions.FileSystemGlobbing.xml",
"lib/netstandard2.0/Microsoft.Extensions.FileSystemGlobbing.dll", "lib/netstandard2.0/Microsoft.Extensions.FileSystemGlobbing.dll",
"lib/netstandard2.0/Microsoft.Extensions.FileSystemGlobbing.xml", "lib/netstandard2.0/Microsoft.Extensions.FileSystemGlobbing.xml",
"microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512", "microsoft.extensions.filesystemglobbing.10.0.2.nupkg.sha512",
"microsoft.extensions.filesystemglobbing.nuspec", "microsoft.extensions.filesystemglobbing.nuspec",
"useSharedDesignerContext.txt" "useSharedDesignerContext.txt"
] ]

View File

@ -36,8 +36,6 @@ public class CoreRegistrationModule : ESuiteModule
.As<IEsuiteDatabaseDbContext>() .As<IEsuiteDatabaseDbContext>()
.InstancePerLifetimeScope(); .InstancePerLifetimeScope();
//Messaging.Common.IocRegistration.RegisterTypes(builder);
builder.RegisterType<NightlyCleanUp>(); builder.RegisterType<NightlyCleanUp>();
builder.RegisterType<NightlySigmaImport>(); builder.RegisterType<NightlySigmaImport>();
} }

View File

@ -1,10 +1,5 @@
{ {
"RabbitMQ": { "RabbitMQ": {
"hostname": "localhost" "hostname": "localhost"
}, }
"Modules": [
"e-suite.API.Common.dll",
"e-suite.Database.SqlServer.dll",
"e-suite.Messaging.Common.dll"
]
} }

View File

@ -3,6 +3,8 @@ using System.Net.Mail;
using System.Net.Mime; using System.Net.Mime;
using e_suite.API.Common.exceptions; using e_suite.API.Common.exceptions;
using e_suite.API.Common.repository; using e_suite.API.Common.repository;
using e_suite.Database.Audit;
using e_suite.Database.Audit.AuditEngine;
using e_suite.Service.Mail.Facade; using e_suite.Service.Mail.Facade;
using e_suite.Service.Mail.Helper; using e_suite.Service.Mail.Helper;
using eSuite.Core.MailService; using eSuite.Core.MailService;
@ -78,7 +80,31 @@ public class MailService : IMailService
try try
{ {
await client.SendMailAsync(message, cancellationToken); await client.SendMailAsync(message, cancellationToken);
//todo add audit record here to say that email of mailtype has been sent to user. var auditUserDetails = new AuditUserDetails
{
UserDisplayName = "Mail service"
};
var fields = new Dictionary<string, Change>
{
["Address"] = new()
{
NewValue = address.Email,
},
["DisplayName"] = new()
{
NewValue = address.DisplayName
},
["EmailType"] = new()
{
NewValue = emailRequest.EmailType
},
["Subject"] = new()
{
NewValue = message.Subject
}
};
await _userManagerRepository.AddAdhocAuditEntry(auditUserDetails, AuditType.EmailSent, fields, cancellationToken);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -159,6 +159,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.Service.SigmaImport
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.DependencyInjection", "e-suite.DependencyInjection\e-suite.DependencyInjection.csproj", "{1D974411-767E-4242-96F7-E545D285B356}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.DependencyInjection", "e-suite.DependencyInjection\e-suite.DependencyInjection.csproj", "{1D974411-767E-4242-96F7-E545D285B356}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "e-suite.DependencyInjection.UnitTests", "e-suite.DependencyInjection.UnitTests\e-suite.DependencyInjection.UnitTests.csproj", "{8D343418-7E3A-40E5-A5CF-6497221F3F7E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -445,6 +447,10 @@ Global
{1D974411-767E-4242-96F7-E545D285B356}.Debug|Any CPU.Build.0 = Debug|Any CPU {1D974411-767E-4242-96F7-E545D285B356}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D974411-767E-4242-96F7-E545D285B356}.Release|Any CPU.ActiveCfg = Release|Any CPU {1D974411-767E-4242-96F7-E545D285B356}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D974411-767E-4242-96F7-E545D285B356}.Release|Any CPU.Build.0 = Release|Any CPU {1D974411-767E-4242-96F7-E545D285B356}.Release|Any CPU.Build.0 = Release|Any CPU
{8D343418-7E3A-40E5-A5CF-6497221F3F7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D343418-7E3A-40E5-A5CF-6497221F3F7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D343418-7E3A-40E5-A5CF-6497221F3F7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D343418-7E3A-40E5-A5CF-6497221F3F7E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -516,6 +522,7 @@ Global
{63981A57-8140-CE4B-DFFC-00C31058CDB2} = {27EA902C-3CD0-4A8F-BA75-8D1AF87902AC} {63981A57-8140-CE4B-DFFC-00C31058CDB2} = {27EA902C-3CD0-4A8F-BA75-8D1AF87902AC}
{068C2F1E-9DF0-34DC-159D-E75FB31849E4} = {726E46E8-E6E2-44D1-AB3B-85481330A84E} {068C2F1E-9DF0-34DC-159D-E75FB31849E4} = {726E46E8-E6E2-44D1-AB3B-85481330A84E}
{1D974411-767E-4242-96F7-E545D285B356} = {A0787221-622B-4D00-A566-BF7297378322} {1D974411-767E-4242-96F7-E545D285B356} = {A0787221-622B-4D00-A566-BF7297378322}
{8D343418-7E3A-40E5-A5CF-6497221F3F7E} = {27EA902C-3CD0-4A8F-BA75-8D1AF87902AC}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C5175258-F776-4FF9-A9EE-386312E47061} SolutionGuid = {C5175258-F776-4FF9-A9EE-386312E47061}