Add ServiceCollection extensions for Oqtane

This commit is contained in:
Hisham Bin Ateya 2020-01-03 20:01:08 +03:00
parent b18942e72d
commit 35c55750bb
3 changed files with 127 additions and 138 deletions

View File

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.Extensions.Hosting;
using Oqtane.Infrastructure;
using Oqtane.Modules;
namespace Microsoft.Extensions.DependencyInjection
{
public static class OqtaneServiceCollectionExtensions
{
private static readonly IList<Assembly> _oqtaneModuleAssemblies = new List<Assembly>();
private static Assembly[] Assemblies => AppDomain.CurrentDomain.GetAssemblies();
internal static IEnumerable<Assembly> GetOqtaneModuleAssemblies() => _oqtaneModuleAssemblies;
public static IServiceCollection AddOqtaneModules(this IServiceCollection services)
{
var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var assembliesFolder = new DirectoryInfo(assemblyPath);
// iterate through Oqtane module assemblies in /bin ( filter is narrow to optimize loading process )
foreach (var file in assembliesFolder.EnumerateFiles("*.Module.*.dll"))
{
// check if assembly is already loaded
var assembly = Assemblies.Where(a => a.Location == file.FullName).FirstOrDefault();
if (assembly == null)
{
// load assembly from stream to prevent locking file ( as long as dependencies are in /bin they will load as well )
assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(file.FullName)));
_oqtaneModuleAssemblies.Add(assembly);
}
}
return services;
}
public static IServiceCollection AddOqtaneThemes(this IServiceCollection services)
{
var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var assembliesFolder = new DirectoryInfo(assemblyPath);
// iterate through Oqtane theme assemblies in /bin ( filter is narrow to optimize loading process )
foreach (var file in assembliesFolder.EnumerateFiles("*.Theme.*.dll"))
{
// check if assembly is already loaded
var assembly = Assemblies.Where(a => a.Location == file.FullName).FirstOrDefault();
if (assembly == null)
{
// load assembly from stream to prevent locking file ( as long as dependencies are in /bin they will load as well )
assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(file.FullName)));
_oqtaneModuleAssemblies.Add(assembly);
}
}
return services;
}
public static IServiceCollection AddOqtaneServices(this IServiceCollection services)
{
// dynamically register module services, contexts, and repository classes
var assemblies = Assemblies.
Where(item => item.FullName.StartsWith("Oqtane.") || item.FullName.Contains(".Module.")).ToArray();
foreach (var assembly in assemblies)
{
var implementationTypes = assembly.GetTypes()
.Where(t => t.GetInterfaces().Contains(typeof(IService)))
.ToArray();
foreach (var implementationType in implementationTypes)
{
var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, "I" + implementationType.Name));
if (serviceType != null)
{
services.AddScoped(serviceType, implementationType); // traditional service interface
}
else
{
services.AddScoped(implementationType, implementationType); // no interface defined for service
}
}
}
return services;
}
public static IServiceCollection AddOqtaneHostedServices(this IServiceCollection services)
{
// dynamically register hosted services
foreach (var assembly in Assemblies)
{
var serviceTypes = assembly.GetTypes()
.Where(t => t.GetInterfaces().Contains(typeof(IHostedService)))
.ToArray();
foreach (var serviceType in serviceTypes)
{
if (serviceType.Name != nameof(HostedServiceBase))
{
services.AddSingleton(typeof(IHostedService), serviceType);
}
}
}
return services;
}
}
}

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
@ -9,10 +7,10 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class MvcModuleExtensions
{
public static IMvcBuilder AddModuleAssemblies(this IMvcBuilder mvcBuilder, List<Assembly> assemblies)
public static IMvcBuilder AddOqtaneApplicationParts(this IMvcBuilder mvcBuilder)
{
// load MVC application parts from module assemblies
foreach (Assembly assembly in assemblies)
foreach (Assembly assembly in OqtaneServiceCollectionExtensions.GetOqtaneModuleAssemblies())
{
// check if assembly contains MVC Controllers
if (assembly.GetTypes().Where(item => item.IsSubclassOf(typeof(Controller))).ToArray().Length > 0)

View File

@ -180,75 +180,15 @@ namespace Oqtane.Server
services.AddTransient<IJobRepository, JobRepository>();
services.AddTransient<IJobLogRepository, JobLogRepository>();
// get list of loaded assemblies
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
DirectoryInfo folder = new DirectoryInfo(path);
List<Assembly> moduleassemblies = new List<Assembly>();
services.AddOqtaneModules();
services.AddOqtaneThemes();
// iterate through Oqtane module assemblies in /bin ( filter is narrow to optimize loading process )
foreach (FileInfo file in folder.EnumerateFiles("*.Module.*.dll"))
{
// check if assembly is already loaded
Assembly assembly = assemblies.Where(item => item.Location == file.FullName).FirstOrDefault();
if (assembly == null)
{
// load assembly from stream to prevent locking file ( as long as dependencies are in /bin they will load as well )
assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(file.FullName)));
moduleassemblies.Add(assembly);
}
}
services.AddMvc()
.AddOqtaneApplicationParts()
.AddNewtonsoftJson();
// iterate through Oqtane theme assemblies in /bin ( filter is narrow to optimize loading process )
foreach (FileInfo file in folder.EnumerateFiles("*.Theme.*.dll"))
{
// check if assembly is already loaded
Assembly assembly = assemblies.Where(item => item.Location == file.FullName).FirstOrDefault();
if (assembly == null)
{
// load assembly from stream to prevent locking file ( as long as dependencies are in /bin they will load as well )
assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(file.FullName)));
}
}
services.AddMvc().AddModuleAssemblies(moduleassemblies).AddNewtonsoftJson();
// dynamically register module services, contexts, and repository classes
assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(item => item.FullName.StartsWith("Oqtane.") || item.FullName.Contains(".Module.")).ToArray();
foreach (Assembly assembly in assemblies)
{
Type[] implementationtypes = assembly.GetTypes()
.Where(item => item.GetInterfaces().Contains(typeof(IService)))
.ToArray();
foreach (Type implementationtype in implementationtypes)
{
Type servicetype = Type.GetType(implementationtype.AssemblyQualifiedName.Replace(implementationtype.Name, "I" + implementationtype.Name));
if (servicetype != null)
{
services.AddScoped(servicetype, implementationtype); // traditional service interface
}
else
{
services.AddScoped(implementationtype, implementationtype); // no interface defined for service
}
}
}
// dynamically register hosted services
foreach (Assembly assembly in assemblies)
{
Type[] servicetypes = assembly.GetTypes()
.Where(item => item.GetInterfaces().Contains(typeof(IHostedService)))
.ToArray();
foreach (Type servicetype in servicetypes)
{
if (servicetype.Name != "HostedServiceBase")
{
services.AddSingleton(typeof(IHostedService), servicetype);
}
}
}
services.AddOqtaneServices();
services.AddOqtaneHostedServices();
services.AddSwaggerGen(c =>
{
@ -387,74 +327,15 @@ namespace Oqtane.Server
services.AddTransient<IJobRepository, JobRepository>();
services.AddTransient<IJobLogRepository, JobLogRepository>();
// get list of loaded assemblies
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
DirectoryInfo folder = new DirectoryInfo(path);
List<Assembly> moduleassemblies = new List<Assembly>();
services.AddOqtaneModules();
services.AddOqtaneThemes();
// iterate through Oqtane module assemblies in /bin ( filter is narrow to optimize loading process )
foreach (FileInfo file in folder.EnumerateFiles("*.Module.*.dll"))
{
// check if assembly is already loaded
Assembly assembly = assemblies.Where(item => item.Location == file.FullName).FirstOrDefault();
if (assembly == null)
{
// load assembly from stream to prevent locking file ( as long as dependencies are in /bin they will load as well )
assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(file.FullName)));
}
}
services.AddMvc()
.AddOqtaneApplicationParts()
.AddNewtonsoftJson();
// iterate through Oqtane theme assemblies in /bin ( filter is narrow to optimize loading process )
foreach (FileInfo file in folder.EnumerateFiles("*.Theme.*.dll"))
{
// check if assembly is already loaded
Assembly assembly = assemblies.Where(item => item.Location == file.FullName).FirstOrDefault();
if (assembly == null)
{
// load assembly from stream to prevent locking file ( as long as dependencies are in /bin they will load as well )
assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(file.FullName)));
}
}
services.AddMvc().AddModuleAssemblies(moduleassemblies).AddNewtonsoftJson();
// dynamically register module services, contexts, and repository classes
assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(item => item.FullName.StartsWith("Oqtane.") || item.FullName.Contains(".Module.")).ToArray();
foreach (Assembly assembly in assemblies)
{
Type[] implementationtypes = assembly.GetTypes()
.Where(item => item.GetInterfaces().Contains(typeof(IService)))
.ToArray();
foreach (Type implementationtype in implementationtypes)
{
Type servicetype = Type.GetType(implementationtype.AssemblyQualifiedName.Replace(implementationtype.Name, "I" + implementationtype.Name));
if (servicetype != null)
{
services.AddScoped(servicetype, implementationtype); // traditional service interface
}
else
{
services.AddScoped(implementationtype, implementationtype); // no interface defined for service
}
}
}
// dynamically register hosted services
foreach (Assembly assembly in assemblies)
{
Type[] servicetypes = assembly.GetTypes()
.Where(item => item.GetInterfaces().Contains(typeof(IHostedService)))
.ToArray();
foreach (Type servicetype in servicetypes)
{
if (servicetype.Name != "HostedServiceBase")
{
services.AddSingleton(typeof(IHostedService), servicetype);
}
}
}
services.AddOqtaneServices();
services.AddOqtaneHostedServices();
services.AddSwaggerGen(c =>
{