Add helper functions to create workflows, access service provider in When clause

This commit is contained in:
Shkar T. Noori 2022-07-24 08:38:39 +00:00
parent c0691416a8
commit 86c2f3e9c4
No known key found for this signature in database
GPG Key ID: E7AD76088FB6FE02
5 changed files with 60 additions and 14 deletions

View File

@ -0,0 +1,3 @@
namespace DIT.Workflower.DependencyInjection;
public record DIContextWrapper<TContext>(TContext Context, IServiceProvider ServiceProvider);

View File

@ -5,7 +5,7 @@ namespace DIT.Workflower.DependencyInjection.Extensions;
public static class IServiceCollectionExtensions
{
public static ITransitionStart<TState, TCommand, TContext> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, in int version = 1)
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, in int version = 1)
where TState : struct
where TCommand : struct
{
@ -13,25 +13,25 @@ public static class IServiceCollectionExtensions
return AddWorkflowDefinition<TState, TCommand, TContext>(services, id, version);
}
public static ITransitionStart<TState, TCommand, TContext> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, in string id)
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, in string id)
where TState : struct
where TCommand : struct
{
return AddWorkflowDefinition<TState, TCommand, TContext>(services, id, version: 1);
}
public static ITransitionStart<TState, TCommand, TContext> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, string id, int version)
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, string id, int version)
where TState : struct
where TCommand : struct
{
var builder = WorkflowDefinitionBuilder<TState, TCommand, TContext>.Create();
var builder = WorkflowDefinitionBuilder<TState, TCommand, DIContextWrapper<TContext>>.Create();
services.TryAddSingleton<IWorkflowFactory<TState, TCommand, TContext>, DefaultWorkflowFactory<TState, TCommand, TContext>>();
services.TryAddSingleton<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>, DefaultWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
services.AddSingleton<IWorkflow<TState, TCommand, TContext>, WorkflowDefinitionWrapper<TState, TCommand, TContext>>(sp =>
services.AddSingleton<IWorkflow<TState, TCommand, DIContextWrapper<TContext>>, WorkflowDefinitionWrapper<TState, TCommand, DIContextWrapper<TContext>>>(sp =>
{
var definition = (WorkflowDefinitionBuilder<TState, TCommand, TContext>)builder;
var wrapper = new WorkflowDefinitionWrapper<TState, TCommand, TContext>(definition, id, version);
var definition = (WorkflowDefinitionBuilder<TState, TCommand, DIContextWrapper<TContext>>)builder;
var wrapper = new WorkflowDefinitionWrapper<TState, TCommand, DIContextWrapper<TContext>>(definition, id, version);
return wrapper;
});

View File

@ -0,0 +1,35 @@
namespace DIT.Workflower.DependencyInjection.Extensions;
public static class IServiceProviderExtensions
{
public static IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>> GetRequiredWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
where TState : struct
where TCommand : struct
{
return sp.GetRequiredService<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
}
public static IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>? GetWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
where TState : struct
where TCommand : struct
{
return sp.GetService<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
}
public static IWorkflow<TState, TCommand, DIContextWrapper<TContext>> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, int version = 1)
where TState : struct
where TCommand : struct
{
var factory = GetRequiredWorkflowFactory<TState, TCommand, TContext>(sp);
return factory.CreateWorkflow(version);
}
public static IWorkflow<TState, TCommand, DIContextWrapper<TContext>> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, string id, int version = 1)
where TState : struct
where TCommand : struct
{
var factory = GetRequiredWorkflowFactory<TState, TCommand, TContext>(sp);
return factory.CreateWorkflow(id, version);
}
}

View File

@ -18,7 +18,13 @@ public record WorkflowDefinitionWrapper<TState, TCommand, TContext> : WorkflowDe
public static string GetDefaultId()
{
return $"{typeof(TState).Name}_{typeof(TCommand).Name}_{typeof(TContext).Name}";
var ctxType = typeof(TContext);
var ctxName = ctxType.Name;
if (ctxType.IsGenericType)
ctxName = string.Join("+", typeof(TContext).GetGenericArguments().Select(x => x.Name));
return $"{typeof(TState).Name}_{typeof(TCommand).Name}_{ctxName}";
}
}

View File

@ -40,8 +40,7 @@ public class DependencyInjectionTests
var sp = sc.BuildServiceProvider();
var workflowFactory = sp.GetRequiredService<IWorkflowFactory<PhoneState, PhoneCommand, PhoneCall>>();
var workflowFactory = sp.GetRequiredWorkflowFactory<PhoneState, PhoneCommand, PhoneCall>();
var v1 = workflowFactory.CreateWorkflow(id);
var v2 = workflowFactory.CreateWorkflow(id, version: 2);
@ -62,6 +61,7 @@ public class DependencyInjectionTests
public void IdGenerationTest()
{
var sc = new ServiceCollection();
const string expectedId = "PhoneState_PhoneCommand_PhoneCall";
sc.AddWorkflowDefinition<PhoneState, PhoneCommand, PhoneCall>(version: 1)
.From(PhoneState.Idle)
@ -69,10 +69,12 @@ public class DependencyInjectionTests
.To(PhoneState.Ringing);
var sp = sc.BuildServiceProvider();
var workflowFactory = sp.GetRequiredService<IWorkflowFactory<PhoneState, PhoneCommand, PhoneCall>>();
var workflowFactory = sp.GetRequiredWorkflowFactory<PhoneState, PhoneCommand, PhoneCall>();
var workflow = workflowFactory.CreateWorkflow();
Assert.Equal("PhoneState_PhoneCommand_PhoneCall", workflow.Id);
Assert.Equal(expectedId, workflow.Id);
Assert.Equal(expectedId, sp.CreateWorkflow<PhoneState, PhoneCommand, PhoneCall>().Id);
Assert.Equal(expectedId, sp.CreateWorkflow<PhoneState, PhoneCommand, PhoneCall>(expectedId).Id);
}
[Fact]
@ -86,7 +88,7 @@ public class DependencyInjectionTests
.To(PhoneState.Ringing);
var sp = sc.BuildServiceProvider();
var workflowFactory = sp.GetRequiredService<IWorkflowFactory<PhoneState, PhoneCommand, PhoneCall>>();
var workflowFactory = sp.GetRequiredWorkflowFactory<PhoneState, PhoneCommand, PhoneCall>();
Assert.Throws<KeyNotFoundException>(() => workflowFactory.CreateWorkflow("unknown"));
}