* Incremental work on samples * Rename HTTP middleware and update samples * Rename HTTP Activities to Workflows * Automatically register core activities when adding Elsa * Fix feature registration bug * Add default auth feature * Make activity serializer more flexible * Bump designer version * Add workflow server + designer samples * Simplify EntityFrameworkCore projects * Update solution * Add Sqlite package references to ensure the correct version is used * Update sample project with EF Core * Update EF extensions * Add server + designer sample project * Cleanup AllInOne project and add some XML comments * Rename ci.yml and add CI for Docker file
77 lines
2.8 KiB
C#
77 lines
2.8 KiB
C#
using System.Reflection;
|
|
using Elsa.Features.Attributes;
|
|
using Elsa.Features.Extensions;
|
|
using Elsa.Features.Services;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
namespace Elsa.Features.Implementations;
|
|
|
|
/// <inheritdoc />
|
|
public class Module : IModule
|
|
{
|
|
private record HostedServiceDescriptor(int Order, Type HostedServiceType);
|
|
|
|
private ISet<IFeature> _features = new HashSet<IFeature>();
|
|
private readonly ICollection<HostedServiceDescriptor> _hostedServiceDescriptors = new List<HostedServiceDescriptor>();
|
|
|
|
/// <summary>
|
|
/// Constructor.
|
|
/// </summary>
|
|
public Module(IServiceCollection services)
|
|
{
|
|
Services = services;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IServiceCollection Services { get; }
|
|
|
|
/// <inheritdoc />
|
|
public IDictionary<object, object> Properties { get; } = new Dictionary<object, object>();
|
|
|
|
/// <inheritdoc />
|
|
public T Configure<T>(Action<T>? configure = default) where T : class, IFeature => Configure(module => (T)Activator.CreateInstance(typeof(T), module)!, configure);
|
|
|
|
/// <inheritdoc />
|
|
public T Configure<T>(Func<IModule, T> factory, Action<T>? configure = default) where T : class, IFeature
|
|
{
|
|
if (_features.FirstOrDefault(x => x is T) is not T feature)
|
|
{
|
|
feature = factory(this);
|
|
_features.Add(feature);
|
|
}
|
|
|
|
configure?.Invoke(feature);
|
|
return feature;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IModule ConfigureHostedService<T>(int priority = 0)
|
|
{
|
|
_hostedServiceDescriptors.Add(new HostedServiceDescriptor(priority, typeof(T)));
|
|
return this;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Apply()
|
|
{
|
|
var featureTypes = _features.Select(x => x.GetType()).TSort(x => x.GetCustomAttributes<DependsOn>().Select(dependsOn => dependsOn.Type)).ToList();
|
|
var features = featureTypes.Select(featureType => _features.FirstOrDefault(x => x.GetType() == featureType) ?? (IFeature)Activator.CreateInstance(featureType, this)!).ToList();
|
|
|
|
// Update list with complete list of features. This is important because during the Configure phase, dependent features might configure other features, which should not be created as new instances.
|
|
_features = features.ToHashSet();
|
|
|
|
foreach (var feature in features)
|
|
{
|
|
feature.Configure();
|
|
feature.ConfigureHostedServices();
|
|
}
|
|
|
|
foreach (var hostedServiceDescriptor in _hostedServiceDescriptors.OrderBy(x => x.Order))
|
|
Services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IHostedService), hostedServiceDescriptor.HostedServiceType));
|
|
|
|
foreach (var feature in features)
|
|
feature.Apply();
|
|
}
|
|
} |