Async/await first CQRS+ES and DDD framework for .NET
OTHER License
Bot releases are hidden (Show)
Published by rasmus over 8 years ago
EventFlow.EventStores.MsSql
and EventFlow.ReadStores.MsSql
haveEventFlow.MsSql
. The embedded SQL scripts have been made idempotent makingConfigureElasticsearch
that takes multiple of URLs, SniffingConnectionPool
StaticConnectionPool
and with sniff life span of fivePublished by rasmus over 8 years ago
IAggregateRoot
has some breaking changes. If these methods aren'tAggregateRoot<,,>
will automatically handle it
CommitAsync
has an additional ISnapshotStore
parameter. If you don'tnull
LoadAsync
is a new method that lets the aggregate control how itsIAggregateStore
is introduced, which provides a cleaner interfaceUpdateAsync
which allows easy updates to aggregate roots without the needLoadAsync
UpdateAsync
StoreAsync
IEventStore
now supports loading events from a specific version usingLoadEventsAsync
that takes a fromEventSequenceNumber
IMsSqlDatabaseMigrator
now has a overloaded method namedMigrateDatabaseUsingScripts
that takes an IEnumerable<SqlScript>
IEventStore
has beenIAggregateStore
. The methods will beLoadAggregateAsync
LoadAggregate
Published by rasmus over 8 years ago
OptimisticConcurrencyRetryStrategy
now correctly onlyOptimisticConcurrencyException
should be retried. BeforeIOptimisticConcurrencyRetryStrategy
that has the old behaviorOptimisticConcurrencyRetryStrategy
has a off-by-one error that causedabstract ICommandHandler<,,,>
from being registered inEventFlowOptionsCommandHandlerExtensions.AddCommandHandlers(...)
abstract IEventUpgrader<,>
from being registered inEventFlowOptionsEventUpgradersExtensions.AddEventUpgraders(...)
abstract IMetadataProvider
from being registered inEventFlowOptionsMetadataProvidersExtensions.AddMetadataProviders(...)
abstract IQueryHandler<,>
from being registered inEventFlowOptionsQueriesExtensions.AddQueryHandlers(...)
abstract ISubscribeSynchronousTo<,,>
from being registered inEventFlowOptionsSubscriberExtensions.AddSubscribers(...)
Published by rasmus over 8 years ago
IJobDisplayNameBuilder
. The default implementation uses job descriptionPublished by rasmus over 8 years ago
MssqlMigrationException
to SqlMigrationException
SqlErrorRetryStrategy
to MsSqlErrorRetryStrategy
Dapper
is no longer IL merged with the packageEventFlow.MsSql
but is now listed as a NuGet dependency. The currentv1.42
EventFlow.SQLite
that adds event storeEventFlow.Sql
as shared package forIMsSqlConfiguration.SetTransientRetryDelay
. ThePublished by rasmus over 8 years ago
Fixed: Deadlock in AsyncHelper
if e.g. an exception caused no async
tasks
to be scheduled. The AsyncHelper
is used by EventFlow to expose non-async
methods to developers and provide the means to call async
methods from
a synchronous context without causing a deadlock. There's no change to any of
the async
methods.
The AsyncHelper
is used in the following methods.
ICommandBus.Publish
IEventStore.LoadEvents
IEventStore.LoadAggregate
IEventStore.LoadAllEvents
IJobRunner.Execute
IReadModelPopulator.Populate
IReadModelPopulator.Purge
IQueryProcessor.Process
Published by rasmus over 8 years ago
EventStore.Client
v3.4.0 (up from v3.0.2)Hangfire.Core
v1.5.3 (up from v1.4.6)RabbitMQ.Client
v3.6.0 (up from v3.5.4)EventStore.Client
that caused it to throwWrongExpectedVersionException
when committing aggregates multiple timesEventFlow.RabbitMQ
EventFlow.EventStores.EventStore
dbup
to v3.3.0 (up from v3.2.1)Published by rasmus almost 9 years ago
Id
in MSSQL read models.MsSqlReadModelIgnoreColumn
attributeMethodInfo.Invoke
to call methods on reflectedArgumentException
if EventFlow hasIReadModelFactory<>.CreateAsync(...)
is now correctly used inPublished by rasmus almost 9 years ago
IReadModelFactory<>
that can bootstrap that read modelIMssqlReadModel
, only the empty IReadModel
MsSqlReadModelIdentityColumn
attribute to markMsSqlReadModelVersionColumn
to mark the version column.
string AggregateId
DateTimeOffset CreateTime
DateTimeOffset UpdatedTime
int LastAggregateSequenceNumber
IMssqlReadModel
and MssqlReadModel
. Developers should insteadMsSqlReadModelIdentityColumn
and MsSqlReadModelVersionColumn
IMssqlReadModel
, but it will beUseElasticsearchReadModel<TReadModel, TReadModelLocator>()
Published by rasmus almost 9 years ago
Identity<>.NewComb()
that creates sequential unique IDs which canIReadModelContext.Resolver
to allow read models to fetchPrettyPrint()
type extension method, mostly used for verboseKeyValuePair<Boolean,Int64>
instead of merely KeyValuePair'2
, making logPublished by rasmus almost 9 years ago
Entity<T>
now inherits from ValueObject
but uses only the Id
GetEqualityComponents()
if you haveEntity<T>
will now throw an ArgumentNullException
if the id
null
ISpecification<T>.WhyIsNotStatisfiedBy
to WhyIsNotSatisfiedBy
andSpecification<T>.IsNotStatisfiedBecause
to IsNotSatisfiedBecause
EventFlow.ReadStores.Elasticsearch
Published by rasmus almost 9 years ago
AddDefaults
now also adds the job type definition to theIJobsDefinitonService
ISpecification<T>
, an easy-to-use Specificaion<T>
and a set of extensionIEventDefinitionService
, ICommandDefinitonService
andIJobsDefinitonService
now longer throw an exception if an existingAddEvents(...)
, AddCommand(...)
AddJobs(...)
no longer throws an exceptionDomainError.With(...)
no longer executes string.format
if onlyPublished by rasmus about 9 years ago
[STORE PATH]\[AGGREGATE NAME]\[AGGREGATE ID]\[SEQUENCE].json
, but[STORE PATH]\[AGGREGATE ID]\[SEQUENCE].json
. Thus if you areIFilesEventLocator
andIEventStore
IEventPersistence
. IEventStore
has the same interface beforeIEventPersistence
IEventPersistence
IEntity
, IEntity<>
and an optional Entity<>
that developersPublished by rasmus about 9 years ago
EventFlow.Autofac
causes an exception with theThe type 'EventFlow.Configuration.Registrations.AutofacStartable' is not assignable to service 'Autofac.IStartable
during EventFlow setupPublished by rasmus about 9 years ago
HasRegistrationFor<>
and GetRegisteredServices()
IServiceRegistration
and added them to IResolver
instead. TheIServiceRegistration.RegisterIfNotRegistered(...)
, usekeepDefault = true
on the other Register(...)
methods insteadCreateResolver()
(or CreateContainer()
if using the EventFlow.Autofac
IBootstrap
interface that you can register. It has aBootAsync(...)
method that will be called as soon as the IoCIStartable
of Autofac)ICommand<,>
interface to abstract Command<,>
class inEventFlow.Commands
.Published by rasmus about 9 years ago
UseHangfireJobScheduler()
and marked UseHandfireJobScheduler()
Published by rasmus about 9 years ago
EventFlowOptions
extensions are now IEventFlowOptions
EventFlowOptions
implements this interface. If you have madeIModule
and register these by callingEventFlowOptions.RegisterModule(...)
EventFlow.Hangfire
NuGetCommandPublishMiddleware
middleware that can/commands/ping/1
in which ping
is the command name and 1
itsICommand<TAggregate,TIdentity,TSourceIdentity>
ICommand.SourceId
. Using theICommand<TAggregate,TIdentity>
(or Command<TAggregate,TIdentity>)ICommand.SourceId
beingISourceId
AddDefaults(...)
now also adds the command type definition to theICommandDefinitonService
Published by rasmus about 9 years ago
EventFlowOptions.AddDefaults(...)
now also adds query handlersPredicate<Type>
to the following option extensionAssembly
: AddAggregateRoots(...)
,AddCommandHandlers(...)
, AddDefaults(...)
, AddEventUpgraders(...)
,AddEvents(...)
, AddMetadataProviders(...)
, AddQueryHandlers(...)
andAddSubscribers(...)
EventFlowOptions.AddAggregateRoots(...)
now prevents abstractIEnumerable<Type>
event A -> subscriber -> command -> aggregate -> event B
,event B
and thenevent A
Published by rasmus about 9 years ago
Aggregate
removed from theiraggregate_name
(orMetadataKeys.AggregateName
). If you are dependent on the previous naming,AggregateName
attribute and apply it to your aggregatesIdentity<>
and IIdentity
from the EventFlow.Aggregates
EventFlow.Core
as the identities are not specific for aggregatesICommand.Id
is renamed to ICommand.AggregateId
to make "room"ICommand.SourceId
property. If commands are serialized, thenCommand<,>
is used, make sure to use the correct protected constructorIEventStore.StoreAsync(...)
now requires an additionalISourceId
argument. To create a random one, use SourceId.New
, but itICommand.SourceId
, which contains the ID of the source. TheCommand<,>
) will be a newCommandId
each time the a Command<,>
instance is created. You can passDistinctCommand
, enabling commands with the same state to have theSourceId
ISourceId
. Read theAggregateName
. The name can be accessed using the new IAggregateRoot.Name
Identity<>.NewDeterministic(Guid, string)
enabling creation ofsource_id
(MetadataKeys.SourceId
) containingevent_id
(MetadataKeys.EventId
) containing aIdentity<>.With(string)
now throws an ArgumentException
instead ofTargetInvocationException
when passed an invalid identityApply
methods once, insteadPublished by rasmus about 9 years ago
EventFlowOptions.AddDefaults(...)
now also adds eventEventFlow.RabbitMQ
which enables domain events to beISubscribeSynchronousToAll
. ServicesAddSubscribers(...)
or AddDefaults(...)
extension to EventFlowOptions
EventFlowOptions.UseAutofacAggregateRootFactory(...)
to use anEventFlowOptions.UseResolverAggregateRootFactory()
to use theUseAutofacAggregateRootFactory(...)
but for when using the internal IoCEventFlowOptions.AddAggregateRoots(...)
to register aggregate rootIServiceRegistration.RegisterType(...)
to register services by