Пример #1
0
        public async Task <QueryResultList <T> > Handle(GetListQuery <T> request, CancellationToken cancellationToken)
        {
            // Drop an AuditLogEvent onto the mediator, to dispatch a request to update the system audit log. Again, we're not going to wait for the outcome of this event. Just fire and forget.
            string        dataAccessTypeString = string.Format("Get{0}List", typeof(T).Name);
            var           dataAccessType       = (DataAccessType)Enum.Parse(typeof(DataAccessType), dataAccessTypeString);
            AuditLogEvent auditLogNotification = new AuditLogEvent(_currentUser.UserName, Guid.Empty, dataAccessType);
            await _mediator.Publish(auditLogNotification);

            // Call the GetList method to get a list of the requested aggregate type, using the provided paging parameters and filter
            var result = await GetList(request.Paging);

            if (result.ResultType == ResultType.OkForQuery)
            {
                // Return the result list identifier
                return(new QueryResultList <T>(result.Content));
            }
            else
            {
                if (result.ResultType == ResultType.AccessDenied)
                {
                    // Drop an AuditLogEvent onto the mediator to indicate that this action was denied
                    AuditLogEvent accessDeniedAuditEntry = new AuditLogEvent(_currentUser.UserName, Guid.Empty, dataAccessType, true);
                    await _mediator.Publish(accessDeniedAuditEntry);
                }

                // Query returned a non-success result, so return the result, and the errors
                return(new QueryResultList <T>(result.ResultType));
            }
        }
 public IActionResult Get([FromQuery] AuditLogEvent parameters = null)
 {
     try
     {
         var model = repository.Get();
         return(Ok(model));
     }
     catch (Exception ex)
     {
         logger.LogError(ex.GetExceptionMessages());
         return(StatusCode(StatusCodes.Status500InternalServerError, Constants.ErrorMessages.FetchError));
     }
 }
Пример #3
0
        /// <summary>
        /// Handle a DELETE command which specifies that an aggregate should be marked as deleted
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task <CommandResult <Guid> > Handle(DeleteCommand <T> request, CancellationToken cancellationToken)
        {
            // Validate input
            if (request.EventStreamId == Guid.Empty)
            {
                return(new CommandResult <Guid>(ResultType.BadRequest));
            }

            if (await GetSpecificAggregateRoot(request.EventStreamId) == null)
            {
                return(new CommandResult <Guid>(ResultType.NothingFound));
            }

            // Call extension point to get the action authorised for the user in question, and the specific resource
            var authResult = await this.AuthoriseDelete(request.EventStreamId);

            if (authResult.ResultType == ResultType.AccessDenied)
            {
                // TODO: Move the Access Denied audit log creation to here, from the child classes?
                return(new CommandResult <Guid>(authResult.ResultType));
            }

            // Create a domain event record for this aggregate, and this entity (This is an UPDATE for the aggregate as we're not DELETING the record physically)
            string eventData = new JObject()
            {
                new JProperty("Status", EntityStatus.Cancelled.ToString())
            }.ToString();
            DomainEventType eventType   = (DomainEventType)Enum.Parse(typeof(DomainEventType), ($"Modify{typeof(T).Name}Event"));
            DomainEvent     domainEvent = new DomainEvent(eventData, _currentUser.UserName, eventType, request.EventStreamId);

            // Save the domain event
            _dc.DomainEvents.Add(domainEvent);
            await _dc.SaveChangesAsync();

            // Publish domain event notification - this is published as a MODIFY on the aggregate as we are not physically deleting the record, rather we're changing its status.
            UpdatedEvent <T> eventNotification = new UpdatedEvent <T>(eventData, _currentUser.UserName, domainEvent.EventStreamId, domainEvent.Id);
            await _mediator.Publish(eventNotification);

            // Drop an AuditLogEvent onto the mediator, to dispatch a request to update the system audit log. Again, we're not going to wait for the outcome of this event. Just fire and forget.
            // We are going to audit this as a DELETE even though it's enacted as a modify, for clarity
            AuditLogEvent auditLogNotification = new AuditLogEvent((DomainEventType)Enum.Parse(typeof(DomainEventType), ($"Delete{typeof(T).Name}Event")), _currentUser.UserName, domainEvent.EventStreamId, domainEvent.Id);
            await _mediator.Publish(auditLogNotification);

            // Return new command result, with the PARENT's event stream id.
            return(new CommandResult <Guid>());
        }
Пример #4
0
        /// <summary>
        /// Handle a CREATE command which specifies that a new entity should be added to a child collection on an aggregate
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task <CommandResult <Guid> > Handle(CreateChildCommand <T> request, CancellationToken cancellationToken)
        {
            // Validate input
            if (string.IsNullOrWhiteSpace(request.EventData) || request.ParentEventStreamId == Guid.Empty)
            {
                return(new CommandResult <Guid>(ResultType.BadRequest));
            }

            if (await GetSpecificAggregateRoot(request.ParentEventStreamId) == null)
            {
                return(new CommandResult <Guid>(ResultType.NothingFound));
            }

            // Call extension point to get the action authorised for the user in question, and the specific resource
            var authResult = await this.AuthoriseModify(request.EventData, request.ParentEventStreamId, request.ChildEntityType);

            if (authResult.ResultType == ResultType.AccessDenied)
            {
                // TODO: Move the Access Denied audit log creation to here, from the child classes?
                return(new CommandResult <Guid>(authResult.ResultType));
            }
            else
            {
                // Create a domain event record for this aggregate, and this new child entity (This is an UPDATE for the aggregate, recorded as a Create of the new child)
                DomainEventType eventType   = (DomainEventType)Enum.Parse(typeof(DomainEventType), string.Format("Create{0}Event", request.ChildEntityType.Name));
                DomainEvent     domainEvent = new DomainEvent(request.EventData, _currentUser.UserName, eventType, request.ParentEventStreamId);

                // Save the domain event
                _dc.DomainEvents.Add(domainEvent);
                await _dc.SaveChangesAsync();

                // Publish domain event notification - this is published as a MODIFY on the aggregate as this will direct it to the correct Aggregate's domain serivce.
                UpdatedEvent <T> eventNotification = new UpdatedEvent <T>(request.EventData, _currentUser.UserName, domainEvent.EventStreamId, domainEvent.Id);
                await _mediator.Publish(eventNotification);

                // Drop an AuditLogEvent onto the mediator, to dispatch a request to update the system audit log. Again, we're not going to wait for the outcome of this event. Just fire and forget.
                AuditLogEvent auditLogNotification = new AuditLogEvent(domainEvent.DomainEventType, _currentUser.UserName, domainEvent.EventStreamId, domainEvent.Id);
                await _mediator.Publish(auditLogNotification);

                // Return new command result, with the PARENT's event stream id.
                return(new CommandResult <Guid>(request.ParentEventStreamId));
            }
        }
Пример #5
0
        /// <summary>
        /// Handle CREATE commands
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task <CommandResult <Guid> > Handle(CreateCommand <T> request, CancellationToken cancellationToken)
        {
            // Validate input
            if (string.IsNullOrWhiteSpace(request.EventData))
            {
                return(new CommandResult <Guid>(ResultType.BadRequest));
            }

            // Call extension point to get the action authorised for the user in question, and the specific resource
            var authResult = await this.AuthoriseCreate(request.EventData);

            if (authResult.ResultType == ResultType.AccessDenied)
            {
                // TODO: Move the Access Denied audit log creation to here, from the child classes?
                return(new CommandResult <Guid>(authResult.ResultType));
            }
            else
            {
                // This is a Create event (and thus starts a new event stream) so we need to create the Event Stream Id
                Guid eventStreamId = Guid.NewGuid();

                // Save the domain event record to the database
                DomainEventType eventType   = (DomainEventType)Enum.Parse(typeof(DomainEventType), string.Format("Create{0}Event", typeof(T).Name));
                DomainEvent     domainEvent = new DomainEvent(request.EventData, _currentUser.UserName, eventType, eventStreamId);

                _dc.DomainEvents.Add(domainEvent);
                await _dc.SaveChangesAsync();

                // Now publish events to signal the domain model to be updated, and to update the audit log
                CreatedEvent <T> eventNotification = new CreatedEvent <T>(request.EventData, _currentUser.UserName, domainEvent.EventStreamId, domainEvent.Id);
                await _mediator.Publish(eventNotification);

                // Drop an AuditLogEvent onto the mediator, to dispatch a request to update the system audit log. Again, we're not going to wait for the outcome of this event. Just fire and forget.
                AuditLogEvent auditLogNotification = new AuditLogEvent(eventNotification.DomainEventType, _currentUser.UserName, domainEvent.EventStreamId, domainEvent.Id);
                await _mediator.Publish(auditLogNotification);

                // If the response was not 201 CREATED (or it is, and we have errors) then we need to ensure that we pass the correct response code back, along with any "error" messages

                //return new CommandResult<Guid>(eventStreamId);
                return(new CommandResult <Guid>(authResult.ResultType, eventStreamId, authResult.Errors));
            }
        }
Пример #6
0
        /// <summary>
        /// Handle a PATCh command which specifies updates on a child entity of the aggregate root
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task <CommandResult <Guid> > Handle(ModifyChildCommand <T> request, CancellationToken cancellationToken)
        {
            // Validate input
            if (request.ParentEventStreamId == Guid.Empty || request.ChildEntityId < 1 || request.ChildEntityType == null || string.IsNullOrWhiteSpace(request.EventData))
            {
                return(new CommandResult <Guid>(ResultType.BadRequest));
            }

            T aggregateRoot = await GetSpecificAggregateRoot(request.ParentEventStreamId);

            // find the child collection
            var         childCollectionProperty = aggregateRoot?.GetType().GetProperties().Where(p => p.PropertyType.GenericTypeArguments.Contains(request.ChildEntityType)).First();
            IEnumerable childCollection         = (IEnumerable)childCollectionProperty?.GetMethod.Invoke(aggregateRoot, null);
            int         childCollectionCount    = childCollectionProperty == null || childCollection == null ? 0 : (int)childCollectionProperty.PropertyType.GetProperty("Count").GetValue(childCollection);

            bool childIdFound = false;

            if (childCollection != null)
            {
                foreach (dynamic child in childCollection)
                {
                    if (child.Id == request.ChildEntityId)
                    {
                        childIdFound = true;
                        break;
                    }
                }
            }

            // TODO: Return nothing found if the childentityId is not in the collection
            if (aggregateRoot == null || childCollection == null || childCollectionCount == 0 || childIdFound == false)
            {
                return(new CommandResult <Guid>(ResultType.NothingFound));
            }

            // Call extension point to get the action authorised for the user in question, and the specific resource.
            // This is a modify on a child entity, we're going to rely on the permission for modification of the parent entity for this.
            var authResult = await this.AuthoriseModify(request.EventData, request.ParentEventStreamId, request.ChildEntityType);

            if (authResult.ResultType == ResultType.AccessDenied)
            {
                // TODO: Move the Access Denied audit log creation to here, from the child classes?
                return(new CommandResult <Guid>(authResult.ResultType));
            }

            // Create a domain event record for this aggregate, and this entity (This is an UPDATE for the aggregate, since it's updating child data owned by this aggregate root)
            DomainEventType eventType   = (DomainEventType)Enum.Parse(typeof(DomainEventType), ($"Modify{request.ChildEntityType.Name}Event"));
            DomainEvent     domainEvent = new DomainEvent(request.EventData, _currentUser.UserName, eventType, request.ParentEventStreamId, request.ChildEntityId);

            // Save the domain event
            _dc.DomainEvents.Add(domainEvent);
            await _dc.SaveChangesAsync();

            // Publish domain event notification - this is published as a MODIFY on the aggregate as we are not physically deleting the record, rather we're changing its status.
            UpdatedEvent <T> eventNotification = new UpdatedEvent <T>(request.EventData, _currentUser.UserName, domainEvent.EventStreamId, domainEvent.Id);
            await _mediator.Publish(eventNotification);

            // Drop an AuditLogEvent onto the mediator, to dispatch a request to update the system audit log. Again, we're not going to wait for the outcome of this event. Just fire and forget.
            // We are going to audit this as a DELETE even though it's enacted as a modify, for clarity
            AuditLogEvent auditLogNotification = new AuditLogEvent((DomainEventType)Enum.Parse(typeof(DomainEventType), ($"Modify{request.ChildEntityType.Name}Event")), _currentUser.UserName, domainEvent.EventStreamId, domainEvent.Id);
            await _mediator.Publish(auditLogNotification);

            // Return new command result, with the PARENT's event stream id.
            return(new CommandResult <Guid>());
        }