elsa-core/src/common/Elsa.Features/Implementations/Module.cs
Sipke Schoorstra e6536636d7
Additional samples + fixes and improvements (#3574)
* 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
2022-12-30 13:11:29 +01:00

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();
}
}