public async Task ComplexTypeUpdate()
        {
            // Arrange
            var container = new RestierContainerBuilder(typeof(LibraryApi));
            var provider = container.BuildContainer();
            var libraryApi = provider.GetService<ApiBase>();

            var item = new DataModificationItem(
                "Readers",
                typeof(Person),
                null,
                DataModificationItemAction.Update, 
                new Dictionary<string, object> { { "Id", new Guid("53162782-EA1B-4712-AF26-8AA1D2AC0461") } },
                new Dictionary<string, object>(),
                new Dictionary<string, object> { { "Addr", new Dictionary<string, object> { { "Zip", "332" } } } });
            var changeSet = new ChangeSet(new[] { item });
            var sc = new SubmitContext(libraryApi.Context, changeSet);

            // Act
            var changeSetPreparer = libraryApi.Context.GetApiService<IChangeSetInitializer>();
            await changeSetPreparer.InitializeAsync(sc, CancellationToken.None);
            var person = item.Resource as Person;

            // Assert
            Assert.NotNull(person);
            Assert.Equal("332", person.Addr.Zip);
        }
Esempio n. 2
0
        private static async Task<object> FindEntity(
            SubmitContext context,
            DataModificationEntry entry,
            CancellationToken cancellationToken)
        {
            IQueryable query = context.ApiContext.Source(entry.EntitySetName);
            query = entry.ApplyTo(query);

            QueryResult result = await context.ApiContext.QueryAsync(new QueryRequest(query), cancellationToken);

            object entity = result.Results.SingleOrDefault();
            if (entity == null)
            {
                // TODO GitHubIssue#38 : Handle the case when entity is resolved
                // there are 2 cases where the entity is not found:
                // 1) it doesn't exist
                // 2) concurrency checks have failed
                // we should account for both - I can see 3 options:
                // a. always return "PreConditionFailed" result
                //  - this is the canonical behavior of WebAPI OData, see the following post:
                //    "Getting started with ASP.NET Web API 2.2 for OData v4.0" on http://blogs.msdn.com/b/webdev/.
                //  - this makes sense because if someone deleted the record, then you still have a concurrency error
                // b. possibly doing a 2nd query with just the keys to see if the record still exists
                // c. only query with the keys, and then set the DbEntityEntry's OriginalValues to the ETag values,
                //    letting the save fail if there are concurrency errors

                ////throw new EntityNotFoundException
                throw new InvalidOperationException(Resources.ResourceNotFound);
            }

            return entity;
        }
        /// <inheritdoc/>
        public Task<bool> AuthorizeAsync(
            SubmitContext context,
            ChangeSetEntry entry,
            CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");
            bool result = true;

            Type returnType = typeof(bool);
            string methodName = ConventionBasedChangeSetAuthorizer.GetAuthorizeMethodName(entry);
            MethodInfo method = this.targetType.GetQualifiedMethod(methodName);

            if (method != null && method.IsFamily &&
                method.ReturnType == returnType)
            {
                object target = null;
                if (!method.IsStatic)
                {
                    target = context.GetApiService<ApiBase>();
                    if (target == null ||
                        !this.targetType.IsAssignableFrom(target.GetType()))
                    {
                        return Task.FromResult(result);
                    }
                }

                var parameters = method.GetParameters();
                if (parameters.Length == 0)
                {
                    result = (bool)method.Invoke(target, null);
                }
            }

            return Task.FromResult(result);
        }
Esempio n. 4
0
        /// <summary>
        /// Asynchronously executes the submit flow.
        /// </summary>
        /// <param name="context">
        /// The submit context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is a submit result.
        /// </returns>
        public static async Task<SubmitResult> SubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");

            var preparer = context.GetApiService<IChangeSetPreparer>();
            if (preparer == null)
            {
                throw new NotSupportedException(Resources.ChangeSetPreparerMissing);
            }

            await preparer.PrepareAsync(context, cancellationToken);

            if (context.Result != null)
            {
                return context.Result;
            }

            var eventsChangeSet = context.ChangeSet;

            IEnumerable<ChangeSetEntry> currentChangeSetItems = eventsChangeSet.Entries.ToArray();

            await PerformValidate(context, currentChangeSetItems, cancellationToken);

            await PerformPreEvent(context, currentChangeSetItems, cancellationToken);

            await PerformPersist(context, currentChangeSetItems, cancellationToken);

            context.ChangeSet.Entries.Clear();

            await PerformPostEvent(context, currentChangeSetItems, cancellationToken);

            return context.Result;
        }
Esempio n. 5
0
        /// <summary>
        /// Asynchronously executes the submit flow.
        /// </summary>
        /// <param name="context">
        /// The submit context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is a submit result.
        /// </returns>
        public static async Task<SubmitResult> SubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");

            var preparer = context.GetHookHandler<IChangeSetPreparer>();
            if (preparer == null)
            {
                throw new NotSupportedException(Resources.ChangeSetPreparerMissing);
            }

            await preparer.PrepareAsync(context, cancellationToken);

            if (context.Result != null)
            {
                return context.Result;
            }

            ChangeSet eventsChangeSet = context.ChangeSet;

            IEnumerable<ChangeSetEntry> currentChangeSetItems;
            int outerLoopCount = 0;

            do
            {
                outerLoopCount++;
                int innerLoopCount = 0;
                do
                {
                    innerLoopCount++;
                    eventsChangeSet.AnEntityHasChanged = false;
                    currentChangeSetItems = eventsChangeSet.Entries.ToArray();

                    if (eventsChangeSet.AnEntityHasChanged)
                    {
                        eventsChangeSet.AnEntityHasChanged = false;
                        currentChangeSetItems = eventsChangeSet.Entries.ToArray();
                    }

                    await PerformValidate(context, currentChangeSetItems, cancellationToken);

                    await PerformPreEvent(context, currentChangeSetItems, cancellationToken);
                }
                while (eventsChangeSet.AnEntityHasChanged && (innerLoopCount < MaxLoop));

                VerifyNoEntityHasChanged(eventsChangeSet);

                await PerformPersist(context, currentChangeSetItems, cancellationToken);

                eventsChangeSet.Entries.Clear();

                await PerformPostEvent(context, currentChangeSetItems, cancellationToken);
            }
            while (eventsChangeSet.AnEntityHasChanged && (outerLoopCount < MaxLoop));

            VerifyNoEntityHasChanged(eventsChangeSet);

            return context.Result;
        }
 /// <inheritdoc/>
 public Task OnExecutedEntryAsync(
     SubmitContext context,
     ChangeSetEntry entry,
     CancellationToken cancellationToken)
 {
     return this.InvokeFilterMethodAsync(
         context, entry, ConventionBasedChangeSetConstants.FilterMethodNamePostFilterSuffix);
 }
 /// <inheritdoc/>
 public Task OnChangeSetItemProcessedAsync(
     SubmitContext context,
     ChangeSetItem item,
     CancellationToken cancellationToken)
 {
     return this.InvokeProcessorMethodAsync(
         context, item, ConventionBasedChangeSetConstants.FilterMethodNamePostFilterSuffix);
 }
Esempio n. 8
0
        /// <summary>
        /// Asynchronously executes the submission.
        /// </summary>
        /// <param name="context">The submit context class used for preparation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task object that represents this asynchronous operation.</returns>
        public async Task<SubmitResult> ExecuteSubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            DbContext dbContext = context.ApiContext.GetProperty<DbContext>(DbApiConstants.DbContextKey);

            await dbContext.SaveChangesAsync(cancellationToken);

            return new SubmitResult(context.ChangeSet);
        }
Esempio n. 9
0
        /// <summary>
        /// Asynchronously executes the submission.
        /// </summary>
        /// <param name="context">The submit context class used for preparation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task object that represents this asynchronous operation.</returns>
        public async Task<SubmitResult> ExecuteSubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            DbContext dbContext = context.DomainContext.GetProperty<DbContext>("DbContext");

            await dbContext.SaveChangesAsync(cancellationToken);

            return new SubmitResult(context.ChangeSet);
        }
Esempio n. 10
0
        /// <summary>
        /// Asynchronously executes the submission.
        /// </summary>
        /// <param name="context">The submit context class used for preparation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task object that represents this asynchronous operation.</returns>
        public async Task<SubmitResult> ExecuteSubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            DbContext dbContext = context.GetApiService<DbContext>();

            await dbContext.SaveChangesAsync(cancellationToken);

            return new SubmitResult(context.ChangeSet);
        }
Esempio n. 11
0
 private static async Task PerformPostEvent(
     SubmitContext context,
     IEnumerable <ChangeSetEntry> changeSetItems,
     CancellationToken cancellationToken)
 {
     foreach (ChangeSetEntry entry in changeSetItems)
     {
         foreach (var filter in context.GetHookPoints <IChangeSetEntryFilter>())
         {
             await filter.OnExecutedEntryAsync(context, entry, cancellationToken);
         }
     }
 }
Esempio n. 12
0
 private static async Task PerformPostEvent(
     SubmitContext context,
     IEnumerable <ChangeSetItem> changeSetItems,
     CancellationToken cancellationToken)
 {
     foreach (ChangeSetItem item in changeSetItems)
     {
         var processor = context.GetApiService <IChangeSetItemProcessor>();
         if (processor != null)
         {
             await processor.OnProcessedChangeSetItemAsync(context, item, cancellationToken);
         }
     }
 }
Esempio n. 13
0
 private static async Task PerformPostEvent(
     SubmitContext context,
     IEnumerable <ChangeSetEntry> changeSetItems,
     CancellationToken cancellationToken)
 {
     foreach (ChangeSetEntry entry in changeSetItems)
     {
         var filter = context.GetApiService <IChangeSetEntryFilter>();
         if (filter != null)
         {
             await filter.OnExecutedEntryAsync(context, entry, cancellationToken);
         }
     }
 }
Esempio n. 14
0
        private static async Task PerformPersist(
            SubmitContext context,
            IEnumerable <ChangeSetItem> changeSetItems,
            CancellationToken cancellationToken)
        {
            var executor = context.GetApiService <ISubmitExecutor>();

            if (executor == null)
            {
                throw new NotSupportedException(Resources.SubmitExecutorMissing);
            }

            context.Result = await executor.ExecuteSubmitAsync(context, cancellationToken);
        }
Esempio n. 15
0
        private async Task InvokeAuthorizers(SubmitContext context, IEnumerable <ChangeSetItem> changeSetItems, CancellationToken cancellationToken)
        {
            if (authorizer == null)
            {
                return;
            }

            foreach (var item in changeSetItems.Where(i => i.HasChanged()))
            {
                if (!await authorizer.AuthorizeAsync(context, item, cancellationToken).ConfigureAwait(false))
                {
                    throw new SecurityException(GetAuthorizeFailedMessage(item));
                }
            }
        }
        /// <summary>
        /// Asynchronously prepare the <see cref="ChangeSet"/>.
        /// </summary>
        /// <param name="context">The submit context class used for preparation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task object that represents this asynchronous operation.</returns>
        public async Task InitializeAsync(
            SubmitContext context,
            CancellationToken cancellationToken)
        {
            DbContext dbContext = context.ApiContext.GetApiService<DbContext>();

            foreach (var entry in context.ChangeSet.Entries.OfType<DataModificationItem>())
            {
                object strongTypedDbSet = dbContext.GetType().GetProperty(entry.ResourceSetName).GetValue(dbContext);
                Type resourceType = strongTypedDbSet.GetType().GetGenericArguments()[0];

                // This means request resource is sub type of resource type
                if (entry.ActualResourceType != null && resourceType != entry.ActualResourceType)
                {
                    // Set type to derived type
                    resourceType = entry.ActualResourceType;
                }

                DbSet set = dbContext.Set(resourceType);

                object resource;

                if (entry.DataModificationItemAction == DataModificationItemAction.Insert)
                {
                    resource = set.Create();
                    SetValues(resource, resourceType, entry.LocalValues);
                    set.Add(resource);
                }
                else if (entry.DataModificationItemAction == DataModificationItemAction.Remove)
                {
                    resource = await FindResource(context, entry, cancellationToken);
                    set.Remove(resource);
                }
                else if (entry.DataModificationItemAction == DataModificationItemAction.Update)
                {
                    resource = await FindResource(context, entry, cancellationToken);

                    DbEntityEntry dbEntry = dbContext.Entry(resource);
                    SetValues(dbEntry, entry, resourceType);
                }
                else
                {
                    throw new NotSupportedException(Resources.DataModificationMustBeCUD);
                }

                entry.Resource = resource;
            }
        }
        /// <inheritdoc/>
        public Task ValidateChangeSetItemAsync(
            SubmitContext context,
            ChangeSetItem item,
            Collection<ChangeSetItemValidationResult> validationResults,
            CancellationToken cancellationToken)
        {
            Ensure.NotNull(validationResults, "validationResults");
            DataModificationItem dataModificationItem = item as DataModificationItem;
            if (dataModificationItem != null)
            {
                object resource = dataModificationItem.Resource;

                // TODO GitHubIssue#50 : should this PropertyDescriptorCollection be cached?
                PropertyDescriptorCollection properties =
                    new DataAnnotations.AssociatedMetadataTypeTypeDescriptionProvider(resource.GetType())
                    .GetTypeDescriptor(resource).GetProperties();

                DataAnnotations.ValidationContext validationContext = new DataAnnotations.ValidationContext(resource);

                foreach (PropertyDescriptor property in properties)
                {
                    validationContext.MemberName = property.Name;

                    IEnumerable<DataAnnotations.ValidationAttribute> validationAttributes =
                        property.Attributes.OfType<DataAnnotations.ValidationAttribute>();
                    foreach (DataAnnotations.ValidationAttribute validationAttribute in validationAttributes)
                    {
                        object value = property.GetValue(resource);
                        DataAnnotations.ValidationResult validationResult =
                            validationAttribute.GetValidationResult(value, validationContext);
                        if (validationResult != DataAnnotations.ValidationResult.Success)
                        {
                            validationResults.Add(new ChangeSetItemValidationResult()
                            {
                                Id = validationAttribute.GetType().FullName,
                                Message = validationResult.ErrorMessage,
                                Severity = EventLevel.Error,
                                Target = resource,
                                PropertyName = property.Name
                            });
                        }
                    }
                }
            }

            return Task.WhenAll();
        }
        /// <inheritdoc/>
        public Task ValidateEntityAsync(
            SubmitContext context,
            ChangeSetEntry entry,
            ValidationResults validationResults,
            CancellationToken cancellationToken)
        {
            Ensure.NotNull(validationResults, "validationResults");
            DataModificationEntry dataModificationEntry = entry as DataModificationEntry;
            if (dataModificationEntry != null)
            {
                object entity = dataModificationEntry.Entity;

                // TODO GitHubIssue#50 : should this PropertyDescriptorCollection be cached?
                PropertyDescriptorCollection properties =
                    new DataAnnotations.AssociatedMetadataTypeTypeDescriptionProvider(entity.GetType())
                    .GetTypeDescriptor(entity).GetProperties();

                DataAnnotations.ValidationContext validationContext = new DataAnnotations.ValidationContext(entity);

                foreach (PropertyDescriptor property in properties)
                {
                    validationContext.MemberName = property.Name;

                    IEnumerable<DataAnnotations.ValidationAttribute> validationAttributes =
                        property.Attributes.OfType<DataAnnotations.ValidationAttribute>();
                    foreach (DataAnnotations.ValidationAttribute validationAttribute in validationAttributes)
                    {
                        object value = property.GetValue(entity);
                        DataAnnotations.ValidationResult validationResult =
                            validationAttribute.GetValidationResult(value, validationContext);
                        if (validationResult != DataAnnotations.ValidationResult.Success)
                        {
                            validationResults.Add(new ValidationResult()
                            {
                                Id = validationAttribute.GetType().FullName,
                                Message = validationResult.ErrorMessage,
                                Severity = ValidationSeverity.Error,
                                Target = entity,
                                PropertyName = property.Name
                            });
                        }
                    }
                }
            }

            return Task.WhenAll();
        }
        /// <inheritdoc/>
        public Task ValidateEntityAsync(
            SubmitContext context,
            ChangeSetEntry entry,
            ValidationResults validationResults,
            CancellationToken cancellationToken)
        {
            Ensure.NotNull(validationResults, "validationResults");
            DataModificationEntry dataModificationEntry = entry as DataModificationEntry;
            if (dataModificationEntry != null)
            {
                object entity = dataModificationEntry.Entity;

                // TODO (.NETCORE): Use PropertyDescriptorCollection in .NET Core (when available?)
                // TODO GitHubIssue#50 : should this PropertyDescriptorCollection be cached?
                IEnumerable<PropertyInfo> properties = entity.GetType().GetTypeInfo().DeclaredProperties;

                DataAnnotations.ValidationContext validationContext = new DataAnnotations.ValidationContext(entity);

                foreach (var property in properties)
                {
                    validationContext.MemberName = property.Name;

                    IEnumerable<DataAnnotations.ValidationAttribute> validationAttributes =
                        property.GetCustomAttributes().OfType<DataAnnotations.ValidationAttribute>();

                    foreach (var validationAttribute in validationAttributes)
                    {
                        object value = property.GetValue(entity);
                        DataAnnotations.ValidationResult validationResult =
                            validationAttribute.GetValidationResult(value, validationContext);
                        if (validationResult != DataAnnotations.ValidationResult.Success)
                        {
                            validationResults.Add(new ValidationResult()
                            {
                                Id = validationAttribute.GetType().FullName,
                                Message = validationResult.ErrorMessage,
                                Severity = ValidationSeverity.Error,
                                Target = entity,
                                PropertyName = property.Name
                            });
                        }
                    }
                }
            }

            return Task.WhenAll();
        }
        public Task OnChangeSetItemProcessedAsync(SubmitContext context, ChangeSetItem item, CancellationToken cancellationToken)
        {
            var dataModificationItem = item as DataModificationItem;
            if (dataModificationItem != null)
            {
                object myEntity = dataModificationItem.Resource;
                string entitySetName = dataModificationItem.ResourceSetName;
                DataModificationItemAction operation = dataModificationItem.DataModificationItemAction;

                // In case of insert, the request URL has no key, and request body may not have key neither as the key may be generated by database
                var keyAttrbiutes = new Dictionary<string, object>();
                var keyConvention = new Dictionary<string, object>();

                var entityTypeName = myEntity.GetType().Name;
                PropertyInfo[] properties = myEntity.GetType().GetProperties();

                foreach (PropertyInfo property in properties)
                {
                    var attribute = Attribute.GetCustomAttribute(property, typeof(KeyAttribute))
                        as KeyAttribute;
                    var propName = property.Name;
                    // This is getting key with Key attribute defined
                    if (attribute != null) // This property has a KeyAttribute
                    {
                        // Do something, to read from the property:
                        object val = property.GetValue(myEntity);
                        keyAttrbiutes.Add(propName, val);
                    }
                    // This is getting key based on convention
                    else if(propName.ToLower().Equals("id") || propName.ToLower().Equals(entityTypeName.ToLower()+"id"))
                    {
                        object val = property.GetValue(myEntity);
                        keyConvention.Add(propName, val);
                    }
                }
                if (keyAttrbiutes.Count > 0)
                {
                    // Use property with key attribute as keys    
                }
                else if(keyConvention.Count > 0)
                {
                    // Key is defined based on convention
                }
            }
            return Inner.OnChangeSetItemProcessedAsync(context, item, cancellationToken);
        }
Esempio n. 21
0
        private async Task PerformValidate(SubmitContext context, IEnumerable <ChangeSetItem> changeSetItems, CancellationToken cancellationToken)
        {
            await InvokeAuthorizers(context, changeSetItems, cancellationToken).ConfigureAwait(false);

            await InvokeValidators(context, changeSetItems, cancellationToken).ConfigureAwait(false);

            foreach (var item in changeSetItems.Where(i => i.HasChanged()))
            {
                if (item.ChangeSetItemProcessingStage == ChangeSetItemProcessingStage.ChangedWithinOwnPreEventing)
                {
                    item.ChangeSetItemProcessingStage = ChangeSetItemProcessingStage.PreEvented;
                }
                else
                {
                    item.ChangeSetItemProcessingStage = ChangeSetItemProcessingStage.Validated;
                }
            }
        }
Esempio n. 22
0
        /// <summary>
        /// Asynchronously prepare the <see cref="ChangeSet"/>.
        /// </summary>
        /// <param name="context">The submit context class used for preparation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task object that represents this asynchronous operation.</returns>
        public async Task PrepareAsync(
            SubmitContext context,
            CancellationToken cancellationToken)
        {
            DbContext dbContext = context.DomainContext.GetProperty<DbContext>("DbContext");

            foreach (var entry in context.ChangeSet.Entries.OfType<DataModificationEntry>())
            {
                object strongTypedDbSet = dbContext.GetType().GetProperty(entry.EntitySetName).GetValue(dbContext);
                Type entityType = strongTypedDbSet.GetType().GetGenericArguments()[0];
                DbSet set = dbContext.Set(entityType);

                object entity;

                if (entry.IsNew)
                {
                    entity = set.Create();

                    SetValues(entity, entityType, entry.LocalValues);

                    set.Add(entity);
                }
                else if (entry.IsDelete)
                {
                    entity = await FindEntity(context, entry, cancellationToken);
                    set.Remove(entity);
                }
                else if (entry.IsUpdate)
                {
                    entity = await FindEntity(context, entry, cancellationToken);

                    DbEntityEntry dbEntry = dbContext.Entry(entity);
                    SetValues(dbEntry, entry, entityType);
                }
                else
                {
                    throw new NotSupportedException(Resources.DataModificationMustBeCUD);
                }

                entry.Entity = entity;
            }
        }
Esempio n. 23
0
        public async Task ComplexTypeUpdate()
        {
            // Arrange
            var libraryDomain = new LibraryDomain();
            var entry = new DataModificationEntry(
                "Readers",
                "Person",
                new Dictionary<string, object> { { "Id", new Guid("53162782-EA1B-4712-AF26-8AA1D2AC0461") } },
                new Dictionary<string, object>(),
                new Dictionary<string, object> { { "Addr", new Dictionary<string, object> { { "Zip", "332" } } } });
            var changeSet = new ChangeSet(new[] { entry });
            var sc = new SubmitContext(libraryDomain.Context, changeSet);

            // Act
            await ChangeSetPreparer.Instance.PrepareAsync(sc, CancellationToken.None);
            var person = entry.Entity as Person;

            // Assert
            Assert.NotNull(person);
            Assert.Equal("332", person.Addr.Zip);
        }
Esempio n. 24
0
        private static async Task InvokeAuthorizers(
            SubmitContext context,
            IEnumerable <ChangeSetItem> changeSetItems,
            CancellationToken cancellationToken)
        {
            var authorizer = context.GetApiService <IChangeSetItemAuthorizer>();

            if (authorizer == null)
            {
                return;
            }

            foreach (ChangeSetItem item in changeSetItems.Where(i => i.HasChanged()))
            {
                if (!await authorizer.AuthorizeAsync(context, item, cancellationToken))
                {
                    var message = DefaultSubmitHandler.GetAuthorizeFailedMessage(item);
                    throw new SecurityException(message);
                }
            }
        }
Esempio n. 25
0
        private static async Task PerformValidate(
            SubmitContext context,
            IEnumerable <ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            await InvokeAuthorizers(context, changeSetItems, cancellationToken);

            await InvokeValidators(context, changeSetItems, cancellationToken);

            foreach (ChangeSetEntry item in changeSetItems.Where(i => i.HasChanged()))
            {
                if (item.ChangeSetEntityState == DynamicChangeSetEntityState.ChangedWithinOwnPreEventing)
                {
                    item.ChangeSetEntityState = DynamicChangeSetEntityState.PreEvented;
                }
                else
                {
                    item.ChangeSetEntityState = DynamicChangeSetEntityState.Validated;
                }
            }
        }
Esempio n. 26
0
        private static async Task PerformPersist(
            SubmitContext context,
            IEnumerable <ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            // Once the change is persisted, the EntityState is lost.
            // In order to invoke the correct post-CUD event, remember which action was performed on the entity.
            foreach (ChangeSetEntry item in changeSetItems)
            {
                if (item.Type == ChangeSetEntryType.DataModification)
                {
                    DataModificationEntry dataModification = (DataModificationEntry)item;
                    if (dataModification.IsNew)
                    {
                        dataModification.AddAction = AddAction.Inserting;
                    }
                    else if (dataModification.IsUpdate)
                    {
                        dataModification.AddAction = AddAction.Updating;
                    }
                    else if (dataModification.IsDelete)
                    {
                        dataModification.AddAction = AddAction.Removing;
                    }
                }
            }

            var executor = context.GetHookHandler <ISubmitExecutor>();

            if (executor == null)
            {
                throw new NotSupportedException(Resources.SubmitExecutorMissing);
            }

            context.Result = await executor.ExecuteSubmitAsync(context, cancellationToken);
        }
Esempio n. 27
0
        private static async Task InvokeValidators(
            SubmitContext context,
            IEnumerable<ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            ValidationResults validationResults = new ValidationResults();

            foreach (ChangeSetEntry entry in changeSetItems.Where(i => i.HasChanged()))
            {
                foreach (var validator in context
                    .GetHookPoints<IChangeSetEntryValidator>().Reverse())
                {
                    await validator.ValidateEntityAsync(context, entry, validationResults, cancellationToken);
                }
            }

            if (validationResults.HasErrors)
            {
                string validationErrorMessage = Resources.ValidationFailsTheOperation;
                throw new ValidationException(validationErrorMessage)
                {
                    ValidationResults = validationResults.Errors
                };
            }
        }
Esempio n. 28
0
        private static async Task InvokeAuthorizers(
            SubmitContext context,
            IEnumerable<ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            foreach (ChangeSetEntry entry in changeSetItems.Where(i => i.HasChanged()))
            {
                string message = null;

                foreach (var authorizer in context
                    .GetHookPoints<IChangeSetEntryAuthorizer>().Reverse())
                {
                    if (!await authorizer.AuthorizeAsync(context, entry, cancellationToken))
                    {
                        message = DefaultSubmitHandler.GetAuthorizeFailedMessage(entry);
                        break;
                    }
                }

                if (message != null)
                {
                    throw new SecurityException(message);
                }
            }
        }
Esempio n. 29
0
        private static async Task PerformValidate(
            SubmitContext context,
            IEnumerable<ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            await InvokeAuthorizers(context, changeSetItems, cancellationToken);

            await InvokeValidators(context, changeSetItems, cancellationToken);

            foreach (ChangeSetEntry item in changeSetItems.Where(i => i.HasChanged()))
            {
                if (item.ChangeSetEntityState == DynamicChangeSetEntityState.ChangedWithinOwnPreEventing)
                {
                    item.ChangeSetEntityState = DynamicChangeSetEntityState.PreEvented;
                }
                else
                {
                    item.ChangeSetEntityState = DynamicChangeSetEntityState.Validated;
                }
            }
        }
 public Task OnChangeSetItemProcessingAsync(SubmitContext context, ChangeSetItem item, CancellationToken cancellationToken)
 {
     return Inner.OnChangeSetItemProcessingAsync(context, item, cancellationToken);
 }
Esempio n. 31
0
        /// <summary>
        /// Asynchronously executes the submit flow.
        /// </summary>
        /// <param name="context">
        /// The submit context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is a submit result.
        /// </returns>
        public async Task <SubmitResult> SubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");

            var preparer = context.GetHookPoint <IChangeSetPreparer>();

            if (preparer == null)
            {
                throw new NotSupportedException();
            }

            await preparer.PrepareAsync(context, cancellationToken);

            // authorize
            var authorized = true;

            foreach (var authorizer in context
                     .GetHookPoints <ISubmitAuthorizer>().Reverse())
            {
                authorized = await authorizer.AuthorizeAsync(
                    context, cancellationToken);

                if (!authorized || context.Result != null)
                {
                    break;
                }
            }

            if (!authorized)
            {
                // TODO GitHubIssue#32 : Figure out a more appropriate exception
                throw new SecurityException();
            }

            if (context.Result != null)
            {
                return(context.Result);
            }

            ChangeSet eventsChangeSet = context.ChangeSet;

            IEnumerable <ChangeSetEntry> currentChangeSetItems;
            int outerLoopCount = 0;

            do
            {
                outerLoopCount++;
                int innerLoopCount = 0;
                do
                {
                    innerLoopCount++;
                    eventsChangeSet.AnEntityHasChanged = false;
                    currentChangeSetItems = eventsChangeSet.Entries.ToArray();

                    if (eventsChangeSet.AnEntityHasChanged)
                    {
                        eventsChangeSet.AnEntityHasChanged = false;
                        currentChangeSetItems = eventsChangeSet.Entries.ToArray();
                    }

                    await PerformValidate(context, currentChangeSetItems, cancellationToken);

                    await PerformPreEvent(context, currentChangeSetItems, cancellationToken);
                }while (eventsChangeSet.AnEntityHasChanged && (innerLoopCount < MaxLoop));

                VerifyNoEntityHasChanged(eventsChangeSet);

                await PerformPersist(context, currentChangeSetItems, cancellationToken);

                eventsChangeSet.Entries.Clear();

                await PerformPostEvent(context, currentChangeSetItems, cancellationToken);
            }while (eventsChangeSet.AnEntityHasChanged && (outerLoopCount < MaxLoop));

            VerifyNoEntityHasChanged(eventsChangeSet);

            return(context.Result);
        }
Esempio n. 32
0
 private static async Task PerformPostEvent(
     SubmitContext context,
     IEnumerable<ChangeSetEntry> changeSetItems,
     CancellationToken cancellationToken)
 {
     foreach (ChangeSetEntry entry in changeSetItems)
     {
         foreach (var filter in context.GetHookPoints<IChangeSetEntryFilter>())
         {
             await filter.OnExecutedEntryAsync(context, entry, cancellationToken);
         }
     }
 }
Esempio n. 33
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="context"></param>
 /// <param name="cancellationToken"></param>
 /// <returns></returns>
 public virtual Task InitializeAsync(SubmitContext context, CancellationToken cancellationToken)
 {
     Ensure.NotNull(context, nameof(context));
     context.ChangeSet = new ChangeSet();
     return(Task.FromResult(0));
 }
        private Task InvokeProcessorMethodAsync(
            SubmitContext context,
            ChangeSetItem item,
            string methodNameSuffix)
        {
            string methodName = GetMethodName(item, methodNameSuffix);
            object[] parameters = GetParameters(item);

            MethodInfo method = this.targetType.GetQualifiedMethod(methodName);

            if (method != null &&
                (method.ReturnType == typeof(void) ||
                typeof(Task).IsAssignableFrom(method.ReturnType)))
            {
                object target = null;
                if (!method.IsStatic)
                {
                    target = context.GetApiService<ApiBase>();
                    if (target == null ||
                        !this.targetType.IsInstanceOfType(target))
                    {
                        return Task.WhenAll();
                    }
                }

                ParameterInfo[] methodParameters = method.GetParameters();
                if (ParametersMatch(methodParameters, parameters))
                {
                    object result = method.Invoke(target, parameters);
                    Task resultTask = result as Task;
                    if (resultTask != null)
                    {
                        return resultTask;
                    }
                }
            }

            return Task.WhenAll();
        }
Esempio n. 35
0
 private static async Task PerformPostEvent(
     SubmitContext context,
     IEnumerable<ChangeSetEntry> changeSetItems,
     CancellationToken cancellationToken)
 {
     foreach (ChangeSetEntry entry in changeSetItems)
     {
         var filter = context.GetApiService<IChangeSetEntryFilter>();
         if (filter != null)
         {
             await filter.OnExecutedEntryAsync(context, entry, cancellationToken);
         }
     }
 }
Esempio n. 36
0
        private static async Task InvokeAuthorizers(
            SubmitContext context,
            IEnumerable<ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            var authorizer = context.GetApiService<IChangeSetEntryAuthorizer>();
            if (authorizer == null)
            {
                return;
            }

            foreach (ChangeSetEntry entry in changeSetItems.Where(i => i.HasChanged()))
            {
                if (!await authorizer.AuthorizeAsync(context, entry, cancellationToken))
                {
                    var message = DefaultSubmitHandler.GetAuthorizeFailedMessage(entry);
                    throw new SecurityException(message);
                }
            }
        }
Esempio n. 37
0
        private static async Task PerformPreEvent(
            SubmitContext context,
            IEnumerable<ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            foreach (ChangeSetEntry entry in changeSetItems)
            {
                if (entry.ChangeSetEntityState == DynamicChangeSetEntityState.Validated)
                {
                    entry.ChangeSetEntityState = DynamicChangeSetEntityState.PreEventing;

                    foreach (var filter in context
                        .GetHookPoints<IChangeSetEntryFilter>().Reverse())
                    {
                        await filter.OnExecutingEntryAsync(context, entry, cancellationToken);
                    }

                    if (entry.ChangeSetEntityState == DynamicChangeSetEntityState.PreEventing)
                    {
                        // if the state is still the intermediate state,
                        // the entity was not changed during processing
                        // and can move to the next step
                        entry.ChangeSetEntityState = DynamicChangeSetEntityState.PreEvented;
                    }
                    else if (entry.ChangeSetEntityState == DynamicChangeSetEntityState.Changed /*&&
                        entity.Details.EntityState == originalEntityState*/)
                    {
                        entry.ChangeSetEntityState = DynamicChangeSetEntityState.ChangedWithinOwnPreEventing;
                    }
                }
            }
        }
Esempio n. 38
0
        private static async Task PerformPersist(
            SubmitContext context,
            IEnumerable<ChangeSetEntry> changeSetItems,
            CancellationToken cancellationToken)
        {
            // Once the change is persisted, the EntityState is lost.
            // In order to invoke the correct post-CUD event, remember which action was performed on the entity.
            foreach (ChangeSetEntry item in changeSetItems)
            {
                if (item.Type == ChangeSetEntryType.DataModification)
                {
                    DataModificationEntry dataModification = (DataModificationEntry)item;
                    if (dataModification.IsNew)
                    {
                        dataModification.AddAction = AddAction.Inserting;
                    }
                    else if (dataModification.IsUpdate)
                    {
                        dataModification.AddAction = AddAction.Updating;
                    }
                    else if (dataModification.IsDelete)
                    {
                        dataModification.AddAction = AddAction.Removing;
                    }
                }
            }

            var executor = context.GetHookPoint<ISubmitExecutor>();
            if (executor == null)
            {
                throw new NotSupportedException();
            }

            context.Result = await executor.ExecuteSubmitAsync(context, cancellationToken);
        }
        private static async Task<object> FindResource(
            SubmitContext context,
            DataModificationItem item,
            CancellationToken cancellationToken)
        {
            IQueryable query = context.ApiContext.GetQueryableSource(item.ResourceSetName);
            query = item.ApplyTo(query);

            QueryResult result = await context.ApiContext.QueryAsync(new QueryRequest(query), cancellationToken);

            object resource = result.Results.SingleOrDefault();
            if (resource == null)
            {
                throw new ResourceNotFoundException(Resources.ResourceNotFound);
            }

            // This means no If-Match or If-None-Match header
            if (item.OriginalValues == null || item.OriginalValues.Count == 0)
            {
                return resource;
            }

            resource = item.ValidateEtag(result.Results.AsQueryable());
            return resource;
        }
Esempio n. 40
0
        /// <summary>
        /// Asynchronously executes the submit flow.
        /// </summary>
        /// <param name="context">
        /// The submit context.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token.
        /// </param>
        /// <returns>
        /// A task that represents the asynchronous
        /// operation whose result is a submit result.
        /// </returns>
        public async Task<SubmitResult> SubmitAsync(
            SubmitContext context, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, "context");

            var preparer = context.GetHookPoint<IChangeSetPreparer>();
            if (preparer == null)
            {
                throw new NotSupportedException();
            }

            await preparer.PrepareAsync(context, cancellationToken);

            // authorize
            var authorized = true;
            foreach (var authorizer in context
                .GetHookPoints<ISubmitAuthorizer>().Reverse())
            {
                authorized = await authorizer.AuthorizeAsync(
                    context, cancellationToken);
                if (!authorized || context.Result != null)
                {
                    break;
                }
            }

            if (!authorized)
            {
                // TODO GitHubIssue#32 : Figure out a more appropriate exception
                throw new SecurityException();
            }

            if (context.Result != null)
            {
                return context.Result;
            }

            ChangeSet eventsChangeSet = context.ChangeSet;

            IEnumerable<ChangeSetEntry> currentChangeSetItems;
            int outerLoopCount = 0;

            do
            {
                outerLoopCount++;
                int innerLoopCount = 0;
                do
                {
                    innerLoopCount++;
                    eventsChangeSet.AnEntityHasChanged = false;
                    currentChangeSetItems = eventsChangeSet.Entries.ToArray();

                    if (eventsChangeSet.AnEntityHasChanged)
                    {
                        eventsChangeSet.AnEntityHasChanged = false;
                        currentChangeSetItems = eventsChangeSet.Entries.ToArray();
                    }

                    await PerformValidate(context, currentChangeSetItems, cancellationToken);

                    await PerformPreEvent(context, currentChangeSetItems, cancellationToken);
                }
                while (eventsChangeSet.AnEntityHasChanged && (innerLoopCount < MaxLoop));

                VerifyNoEntityHasChanged(eventsChangeSet);

                await PerformPersist(context, currentChangeSetItems, cancellationToken);

                eventsChangeSet.Entries.Clear();

                await PerformPostEvent(context, currentChangeSetItems, cancellationToken);
            }
            while (eventsChangeSet.AnEntityHasChanged && (outerLoopCount < MaxLoop));

            VerifyNoEntityHasChanged(eventsChangeSet);

            return context.Result;
        }
Esempio n. 41
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="context"></param>
 /// <param name="cancellationToken"></param>
 /// <returns></returns>
 public virtual Task <SubmitResult> ExecuteSubmitAsync(SubmitContext context, CancellationToken cancellationToken)
 {
     Ensure.NotNull(context, nameof(context));
     return(Task.FromResult(new SubmitResult(context.ChangeSet)));
 }
Esempio n. 42
0
 public Task<SubmitResult> ExecuteSubmitAsync(SubmitContext context, CancellationToken cancellationToken)
 {
     return Task.FromResult(new SubmitResult(context.ChangeSet));
 }
Esempio n. 43
0
 private async Task PerformPersist(SubmitContext context, CancellationToken cancellationToken)
 {
     context.Result = await executor.ExecuteSubmitAsync(context, cancellationToken).ConfigureAwait(false);
 }