mirror of
https://github.com/ditkrg/DIT.Workflower.git
synced 2026-01-22 22:06:42 +00:00
BREAKING: Use Scoped services for the IWorkflow in DI.
This commit is contained in:
parent
f6f93d4744
commit
6de3d47516
@ -17,7 +17,7 @@ public interface IWorkflow<TState, TCommand, TContext>
|
|||||||
/// <typeparam name="TCommand">The type of the workflow command.</typeparam>
|
/// <typeparam name="TCommand">The type of the workflow command.</typeparam>
|
||||||
/// <typeparam name="TContext">The type of the workflow context.</typeparam>
|
/// <typeparam name="TContext">The type of the workflow context.</typeparam>
|
||||||
/// <returns>A list of transition definitions.</returns>
|
/// <returns>A list of transition definitions.</returns>
|
||||||
public List<TransitionDefinition<TState, TCommand, TContext>> GetAllTransitionDefinitions();
|
public List<TransitionDefinition<TState, TCommand, ContextWrapper<TContext>>> GetAllTransitionDefinitions();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a list of allowed transitions without any condition checks.
|
/// Gets a list of allowed transitions without any condition checks.
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
namespace DIT.Workflower.DependencyInjection;
|
namespace DIT.Workflower.DependencyInjection;
|
||||||
|
|
||||||
public record DIContextWrapper<TContext>(TContext Context, IServiceProvider ServiceProvider);
|
public record ContextWrapper<TContext>(TContext Context, IServiceProvider ServiceProvider);
|
||||||
|
|||||||
@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
<!-- Deterministic Builds -->
|
<!-- Deterministic Builds -->
|
||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
|
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup >
|
<ItemGroup >
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0" Condition="'$(TargetFramework)' == 'net6.0'" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" Condition="'$(TargetFramework)' == 'net6.0'" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0" Condition="'$(TargetFramework)' == 'net7.0'" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" Condition="'$(TargetFramework)' == 'net7.0'" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0" Condition="'$(TargetFramework)' == 'net8.0'" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" Condition="'$(TargetFramework)' == 'net8.0'" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace DIT.Workflower.DependencyInjection.Extensions;
|
namespace DIT.Workflower.DependencyInjection.Extensions;
|
||||||
|
|
||||||
public static class IServiceCollectionExtensions
|
public static class ServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
|
public static ITransitionStart<TState, TCommand, ContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(
|
||||||
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, in int version = 1)
|
this IServiceCollection services, in int version = 1)
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
@ -13,25 +13,27 @@ public static class IServiceCollectionExtensions
|
|||||||
return AddWorkflowDefinition<TState, TCommand, TContext>(services, id, version);
|
return AddWorkflowDefinition<TState, TCommand, TContext>(services, id, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, in string id)
|
public static ITransitionStart<TState, TCommand, ContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(
|
||||||
|
this IServiceCollection services, in string id)
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
return AddWorkflowDefinition<TState, TCommand, TContext>(services, id, version: 1);
|
return AddWorkflowDefinition<TState, TCommand, TContext>(services, id, version: 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ITransitionStart<TState, TCommand, DIContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(this IServiceCollection services, string id, int version)
|
public static ITransitionStart<TState, TCommand, ContextWrapper<TContext>> AddWorkflowDefinition<TState, TCommand, TContext>(
|
||||||
|
this IServiceCollection services, string id, int version)
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
var builder = WorkflowDefinitionBuilder<TState, TCommand, DIContextWrapper<TContext>>.Create();
|
var builder = WorkflowDefinitionBuilder<TState, TCommand, ContextWrapper<TContext>>.Create();
|
||||||
|
var definition = (WorkflowDefinitionBuilder<TState, TCommand, ContextWrapper<TContext>>)builder;
|
||||||
|
|
||||||
services.TryAddSingleton<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>, DefaultWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
|
services.TryAddScoped<IWorkflowFactory<TState, TCommand, TContext>, DefaultWorkflowFactory<TState, TCommand, TContext>>();
|
||||||
|
|
||||||
services.AddSingleton<IWorkflow<TState, TCommand, DIContextWrapper<TContext>>, WorkflowDefinitionWrapper<TState, TCommand, DIContextWrapper<TContext>>>(sp =>
|
services.AddScoped<IWorkflow<TState, TCommand, TContext>, WorkflowDefinitionWrapper<TState, TCommand, TContext>>(sp =>
|
||||||
{
|
{
|
||||||
var definition = (WorkflowDefinitionBuilder<TState, TCommand, DIContextWrapper<TContext>>)builder;
|
var wrapper = new WorkflowDefinitionWrapper<TState, TCommand, TContext>(definition, sp, id, version);
|
||||||
var wrapper = new WorkflowDefinitionWrapper<TState, TCommand, DIContextWrapper<TContext>>(definition, id, version);
|
|
||||||
return wrapper;
|
return wrapper;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +1,22 @@
|
|||||||
namespace DIT.Workflower.DependencyInjection.Extensions;
|
namespace DIT.Workflower.DependencyInjection.Extensions;
|
||||||
|
|
||||||
public static class IServiceProviderExtensions
|
public static class ServiceProviderExtensions
|
||||||
{
|
{
|
||||||
public static IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>> GetRequiredWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
|
public static IWorkflowFactory<TState, TCommand, TContext> GetRequiredWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
return sp.GetRequiredService<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
|
return sp.GetRequiredService<IWorkflowFactory<TState, TCommand, TContext>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>? GetWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
|
public static IWorkflowFactory<TState, TCommand, TContext>? GetWorkflowFactory<TState, TCommand, TContext>(this IServiceProvider sp)
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
return sp.GetService<IWorkflowFactory<TState, TCommand, DIContextWrapper<TContext>>>();
|
return sp.GetService<IWorkflowFactory<TState, TCommand, TContext>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWorkflow<TState, TCommand, DIContextWrapper<TContext>> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, int version = 1)
|
public static IWorkflow<TState, TCommand, TContext> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, int version = 1)
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
@ -24,7 +24,7 @@ public static class IServiceProviderExtensions
|
|||||||
return factory.CreateWorkflow(version);
|
return factory.CreateWorkflow(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWorkflow<TState, TCommand, DIContextWrapper<TContext>> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, string id, int version = 1)
|
public static IWorkflow<TState, TCommand, TContext> CreateWorkflow<TState, TCommand, TContext>(this IServiceProvider sp, string id, int version = 1)
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,21 +1,56 @@
|
|||||||
namespace DIT.Workflower.DependencyInjection;
|
namespace DIT.Workflower.DependencyInjection;
|
||||||
|
|
||||||
public record WorkflowDefinitionWrapper<TState, TCommand, TContext> : WorkflowDefinition<TState, TCommand, TContext>, IWorkflow<TState, TCommand, TContext>
|
public sealed class WorkflowDefinitionWrapper<TState, TCommand, TContext> : IWorkflow<TState, TCommand, TContext>
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly WorkflowDefinition<TState, TCommand, ContextWrapper<TContext>> _definition;
|
||||||
|
|
||||||
public string Id { get; }
|
public string Id { get; }
|
||||||
|
|
||||||
public int Version { get; }
|
public int Version { get; }
|
||||||
|
public List<TransitionDefinition<TState, TCommand, ContextWrapper<TContext>>> GetAllTransitionDefinitions()
|
||||||
public WorkflowDefinitionWrapper(WorkflowDefinitionBuilder<TState, TCommand, TContext> builder, string id, int version)
|
|
||||||
: base(builder.Transitions)
|
|
||||||
{
|
{
|
||||||
|
return _definition.GetAllTransitionDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Transition<TState, TCommand>> GetAllowedTransitions(TState from)
|
||||||
|
{
|
||||||
|
return _definition.GetAllowedTransitions(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Transition<TState, TCommand>> GetAllowedTransitions(TContext context, TState from)
|
||||||
|
{
|
||||||
|
return _definition.GetAllowedTransitions(GetContextWrapper(context), from);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Transition<TState, TCommand>> GetAllowedTransitions(ListTransitionsRequest<TState, TCommand, TContext> request)
|
||||||
|
{
|
||||||
|
var wrappedRequest = new ListTransitionsRequest<TState, TCommand, ContextWrapper<TContext>>
|
||||||
|
{
|
||||||
|
From = request.From,
|
||||||
|
To = request.To,
|
||||||
|
Command = request.Command,
|
||||||
|
Context = request.Context is null ? null : GetContextWrapper(request.Context)
|
||||||
|
};
|
||||||
|
|
||||||
|
return _definition.GetAllowedTransitions(wrappedRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkflowDefinitionWrapper(WorkflowDefinitionBuilder<TState, TCommand, ContextWrapper<TContext>> builder, IServiceProvider serviceProvider, string id, int version)
|
||||||
|
{
|
||||||
|
_definition = builder.Build();
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
|
||||||
Id = id;
|
Id = id;
|
||||||
Version = version;
|
Version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ContextWrapper<TContext> GetContextWrapper(in TContext context)
|
||||||
|
=> new(context, _serviceProvider);
|
||||||
|
|
||||||
public static string GetDefaultId()
|
public static string GetDefaultId()
|
||||||
{
|
{
|
||||||
var ctxType = typeof(TContext);
|
var ctxType = typeof(TContext);
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<!-- Deterministic Builds -->
|
<!-- Deterministic Builds -->
|
||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
|
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace DIT.Workflower;
|
namespace DIT.Workflower;
|
||||||
|
|
||||||
public record WorkflowDefinition<TState, TCommand, TContext>
|
public class WorkflowDefinition<TState, TCommand, TContext>
|
||||||
where TState : struct
|
where TState : struct
|
||||||
where TCommand : struct
|
where TCommand : struct
|
||||||
{
|
{
|
||||||
@ -41,24 +41,24 @@ public record WorkflowDefinition<TState, TCommand, TContext>
|
|||||||
{
|
{
|
||||||
var query = _transitions.AsQueryable();
|
var query = _transitions.AsQueryable();
|
||||||
|
|
||||||
if (request.From is TState from)
|
if (request.From is { } from)
|
||||||
{
|
{
|
||||||
query = query.Where(doc => doc.From.Equals(from));
|
query = query.Where(doc => doc.From.Equals(from));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.To is TState to)
|
if (request.To is { } to)
|
||||||
{
|
{
|
||||||
query = query.Where(doc => doc.To.Equals(to));
|
query = query.Where(doc => doc.To.Equals(to));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.Command is TCommand command)
|
if (request.Command is { } command)
|
||||||
{
|
{
|
||||||
query = query.Where(doc => doc.Command.Equals(command));
|
query = query.Where(doc => doc.Command.Equals(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.Context is not null)
|
if (request.Context is not null)
|
||||||
{
|
{
|
||||||
query = query.Where(doc => doc.Conditions == null || !doc.Conditions.Any(cond => !cond(request.Context)));
|
query = query.Where(doc => doc.Conditions == null || doc.Conditions.All(cond => cond(request.Context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return query.Select(x => x.ToTransition());
|
return query.Select(x => x.ToTransition());
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using DIT.Workflower.DependencyInjection.Abstractions;
|
using DIT.Workflower.DependencyInjection.Extensions;
|
||||||
using DIT.Workflower.DependencyInjection.Extensions;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace DIT.Workflower.Tests.DependencyInjection;
|
namespace DIT.Workflower.Tests.DependencyInjection;
|
||||||
@ -49,7 +48,6 @@ public class DependencyInjectionTests
|
|||||||
Assert.NotNull(v1);
|
Assert.NotNull(v1);
|
||||||
Assert.NotNull(v2);
|
Assert.NotNull(v2);
|
||||||
|
|
||||||
|
|
||||||
Assert.Single(v1!.GetAllowedTransitions(PhoneState.Idle));
|
Assert.Single(v1!.GetAllowedTransitions(PhoneState.Idle));
|
||||||
Assert.Single(v2!.GetAllowedTransitions(PhoneState.Idle));
|
Assert.Single(v2!.GetAllowedTransitions(PhoneState.Idle));
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user