using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Elsa.Builders; using Elsa.Caching; using Elsa.Dispatch; using Elsa.DistributedLock; using Elsa.DistributedLocking; using Elsa.Models; using Elsa.Persistence; using Elsa.Persistence.InMemory; using Elsa.Serialization; using Elsa.Services; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Rebus.DataBus.InMem; using Rebus.Persistence.InMem; using Rebus.Transport.InMem; using Storage.Net; using Storage.Net.Blobs; namespace Elsa { public class ElsaOptions { private readonly IList _messageTypes = new List(); public ElsaOptions(IServiceCollection services) { Services = services; WorkflowDefinitionStoreFactory = sp => ActivatorUtilities.CreateInstance(sp); WorkflowInstanceStoreFactory = sp => ActivatorUtilities.CreateInstance(sp); WorkflowExecutionLogStoreFactory = sp => ActivatorUtilities.CreateInstance(sp); WorkflowTriggerStoreFactory = sp => ActivatorUtilities.CreateInstance(sp); WorkflowDefinitionDispatcherFactory = sp => ActivatorUtilities.CreateInstance(sp); WorkflowInstanceDispatcherFactory = sp => ActivatorUtilities.CreateInstance(sp); CorrelatingWorkflowDispatcherFactory = sp => ActivatorUtilities.CreateInstance(sp); StorageFactory = sp => Storage.Net.StorageFactory.Blobs.InMemory(); DistributedLockProviderFactory = sp => new DefaultLockProvider(); SignalFactory = sp => new Signal(); JsonSerializerConfigurer = (sp, serializer) => { }; 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: ServiceLifetime.Singleton); }; services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddMemoryCache(); ConfigureServiceBusEndpoint = ConfigureInMemoryServiceBusEndpoint; CreateJsonSerializer = sp => { var serializer = DefaultContentSerializer.CreateDefaultJsonSerializer(); JsonSerializerConfigurer(sp, serializer); return serializer; }; } public IServiceCollection Services { get; } public ServiceFactory ActivityFactory { get; } = new(); public ServiceFactory WorkflowFactory { get; } = new(); public IEnumerable ActivityTypes => ActivityFactory.Types; public IEnumerable WorkflowTypes => WorkflowFactory.Types; public IEnumerable MessageTypes => _messageTypes.ToList(); public ServiceBusOptions ServiceBusOptions { get; } = new(); internal Func StorageFactory { get; set; } internal Func WorkflowDefinitionStoreFactory { get; set; } internal Func WorkflowInstanceStoreFactory { get; set; } internal Func WorkflowExecutionLogStoreFactory { get; set; } internal Func WorkflowTriggerStoreFactory { get; set; } internal Func DistributedLockProviderFactory { get; private set; } internal Func SignalFactory { get; private set; } internal Func CreateJsonSerializer { get; private set; } internal Action JsonSerializerConfigurer { get; private set; } internal Func WorkflowDefinitionDispatcherFactory { get; set; } internal Func WorkflowInstanceDispatcherFactory { get; set; } internal Func CorrelatingWorkflowDispatcherFactory { get; set; } internal Action AddAutoMapper { get; private set; } internal Action ConfigureServiceBusEndpoint { get; private set; } internal bool WithCoreActivities { get; private set; } = true; public ElsaOptions NoCoreActivities() { WithCoreActivities = false; return this; } public ElsaOptions AddActivity() where T : IActivity => AddActivity(typeof(T)); public ElsaOptions AddActivity(Type activityType) { Services.AddTransient(activityType); Services.AddTransient(sp => (IActivity) sp.GetRequiredService(activityType)); ActivityFactory.Add(activityType, provider => (IActivity)ActivatorUtilities.GetServiceOrCreateInstance(provider, activityType)); return this; } public ElsaOptions AddActivitiesFrom(Assembly assembly) => AddActivitiesFrom(new[] { assembly }); public ElsaOptions AddActivitiesFrom(params Assembly[] assemblies) => AddActivitiesFrom((IEnumerable) assemblies); public ElsaOptions AddActivitiesFrom(params Type[] assemblyMarkerTypes) => AddActivitiesFrom(assemblyMarkerTypes.Select(x => x.Assembly).Distinct()); public ElsaOptions AddActivitiesFrom() where TMarker:class => AddActivitiesFrom(typeof(TMarker)); public ElsaOptions AddActivitiesFrom(IEnumerable assemblies) { var types = assemblies.SelectMany(x => x.GetAllWithInterface()); foreach (var type in types) AddActivity(type); return this; } public ElsaOptions RemoveActivity() where T : IActivity => RemoveActivity(typeof(T)); public ElsaOptions RemoveActivity(Type activityType) { ActivityFactory.Remove(activityType); return this; } public ElsaOptions AddWorkflow() where T : IWorkflow => AddWorkflow(typeof(T)); public ElsaOptions AddWorkflow(Type workflowType) { Services.AddSingleton(workflowType); Services.AddSingleton(sp => (IWorkflow)sp.GetRequiredService(workflowType)); WorkflowFactory.Add(workflowType, provider => (IWorkflow)ActivatorUtilities.GetServiceOrCreateInstance(provider, workflowType)); return this; } public ElsaOptions AddWorkflow(IWorkflow workflow) { Services.AddSingleton(workflow); WorkflowFactory.Add(workflow.GetType(), workflow); return this; } public ElsaOptions AddWorkflow(Func workflow) where T: class, IWorkflow { Services.AddSingleton(workflow); Services.AddSingleton(sp => sp.GetRequiredService()); WorkflowFactory.Add(typeof(T), sp => sp.GetRequiredService()); return this; } public ElsaOptions AddWorkflowsFrom() => AddWorkflowsFrom(typeof(T).Assembly); public ElsaOptions AddWorkflowsFrom(Assembly assembly) { var types = assembly.GetAllWithInterface(); foreach (var type in types) AddWorkflow(type); return this; } public ElsaOptions RemoveWorkflow() where T : IWorkflow => RemoveWorkflow(typeof(T)); public ElsaOptions RemoveWorkflow(Type workflowType) { WorkflowFactory.Remove(workflowType); return this; } public ElsaOptions AddMessageType(Type messageType) { _messageTypes.Add(messageType); return this; } public ElsaOptions AddMessageType() => AddMessageType(typeof(T)); public ElsaOptions UseDistributedLockProvider(Func factory) { DistributedLockProviderFactory = factory; return this; } public ElsaOptions UseSignal(Func factory) { SignalFactory = factory; return this; } public ElsaOptions UseStorage(Func factory) => UseStorage(_ => factory()); public ElsaOptions UseStorage(Func factory) { StorageFactory = factory; return this; } public ElsaOptions UseWorkflowDefinitionStore(Func factory) { WorkflowDefinitionStoreFactory = factory; return this; } public ElsaOptions UseWorkflowInstanceStore(Func factory) { WorkflowInstanceStoreFactory = factory; return this; } public ElsaOptions UseWorkflowExecutionLogStore(Func factory) { WorkflowExecutionLogStoreFactory = factory; return this; } public ElsaOptions UseWorkflowTriggerStore(Func factory) { WorkflowTriggerStoreFactory = factory; return this; } public ElsaOptions UseAutoMapper(Action addAutoMapper) { AddAutoMapper = addAutoMapper; return this; } public ElsaOptions UseJsonSerializer(Func factory) { CreateJsonSerializer = factory; return this; } public ElsaOptions ConfigureJsonSerializer(Action configure) { JsonSerializerConfigurer = configure; return this; } public ElsaOptions UseServiceBus(Action setup) { ConfigureServiceBusEndpoint = setup; return this; } private void ConfigureInMemoryServiceBusEndpoint(ServiceBusEndpointConfigurationContext context) { var serviceProvider = context.ServiceProvider; var transport = serviceProvider.GetService(); var store = serviceProvider.GetRequiredService(); var queueName = context.QueueName; context.Configurer .Subscriptions(s => s.StoreInMemory(store)) .Transport(t => t.UseInMemoryTransport(transport, queueName)); } } }