using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Elsa.Attributes; using Elsa.Builders; using Elsa.Caching; using Elsa.Persistence; using Elsa.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Newtonsoft.Json; using Rebus.DataBus.InMem; using Rebus.Persistence.InMem; using Rebus.Transport.InMem; using Storage.Net.Blobs; namespace Elsa { public class ElsaOptionsBuilder { public ElsaOptionsBuilder(IServiceCollection services) { ElsaOptions = new ElsaOptions(); Services = services; AddAutoMapper = () => { // The profiles are added to AddWorkflowsCore so that they are not forgotten in case the AddAutoMapper function(option) is overridden. services.AddAutoMapper(Enumerable.Empty(), ServiceLifetime.Singleton); }; services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddMemoryCache(); services.AddSingleton(); DistributedLockingOptionsBuilder = new DistributedLockingOptionsBuilder(this); } public ElsaOptions ElsaOptions { get; } public IServiceCollection Services { get; } public DistributedLockingOptionsBuilder DistributedLockingOptionsBuilder { get; } internal Action AddAutoMapper { get; private set; } internal bool WithCoreActivities { get; set; } = true; public ElsaOptionsBuilder NoCoreActivities() { WithCoreActivities = false; return this; } public ElsaOptionsBuilder WithContainerName(string name) { ElsaOptions.ContainerName = name; return this; } public ElsaOptionsBuilder AddFeatures(IEnumerable assemblies, IEnumerable features) { foreach (Assembly assembly in assemblies) { foreach (Type type in assembly.GetTypes()) { var attributes = type.GetCustomAttributes(typeof(FeatureAttribute), true); foreach (Attribute attribute in attributes) { if (!features.Contains(((FeatureAttribute)attribute).FeatureName)) continue; MethodInfo methodInfo = type.GetMethod("ConfigureElsa"); if (methodInfo != null) { object[] parametersArray = new object[] { this }; object classInstance = Activator.CreateInstance(type, null); methodInfo.Invoke(classInstance, parametersArray); } } } } return this; } public ElsaOptionsBuilder AddActivity() where T : IActivity => AddActivity(typeof(T)); public ElsaOptionsBuilder AddActivity(Type activityType) { Services.AddTransient(activityType); Services.AddTransient(sp => (IActivity) sp.GetRequiredService(activityType)); ElsaOptions.ActivityFactory.Add(activityType, provider => (IActivity) ActivatorUtilities.GetServiceOrCreateInstance(provider, activityType)); return this; } public ElsaOptionsBuilder AddActivitiesFrom(Assembly assembly) => AddActivitiesFrom(new[] { assembly }); public ElsaOptionsBuilder AddActivitiesFrom(params Assembly[] assemblies) => AddActivitiesFrom((IEnumerable) assemblies); public ElsaOptionsBuilder AddActivitiesFrom(params Type[] assemblyMarkerTypes) => AddActivitiesFrom(assemblyMarkerTypes.Select(x => x.Assembly).Distinct()); public ElsaOptionsBuilder AddActivitiesFrom() where TMarker : class => AddActivitiesFrom(typeof(TMarker)); public ElsaOptionsBuilder AddActivitiesFrom(IEnumerable assemblies) { var types = assemblies.SelectMany(x => x.GetAllWithInterface()); foreach (var type in types) AddActivity(type); return this; } public ElsaOptionsBuilder RemoveActivity() where T : IActivity => RemoveActivity(typeof(T)); public ElsaOptionsBuilder RemoveActivity(Type activityType) { ElsaOptions.ActivityFactory.Remove(activityType); return this; } public ElsaOptionsBuilder AddWorkflow() where T : IWorkflow => AddWorkflow(typeof(T)); public ElsaOptionsBuilder AddWorkflow(Type workflowType) { var workflowFactory = ElsaOptions.WorkflowFactory; if (workflowFactory.Types.Contains(workflowType)) return this; Services.AddSingleton(workflowType); Services.AddSingleton(sp => (IWorkflow) sp.GetRequiredService(workflowType)); workflowFactory.Add(workflowType, provider => (IWorkflow) ActivatorUtilities.GetServiceOrCreateInstance(provider, workflowType)); return this; } public ElsaOptionsBuilder AddWorkflow(IWorkflow workflow) { Services.AddSingleton(workflow); ElsaOptions.WorkflowFactory.Add(workflow.GetType(), workflow); return this; } public ElsaOptionsBuilder AddWorkflow(Func workflow) where T : class, IWorkflow { Services.AddSingleton(workflow); Services.AddSingleton(sp => sp.GetRequiredService()); ElsaOptions.WorkflowFactory.Add(typeof(T), sp => sp.GetRequiredService()); return this; } public ElsaOptionsBuilder AddWorkflowsFrom() => AddWorkflowsFrom(typeof(T).Assembly); public ElsaOptionsBuilder AddWorkflowsFrom(Assembly assembly) { var types = assembly.GetAllWithInterface(); foreach (var type in types) AddWorkflow(type); return this; } public ElsaOptionsBuilder RemoveWorkflow() where T : IWorkflow => RemoveWorkflow(typeof(T)); public ElsaOptionsBuilder RemoveWorkflow(Type workflowType) { ElsaOptions.WorkflowFactory.Remove(workflowType); return this; } public ElsaOptionsBuilder AddCompetingMessageType(Type messageType) { ElsaOptions.CompetingMessageTypes.Add(messageType); return this; } public ElsaOptionsBuilder AddCompetingMessageType() => AddCompetingMessageType(typeof(T)); public ElsaOptionsBuilder AddPubSubMessageType(Type messageType) { ElsaOptions.PubSubMessageTypes.Add(messageType); return this; } public ElsaOptionsBuilder AddPubSubMessageType() => AddPubSubMessageType(typeof(T)); public ElsaOptionsBuilder ConfigureDistributedLockProvider(Action configureOptions) { configureOptions(DistributedLockingOptionsBuilder); return this; } public ElsaOptionsBuilder UseStorage(Func factory) => UseStorage(_ => factory()); public ElsaOptionsBuilder UseStorage(Func factory) { ElsaOptions.StorageFactory = factory; return this; } public ElsaOptionsBuilder UseWorkflowDefinitionStore(Func factory) { ElsaOptions.WorkflowDefinitionStoreFactory = factory; return this; } public ElsaOptionsBuilder UseWorkflowInstanceStore(Func factory) { ElsaOptions.WorkflowInstanceStoreFactory = factory; return this; } public ElsaOptionsBuilder UseWorkflowExecutionLogStore(Func factory) { ElsaOptions.WorkflowExecutionLogStoreFactory = factory; return this; } public ElsaOptionsBuilder UseWorkflowTriggerStore(Func factory) { ElsaOptions.WorkflowTriggerStoreFactory = factory; return this; } public ElsaOptionsBuilder UseAutoMapper(Action addAutoMapper) { AddAutoMapper = addAutoMapper; return this; } public ElsaOptionsBuilder UseJsonSerializer(Func factory) { ElsaOptions.CreateJsonSerializer = factory; return this; } public ElsaOptionsBuilder ConfigureJsonSerializer(Action configure) { ElsaOptions.JsonSerializerConfigurer = configure; return this; } public ElsaOptionsBuilder UseServiceBus(Action setup) { ElsaOptions.ConfigureServiceBusEndpoint = setup; return this; } } }