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); }
/// <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); }
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(); }
public NcqrsEventSource(IEventSource source) : base("Source_" + source.EventSourceId.ToString(), "Source_" + source.EventSourceId.ToString()) { Timestamp = DateTime.UtcNow; Version = source.Version; Name = source.GetType().ToString(); }
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 ); }
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 }; }
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(); } }
/// <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(); } }
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; }
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); } }
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); } }
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; }
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; })); }
public void Test_WovenAssembly_WeakEventReferenceRemoved() { IEventSource wovenClass = CreateWovenEventSource(); Assert.IsFalse(wovenClass.GetType().Assembly.GetReferencedAssemblies().Any(name => name.FullName.Equals(typeof(WeakEvents.ImplementWeakEventsAttribute).Assembly.FullName))); }
public void Test_WovenClass_WeakEventAttributeRemoved() { IEventSource wovenClass = CreateWovenEventSource(); Assert.AreEqual(0, wovenClass.GetType().GetCustomAttributes(typeof(WeakEvents.ImplementWeakEventsAttribute), false).Length); }
/// <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(); } }
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++; } }
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(); }