예제 #1
0
        public void UpdateToCurrent(IEventSource aggregate)
        {
            long start = aggregate.ExpectedVersion + 1;
            var  id    = aggregate.Id;

            if (start <= 0)
            {
                throw new InvalidOperationException("Cannot get version <= 0");
            }
            string streamName = _streamNameBuilder.GenerateForAggregate(aggregate.GetType(), id);

            StreamEventsSlice streamEventsSlice;

            do
            {
                streamEventsSlice = _streamStoreConnection.ReadStreamForward(streamName, start, ReadPageSize);
                if (streamEventsSlice is StreamNotFoundSlice)
                {
                    throw new AggregateNotFoundException(id, aggregate.GetType());
                }
                if (streamEventsSlice is StreamDeletedSlice)
                {
                    throw new AggregateDeletedException(id, aggregate.GetType());
                }
                start = streamEventsSlice.NextEventNumber;
                var events = streamEventsSlice.Events.Select(evt => _eventSerializer.Deserialize(evt)).ToArray();
                if (events.Any())
                {
                    aggregate.RestoreFromEvents(events);
                }
            }while (!streamEventsSlice.IsEndOfStream);
        }
예제 #2
0
        /// <summary>
        /// Hard delete the aggregate. This permanently deletes the aggregate's stream.
        /// </summary>
        /// <param name="aggregate">The aggregate to be deleted.</param>
        public void HardDelete(IEventSource aggregate)
        {
            var streamName      = _streamNameBuilder.GenerateForAggregate(aggregate.GetType(), aggregate.Id);
            var expectedVersion = aggregate.ExpectedVersion;

            _streamStoreConnection.HardDeleteStream(streamName, expectedVersion);
        }
예제 #3
0
        public void Save(IEventSource aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders)
        {
            var commitHeaders = new Dictionary <string, object>
            {
                { CommitIdHeader, commitId },
                { AggregateClrTypeHeader, aggregate.GetType().AssemblyQualifiedName }
            };

            updateHeaders(commitHeaders);

            var streamName      = _aggregateIdToStreamName(aggregate.GetType(), aggregate.Id);
            var newEvents       = aggregate.TakeEvents().ToList();
            var expectedVersion = aggregate.ExpectedVersion;
            var eventsToSave    = newEvents.Select(e => ToEventData(Guid.NewGuid(), e, commitHeaders)).ToList();

            if (eventsToSave.Count < WritePageSize)
            {
                _eventStoreConnection.AppendToStreamAsync(streamName, expectedVersion, eventsToSave).Wait();
            }
            else
            {
                var transaction = _eventStoreConnection.StartTransactionAsync(streamName, expectedVersion).Result;

                var position = 0;
                while (position < eventsToSave.Count)
                {
                    var pageEvents = eventsToSave.Skip(position).Take(WritePageSize);
                    transaction.WriteAsync(pageEvents).Wait();
                    position += WritePageSize;
                }

                transaction.CommitAsync().Wait();
            }
            if (_outBus != null)
            {
                foreach (var evt in newEvents)
                {
                    try
                    {
                        _outBus.Publish((Message)evt);
                    }
                    catch { }//TODO: see if we need to do something here
                }
            }
            //aggregate.ClearUncommittedEvents();
        }
예제 #4
0
 public NcqrsEventSource(IEventSource source)
     : base("Source_" + source.EventSourceId.ToString(),
            "Source_" + source.EventSourceId.ToString())
 {
     Timestamp = DateTime.UtcNow;
     Version   = source.Version;
     Name      = source.GetType().ToString();
 }
예제 #5
0
 public NcqrsEventSource(IEventSource source)
     : base("Source_" + source.EventSourceId.ToString(),
         "Source_" + source.EventSourceId.ToString())
 {
     Timestamp = DateTime.UtcNow;
     Version = source.Version;
     Name = source.GetType().ToString();
 }
        public void Save(IEventSource aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders)
        {
            var jsonText = JsonConvert.SerializeObject(aggregate, SerializerSettings);

            File.WriteAllText(
                _fileFullName(aggregate.GetType(), aggregate.Id),
                jsonText
                );
        }
예제 #7
0
        public static EventSourceEntity CreateFromEventSource(IEventSource source)
        {
            Contract.Requires<ArgumentNullException>(source != null, "The source cannot be null.");

            return new EventSourceEntity
            {
                RowKey = source.EventSourceId.ToString(),
                PartitionKey = source.GetType().FullName,
                Version = source.Version
            };
        }
예제 #8
0
 private void AddEventSource(IEventSource eventSource, SQLiteTransaction transaction)
 {
     using (var cmd = new SQLiteCommand(Query.InsertNewProviderQuery, transaction.Connection))
     {
         cmd.SetTransaction(transaction)
         .AddParam("Id", eventSource.EventSourceId)
         .AddParam("Type", eventSource.GetType().ToString())
         .AddParam("Version", eventSource.Version);
         cmd.ExecuteNonQuery();
     }
 }
예제 #9
0
 /// <summary>
 /// Adds the event source to the event store.
 /// </summary>
 /// <param name="eventSource">The event source to add.</param>
 /// <param name="transaction">The transaction.</param>
 private static void AddEventSource(IEventSource eventSource, SqlTransaction transaction)
 {
     using (var command = new SqlCommand(Queries.InsertNewProviderQuery, transaction.Connection))
     {
         command.Transaction = transaction;
         command.Parameters.AddWithValue("Id", eventSource.EventSourceId);
         command.Parameters.AddWithValue("Type", eventSource.GetType().ToString());
         command.Parameters.AddWithValue("Version", eventSource.Version);
         command.ExecuteNonQuery();
     }
 }
예제 #10
0
        private IDictionary <string, Action <IEventSource, object> > GetCached(IEventSource eventsource, Type eventType)
        {
            // Wtf is going on here? Well allow me to explain
            // In our eventsources we have methods that look like:
            // private void Handle(Events.MyEvent e) {}
            // and we may also have
            // private void Conflict(Events.MyEvent e) {}
            // this little cache GetOrAdd is basically searching for those methods and returning an Action the caller
            // can use to execute the method
            var mappedType = _mapper.GetMappedTypeFor(eventType);
            IDictionary <string, Action <IEventSource, object> > handles;

            lock (Lock)
            {
                if (Cache.TryGetValue(eventType, out handles))
                {
                    return(handles);
                }
            }

            var methods = eventsource.GetType()
                          .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                          .Where(
                m => (m.Name == "Handle" || m.Name == "Conflict") &&
                m.GetParameters().Length == 1 &&
                m.GetParameters().Single().ParameterType == mappedType &&
                m.ReturnParameter.ParameterType == typeof(void));
            //.Select(m => new { Method = m, MessageType = m.GetParameters().Single().ParameterType });

            var methodInfos = methods as MethodInfo[] ?? methods.ToArray();

            if (!methodInfos.Any())
            {
                return(null);
            }

            handles = methodInfos.ToDictionary(x => x.Name, x => (Action <IEventSource, object>)((es, m) =>
            {
                try
                {
                    x.Invoke(es, new[] { m });
                }
                catch (TargetInvocationException e)
                {
                    ExceptionDispatchInfo.Capture(e.InnerException).Throw();
                }
            }));

            lock (Lock)
            {
                return(Cache[eventType] = handles);
            }
        }
        // This method discovers all private Apply methods on an event source that take an event as the sole parameter and return void
        // and registers them with the given source. The result of the discovery process is cached.
        public static void DiscoverRoutes(this IEventSource source, Action <Type, Action <object> > register)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (register == null)
            {
                throw new ArgumentNullException(nameof(register));
            }

            var routeFactories = RouteFactoryIndex.GetOrAdd(source.GetType(), typeOfSource => {
                var builder           = new List <Func <IEventSource, Tuple <Type, Action <object> > > >();
                var instanceParameter = Expression.Parameter(typeof(IEventSource), "instance");
                var eventParameter    = Expression.Parameter(typeof(object), "@event");
                foreach (var method in
                         typeOfSource
                         .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                         .Where(candidateMethod =>
                                candidateMethod.Name == "Apply" &&
                                candidateMethod.GetParameters().Length == 1 &&
                                candidateMethod.ReturnType == typeof(void)
                                )
                         )
                {
                    var typeOfEvent = method.GetParameters()[0].ParameterType;
                    var route       = Expression.Lambda <Action <IEventSource, object> >(
                        Expression.Call(
                            Expression.Convert(instanceParameter, typeOfSource),
                            method,
                            Expression.Convert(eventParameter, typeOfEvent)),
                        instanceParameter,
                        eventParameter
                        ).Compile();

                    builder.Add(
                        instance =>
                        Tuple.Create <Type, Action <object> >(
                            typeOfEvent,
                            @event => route(instance, @event))
                        );
                }
                return(builder.ToArray());
            });

            Array.ForEach(routeFactories, routeFactory => {
                var route = routeFactory(source);
                register(route.Item1, route.Item2);
            });
        }
        public void Save(IEventSource aggregate)
        {
            var commitHeaders = new Dictionary <string, object>
            {
                { CommitIdHeader, Guid.NewGuid() /*commitId*/ },
                { AggregateClrTypeNameHeader, aggregate.GetType().AssemblyQualifiedName },
                { AggregateClrTypeHeader, aggregate.GetType().Name }
            };

            var streamName      = _streamNameBuilder.GenerateForAggregate(aggregate.GetType(), aggregate.Id);
            var newEvents       = aggregate.TakeEvents().ToArray();
            var expectedVersion = aggregate.ExpectedVersion;
            var eventsToSave    = new EventData[newEvents.Length];

            for (int i = 0; i < newEvents.Length; i++)
            {
                eventsToSave[i] =
                    _eventSerializer.Serialize(
                        newEvents[i],
                        new Dictionary <string, object>(commitHeaders));
            }
            _streamStoreConnection.AppendToStream(streamName, expectedVersion, null, eventsToSave);
        }
        public IEnumerable<ISourcedEventHandler> GetEventHandlersFromAggregateRoot(IEventSource eventSource)
        {
            Contract.Requires<ArgumentNullException>(eventSource != null, "The eventSource cannot be null.");
            Contract.Ensures(Contract.Result<IEnumerable<ISourcedEventHandler>>() != null, "The result should never be null.");

            var targetType = eventSource.GetType();
            var handlers = new List<ISourcedEventHandler>();

            Logger.DebugFormat("Trying to get all event handlers based by convention for {0}.", targetType);

            var methodsToMatch = targetType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            var matchedMethods = from method in methodsToMatch
                                 let parameters = method.GetParameters()
                                 let noEventHandlerAttributes =
                                     method.GetCustomAttributes(typeof(NoEventHandlerAttribute), true)
                                 where
                                     // Get only methods where the name matches.
                                    Regex.IsMatch(method.Name, _regexPattern, RegexOptions.CultureInvariant) &&
                                     // Get only methods that have 1 parameter.
                                    parameters.Length == 1 &&
                                     // Get only methods where the first parameter is an event.
                                    typeof(IEvent).IsAssignableFrom(parameters[0].ParameterType) &&
                                     // Get only methods that are not marked with the no event handler attribute.
                                    noEventHandlerAttributes.Length == 0
                                 select
                                    new { MethodInfo = method, FirstParameter = method.GetParameters()[0] };

            foreach (var method in matchedMethods)
            {
                var methodCopy = method.MethodInfo;
                Type firstParameterType = methodCopy.GetParameters().First().ParameterType;

                Action<IEvent> invokeAction = (e) => methodCopy.Invoke(eventSource, new object[] { e });

                Logger.DebugFormat("Created event handler for method {0} based on convention.", methodCopy.Name);

                var handler = new TypeThresholdedActionBasedDomainEventHandler(invokeAction, firstParameterType, true);
                handlers.Add(handler);
            }

            return handlers;
        }
예제 #14
0
        private void AddConfigTab(IEventSource source)
        {
            var tabPage = new TabPage
            {
                Name = source.Name,
                Text = "Event Source " + source.GetType().Name
            };

            var control = source.CreateConfigControl();

            if (control != null)
            {
                control.Dock      = DockStyle.Fill;
                control.BackColor = SystemColors.ControlLightLight;
                tabPage.Controls.Add(control);

                this.tabControl.TabPages.Add(tabPage);
            }
        }
예제 #15
0
        private void AddConfigTab(IEventSource source)
        {
            var label = source.GetType().Name;

            if (esNames.ContainsKey(label))
            {
                label = esNames[label];
            }

            var tabPage = new ConfigTabPage
            {
                Name          = source.Name,
                Text          = "",
                IsEventSource = true,
            };

            var control = source.CreateConfigControl();

            if (control != null)
            {
                control.Dock      = DockStyle.Fill;
                control.BackColor = SystemColors.ControlLightLight;
                tabPage.Controls.Add(control);

                var index = 0;
                foreach (var page in this.tabControl.TabPages)
                {
                    if (index == 0 || ((ConfigTabPage)page).IsEventSource)
                    {
                        index++;
                    }
                    else
                    {
                        break;
                    }
                }

                this.tabControl.TabPages.Insert(index, tabPage);
            }
        }
예제 #16
0
        private void btnCactbotUpdate_Click(object sender, EventArgs e)
        {
            try
            {
                var asm         = Assembly.Load("CactbotEventSource");
                var checkerType = asm.GetType("Cactbot.VersionChecker");
                var loggerType  = asm.GetType("Cactbot.ILogger");
                var configType  = asm.GetType("Cactbot.CactbotEventSourceConfig");

                var          esList    = container.Resolve <Registry>().EventSources;
                IEventSource cactbotEs = null;

                foreach (var es in esList)
                {
                    if (es.Name == "Cactbot Config" || es.Name == "Cactbot")
                    {
                        cactbotEs = es;
                        break;
                    }
                }

                if (cactbotEs == null)
                {
                    MessageBox.Show("Cactbot is loaded but it never registered with OverlayPlugin!", "Error");
                    return;
                }

                var cactbotConfig = cactbotEs.GetType().GetProperty("Config").GetValue(cactbotEs);
                configType.GetField("LastUpdateCheck").SetValue(cactbotConfig, DateTime.MinValue);

                var checker = checkerType.GetConstructor(new Type[] { loggerType }).Invoke(new object[] { cactbotEs });
                checkerType.GetMethod("DoUpdateCheck", new Type[] { configType }).Invoke(checker, new object[] { cactbotConfig });
            } catch (FileNotFoundException)
            {
                MessageBox.Show("Could not find Cactbot!", "Error");
            } catch (Exception ex)
            {
                MessageBox.Show("Failed: " + ex.ToString(), "Error");
            }
        }
        /// <summary>
        /// Gets the event handlers from aggregate root based on attributes.
        /// </summary>
        /// <param name="eventSource">The aggregate root.</param>
        /// <see cref="AttributeBasedDomainSourcedEventHandlerMappingStrategy"/>
        /// <returns>All the <see cref="IDomainEventHandler"/>'s created based on attribute mapping.</returns>
        public IEnumerable<ISourcedEventHandler> GetEventHandlersFromAggregateRoot(IEventSource eventSource)
        {
            Contract.Requires<ArgumentNullException>(eventSource != null, "The eventSource cannot be null.");

            var targetType = eventSource.GetType();
            var handlers = new List<ISourcedEventHandler>();

            foreach (var method in targetType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
            {
                EventHandlerAttribute attribute;

                if (IsMarkedAsEventHandler(method, out attribute))
                {
                    if (method.IsStatic) // Handlers are never static. Since they need to update the internal state of an eventsource.
                    {
                        var message = String.Format("The method {0}.{1} could not be mapped as an event handler, since it is static.", method.DeclaringType.Name, method.Name);
                        throw new InvalidEventHandlerMappingException(message);
                    }
                    if (NumberOfParameters(method) != 1) // The method should only have one parameter.
                    {
                        var message = String.Format("The method {0}.{1} could not be mapped as an event handler, since it has {2} parameters where 1 is required.", method.DeclaringType.Name, method.Name, NumberOfParameters(method));
                        throw new InvalidEventHandlerMappingException(message);
                    }
                    if (!typeof(IEvent).IsAssignableFrom(FirstParameterType(method))) // The parameter should be an IEvent.
                    {
                        var message = String.Format("The method {0}.{1} could not be mapped as an event handler, since it the first parameter is not an event type.", method.DeclaringType.Name, method.Name);
                        throw new InvalidEventHandlerMappingException(message);
                    }

                    var handler = CreateHandlerForMethod(eventSource, method, attribute);
                    handlers.Add(handler);
                }
            }

            return handlers;
        }
예제 #18
0
        public Action <IEventSource, Object> Resolve(IEventSource eventsource, Type eventType)
        {
            var mappedType = _mapper.GetMappedTypeFor(eventType);

            return(_cache.GetOrAdd(mappedType, (key) =>
            {
                var handleMethod = eventsource.GetType()
                                   .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                                   .SingleOrDefault(
                    m => m.Name == "Handle" &&
                    m.GetParameters().Length == 1 &&
                    m.GetParameters().Single().ParameterType == mappedType &&
                    m.ReturnParameter.ParameterType == typeof(void));
                //.Select(m => new { Method = m, MessageType = m.GetParameters().Single().ParameterType });

                if (handleMethod == null)
                {
                    return null;
                }

                Action <IEventSource, Object> action = (es, m) => handleMethod.Invoke(es, new[] { m });
                return action;
            }));
        }
예제 #19
0
        public void Test_WovenAssembly_WeakEventReferenceRemoved()
        {
            IEventSource wovenClass = CreateWovenEventSource();

            Assert.IsFalse(wovenClass.GetType().Assembly.GetReferencedAssemblies().Any(name => name.FullName.Equals(typeof(WeakEvents.ImplementWeakEventsAttribute).Assembly.FullName)));
        }
예제 #20
0
        public void Test_WovenClass_WeakEventAttributeRemoved()
        {
            IEventSource wovenClass = CreateWovenEventSource();

            Assert.AreEqual(0, wovenClass.GetType().GetCustomAttributes(typeof(WeakEvents.ImplementWeakEventsAttribute), false).Length);
        }
예제 #21
0
 /// <summary>
 /// Adds the event source to the event store.
 /// </summary>
 /// <param name="eventSource">The event source to add.</param>
 /// <param name="transaction">The transaction.</param>
 private static void AddEventSource(IEventSource eventSource, SqlTransaction transaction)
 {
     using (var command = new SqlCommand(InsertNewProviderQuery, transaction.Connection))
     {
         command.Transaction = transaction;
         command.Parameters.AddWithValue("Id", eventSource.Id);
         command.Parameters.AddWithValue("Type", eventSource.GetType().ToString());
         command.Parameters.AddWithValue("Version", eventSource.Version);
         command.ExecuteNonQuery();
     }
 }
예제 #22
0
        private void WriteSync <K, E>(IEventSource eventSource, string originatorId, EventSourceEntry <K, E> entry, DateTime?utcTimeStamp)
        {
            int numberOfRetries = 0;

            while (true)
            {
                try
                {
                    eventSource.Write(originatorId, entry, utcTimeStamp).Wait();

                    return;
                }
                catch (Exception ex)
                {
                    if (numberOfRetries >= mPolicy.EventSourceRetryLimit)
                    {
                        this.LogException(string.Format("Unable to log to event source {0} for {1}-{2}-{3}", eventSource.GetType().Name, entry.EntityType, entry.Key, entry.EntityVersion), ex);
                        throw;
                    }
                }

                Task.Delay(TimeSpan.FromMilliseconds(numberOfRetries * 100)).Wait();

                numberOfRetries++;
            }
        }
예제 #23
0
 private void AddEventSource(IEventSource eventSource, SQLiteTransaction transaction)
 {
     using (var cmd = new SQLiteCommand(Query.InsertNewProviderQuery, transaction.Connection))
     {
         cmd.SetTransaction(transaction)
             .AddParam("Id", eventSource.EventSourceId)
             .AddParam("Type", eventSource.GetType().ToString())
             .AddParam("Version", eventSource.Version);
         cmd.ExecuteNonQuery();
     }
 }
        public void Save(IEventSource aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders)
        {
            var commitHeaders = new Dictionary <string, object>
            {
                { CommitIdHeader, commitId },
                { AggregateClrTypeHeader, aggregate.GetType().AssemblyQualifiedName }
            };

            updateHeaders(commitHeaders);

            var streamName         = _aggregateIdToStreamName(aggregate.GetType(), aggregate.Id);
            var categoryStreamName = _aggregateTypeToCategoryStreamName(aggregate.GetType());
            var newEvents          = aggregate.TakeEvents().ToList();

            var eventsToSave = newEvents.Select(e => ToEventData(Guid.NewGuid(), e, commitHeaders)).ToList();

            List <EventData> stream;

            _store.TryGetValue(streamName, out stream);
            List <EventData> catStream;

            _store.TryGetValue(categoryStreamName, out catStream);



            if (stream == null)
            {
                if (aggregate.ExpectedVersion == ExpectedVersion.Any || aggregate.ExpectedVersion == ExpectedVersion.NoStream)
                {
                    stream = new List <EventData>();
                    _store.Add(streamName, stream);
                    if (catStream == null)
                    {
                        catStream = new List <EventData>();
                        _store.Add(categoryStreamName, catStream);
                    }
                }
                else
                {
                    throw new WrongExpectedVersionException("Stream " + streamName + " does not exist.");
                }
            }

            if (stream.Count != 0 && stream.Count - 1 != aggregate.ExpectedVersion)  // a new stream will be @ version 0
            {
                throw new AggregateException(new WrongExpectedVersionException(
                                                 $"Stream {streamName} at version {stream.Count}, expected version {aggregate.ExpectedVersion}"));
            }


            stream.AddRange(eventsToSave);
            catStream?.AddRange(eventsToSave);

            foreach (var evt in eventsToSave)
            {
                var etName = _eventNameToEventTypeStreamName(evt.Type);
                List <EventData> etStream;
                if (!_store.TryGetValue(etName, out etStream))
                {
                    etStream = new List <EventData>();
                    _store.Add(etName, etStream);
                }
                etStream.Add(evt);
            }

            foreach (var @event in newEvents.Where(@event => (@event as Message) != null))
            {
                _bus.Publish(@event as Message);
                _history.Add(new Tuple <string, Message>(streamName, @event as Message));
            }
            // aggregate.ClearUncommittedEvents();
        }