public static string GetConcurrencyToken <TEntity>(this IEntityPropertyAccessor entityPropertyAccessor, TEntity entityType, object entity)
        {
            if (entityPropertyAccessor == null)
            {
                throw new ArgumentNullException(nameof(entityPropertyAccessor));
            }

            return(entityPropertyAccessor.GetConcurrencyToken(typeof(TEntity), entity));
        }
Example #2
0
        public ProductDeleteModel ProjectToDeleteModel(Product product,
                                                       [Inject] IEntityPropertyAccessor propertyManager)
        {
            if (product == null)
            {
                return(null);
            }

            var concurrencyToken = propertyManager.GetConcurrencyToken(typeof(Product), product);

            return(new ProductDeleteModel
            {
                Id = product.Id,
                ConcurrencyToken = concurrencyToken
            });
        }
Example #3
0
        public override async ValueTask <IDispatchResult> ProcessAsync <TMessage>(DispatchDataDictionary <TMessage> dispatchData,
                                                                                  Func <DispatchDataDictionary <TMessage>, ValueTask <IDispatchResult> > next,
                                                                                  CancellationToken cancellation)
        {
            var message    = dispatchData.Message;
            var handler    = Context.MessageHandler;
            var descriptor = EntityMessageHandlerContextDescriptor.GetDescriptor(handler.GetType());

            if (!descriptor.IsEntityMessageHandler)
            {
                return(await next(dispatchData));
            }

            if (!TryGetEntityLookup(message, descriptor, out var entityLookup))
            {
                return(await next(dispatchData));
            }

            var messageAccessor       = GetMessageAccessor();
            var checkConcurrencyToken = messageAccessor.TryGetConcurrencyToken(message, out var concurrencyToken);

            do
            {
                var entity = await entityLookup(cancellation);

                var createsEntityAttribute = Context.MessageHandlerAction.Member.GetCustomAttribute <CreatesEntityAttribute>();

                if (entity == null)
                {
                    if (createsEntityAttribute == null ||
                        !createsEntityAttribute.CreatesEntity)
                    {
                        return(new EntityNotFoundDispatchResult(descriptor.EntityType));
                    }
                }
                else
                {
                    if (createsEntityAttribute != null &&
                        createsEntityAttribute.CreatesEntity &&
                        !createsEntityAttribute.AllowExisingEntity)
                    {
                        if (!_entityPropertyAccessor.TryGetId(descriptor.EntityType, entity, out var id))
                        {
                            return(new EntityAlreadyPresentDispatchResult(descriptor.EntityType));
                        }
                        else
                        {
                            return(new EntityAlreadyPresentDispatchResult(descriptor.EntityType, id));
                        }
                    }

                    if (checkConcurrencyToken &&
                        concurrencyToken != _entityPropertyAccessor.GetConcurrencyToken(descriptor.EntityType, entity))
                    {
                        return(new ConcurrencyIssueDispatchResult());
                    }

                    descriptor.SetHandlerEntity(handler, entity);
                }

                var originalEntity = entity;
                var dispatchResult = await next(dispatchData);

                if (!dispatchResult.IsSuccess)
                {
                    return(dispatchResult);
                }

                var markedAsDeleted = descriptor.IsMarkedAsDeleted(handler);
                entity = descriptor.GetHandlerEntity(handler);

                try
                {
                    // The Store/Delete calls must be protected to be called with a null entity.
                    if (entity != null || originalEntity != null) // TODO: Do we care about events etc. here?
                    {
                        if (!_entityPropertyAccessor.TryGetId(descriptor.EntityType, entity ?? originalEntity, out var id))
                        {
                            return(new FailureDispatchResult("Unable to determine the id of the specified entity."));
                        }

                        if (markedAsDeleted || entity == null)
                        {
                            await _entityStorageEngine.DeleteAsync(descriptor.EntityType, entity ?? originalEntity, id);
                        }
                        else if (await _entityStorageEngine.TryStoreAsync(descriptor.EntityType, entity, id))
                        {
                            dispatchResult = AddAdditionalResultData(descriptor, entity, dispatchResult);
                        }
                        else
                        {
                            continue;
                        }
                    }
                }
                catch (ConcurrencyException)
                {
                    Assert(false);
                    continue;
                }
                catch (StorageException exc)
                {
                    return(new StorageIssueDispatchResult(exc));
                }
                catch (Exception exc)
                {
                    return(new FailureDispatchResult(exc));
                }

                return(dispatchResult);
            }while (!checkConcurrencyToken);

            return(new ConcurrencyIssueDispatchResult());
        }