Esempio n. 1
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 InitializeAsync(
            SubmitContext context,
            CancellationToken cancellationToken)
        {
            DbContext dbContext = context.GetApiService <DbContext>();

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

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

                MethodInfo prepareEntryMethod = prepareEntryGeneric.MakeGenericMethod(entityType);

                var task = (Task)prepareEntryMethod.Invoke(
                    obj: null,
                    parameters: new[] { context, dbContext, entry, strongTypedDbSet, cancellationToken });
                await task;
            }
        }
        /// <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. 3
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 override Task <SubmitResult> ExecuteSubmitAsync(SubmitContext context, CancellationToken cancellationToken)
        {
            var dbContext = context.GetApiService <DbContext>();
            await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

            return(await base.ExecuteSubmitAsync(context, cancellationToken).ConfigureAwait(false));
        }
        private static async Task <object> FindResource(
            SubmitContext context,
            DataModificationItem item,
            CancellationToken cancellationToken)
        {
            var        apiBase = context.GetApiService <ApiBase>();
            IQueryable query   = apiBase.GetQueryableSource(item.ResourceSetName);

            query = item.ApplyTo(query);

            QueryResult result = await apiBase.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. 5
0
        /// <summary>
        /// Processes any potential soft-deletes and saves the changes to the resulting database.
        /// </summary>
        /// <param name="context">The <see cref="SubmitContext"/> to be processed.</param>
        /// <param name="cancellationToken">The Task's <see cref="CancellationToken"/>.</param>
        /// <returns></returns>
        public async Task <SubmitResult> ExecuteSubmitAsync(SubmitContext context, CancellationToken cancellationToken)
        {
            var dbContext = context.GetApiService <DbContext>();

            if (!string.IsNullOrWhiteSpace(AdminRole))
            {
                if (ClaimsPrincipal.Current.IsInRole(AdminRole))
                {
                    // If you're an admin, you can hard delete. If you need to soft-delete as an admin,
                    // you should change the Delete property yourself and update instead of delete.
                    return(await SaveChanges(dbContext, context.ChangeSet, cancellationToken));
                }
            }

            foreach (var entry in context.ChangeSet.Entries)
            {
                // Are we deleting something?
                if (entry is DataModificationItem item && item.EntitySetOperation == RestierEntitySetOperations.Delete)
                {
                    var entity          = item.Resource;
                    var deletedProperty = entity.GetType().GetProperties().FirstOrDefault(p => p.Name == SoftDeletePropertyName);

                    // If Entity has the configured Deleted property, set value to True and update EntityState to Modified instead of Deleted
                    if (deletedProperty != null)
                    {
                        deletedProperty.SetValue(entity, true);
                        dbContext.Entry(entity).State = EntityState.Modified;
                    }
                }
            }

            return(await SaveChanges(dbContext, context.ChangeSet, cancellationToken));
        }
        /// <inheritdoc/>
        public Task <bool> AuthorizeAsync(SubmitContext context, ChangeSetItem item, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, nameof(context));
            var result = true;

            var returnType       = typeof(bool);
            var dataModification = (DataModificationItem)item;
            var methodName       = ConventionBasedMethodNameFactory.GetEntitySetMethodName(dataModification, RestierPipelineState.Authorization);
            var method           = targetType.GetQualifiedMethod(methodName);

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

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

            return(Task.FromResult(result));
        }
Esempio n. 7
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. 8
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 InitializeAsync(SubmitContext context, CancellationToken cancellationToken)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var dbContext = context.GetApiService <DbContext>();

            foreach (var entry in context.ChangeSet.Entries.OfType <DataModificationItem>())
            {
                var strongTypedDbSet = dbContext.GetType().GetProperty(entry.ResourceSetName).GetValue(dbContext);
                var 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;
                }

                var set = dbContext.Set(resourceType);

                object resource;

                if (entry.EntitySetOperation == RestierEntitySetOperation.Insert)
                {
                    resource = set.Create();
                    SetValues(resource, resourceType, entry.LocalValues);
                    set.Add(resource);
                }
                else if (entry.EntitySetOperation == RestierEntitySetOperation.Delete)
                {
                    resource = await FindResource(context, entry, cancellationToken).ConfigureAwait(false);

                    set.Remove(resource);
                }
                else if (entry.EntitySetOperation == RestierEntitySetOperation.Update)
                {
                    resource = await FindResource(context, entry, cancellationToken).ConfigureAwait(false);

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

                entry.Resource = resource;
            }
        }
Esempio n. 9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        /// <param name="item"></param>
        /// <param name="pipelineState"></param>
        /// <returns></returns>
        private Task InvokeProcessorMethodAsync(SubmitContext context, ChangeSetItem item, RestierPipelineState pipelineState)
        {
            var dataModification   = (DataModificationItem)item;
            var expectedMethodName = ConventionBasedMethodNameFactory.GetEntitySetMethodName(dataModification, pipelineState);
            var expectedMethod     = targetType.GetQualifiedMethod(expectedMethodName);

            if (!IsUsable(expectedMethod))
            {
                if (expectedMethod != null)
                {
                    Debug.WriteLine($"Restier Filter found '{expectedMethodName}' but it is unaccessible due to its protection level. Change it to be 'protected internal'.");
                }
                else
                {
                    var actualMethodName = expectedMethodName.Replace(dataModification.ExpectedResourceType.Name, dataModification.ResourceSetName);
                    var actualMethod     = targetType.GetQualifiedMethod(actualMethodName);
                    if (actualMethod != null)
                    {
                        Debug.WriteLine($"BREAKING: Restier Filter expected'{expectedMethodName}' but found '{actualMethodName}'. Please correct the method name.");
                    }
                }
            }
            else
            {
                object target = null;
                if (!expectedMethod.IsStatic)
                {
                    target = context.GetApiService <ApiBase>();
                    if (target == null || !targetType.IsInstanceOfType(target))
                    {
                        return(Task.WhenAll());
                    }
                }

                var parameters       = GetParameters(item);
                var methodParameters = expectedMethod.GetParameters();
                if (ParametersMatch(methodParameters, parameters))
                {
                    var result = expectedMethod.Invoke(target, parameters);
                    if (result is Task resultTask)
                    {
                        return(resultTask);
                    }
                }
            }

            return(Task.WhenAll());
        }
Esempio n. 10
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.GetApiService <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];
                MethodInfo prepareEntryMethod = prepareEntryGeneric.MakeGenericMethod(entityType);

                var task = (Task)prepareEntryMethod.Invoke(
                    obj: null,
                    parameters: new[] { context, dbContext, entry, strongTypedDbSet, cancellationToken });
                await task;
            }
        }
        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());
        }
        private Task InvokeFilterMethodAsync(
            SubmitContext context,
            ChangeSetEntry entry,
            string methodNameSuffix)
        {
            string methodName = ConventionBasedChangeSetEntryFilter.GetMethodName(entry, methodNameSuffix);

            object[] parameters = ConventionBasedChangeSetEntryFilter.GetParameters(entry);

            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.IsAssignableFrom(target.GetType()))
                    {
                        return(Task.WhenAll());
                    }
                }

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

            return(Task.WhenAll());
        }
Esempio n. 13
0
        public Task InitializeAsync(SubmitContext context, CancellationToken cancellationToken)
        {
            var key = InMemoryProviderUtils.GetSessionId();
            var dataStoreManager = context.GetApiService <IDataStoreManager <string, TDataStoreType> >();

            if (dataStoreManager == null)
            {
                throw new ArgumentNullException(Resources.DataStoreManagerNotFound,
                                                typeof(IDataStoreManager <string, TDataStoreType>).ToString());
            }

            var dataSource = dataStoreManager.GetDataStoreInstance(key);

            foreach (var dataModificationItem in context.ChangeSet.Entries.OfType <DataModificationItem>())
            {
                var resourceType = dataModificationItem.ExpectedResourceType;
                if (dataModificationItem.ActualResourceType != null &&
                    dataModificationItem.ActualResourceType != dataModificationItem.ExpectedResourceType)
                {
                    resourceType = dataModificationItem.ActualResourceType;
                }

                var    operation = dataModificationItem.DataModificationItemAction;
                object resource  = null;
                switch (operation)
                {
                case DataModificationItemAction.Insert:
                    // Here we create a instance of entity, parameters are from the request.
                    // Known issues: not support odata.id
                    resource = Activator.CreateInstance(resourceType);
                    SetValues(resource, resourceType, dataModificationItem.LocalValues);
                    dataModificationItem.Resource = resource;

                    // insert new entity into entity set
                    var entitySetPropForInsert = GetEntitySetPropertyInfoFromDataModificationItem(dataSource,
                                                                                                  dataModificationItem);

                    if (entitySetPropForInsert != null && entitySetPropForInsert.CanWrite)
                    {
                        var originSet = entitySetPropForInsert.GetValue(dataSource);
                        entitySetPropForInsert.PropertyType.GetMethod("Add").Invoke(originSet, new[] { resource });
                    }
                    break;

                case DataModificationItemAction.Update:
                    resource = FindResource(dataSource, context, dataModificationItem, cancellationToken);
                    dataModificationItem.Resource = resource;

                    // update the entity
                    if (resource != null)
                    {
                        SetValues(resource, resourceType, dataModificationItem.LocalValues);
                    }
                    break;

                case DataModificationItemAction.Remove:
                    resource = FindResource(dataSource, context, dataModificationItem, cancellationToken);
                    dataModificationItem.Resource = resource;

                    // remove the entity
                    if (resource != null)
                    {
                        var entitySetPropForRemove = GetEntitySetPropertyInfoFromDataModificationItem(dataSource,
                                                                                                      dataModificationItem);

                        if (entitySetPropForRemove != null && entitySetPropForRemove.CanWrite)
                        {
                            var originSet = entitySetPropForRemove.GetValue(dataSource);
                            entitySetPropForRemove.PropertyType.GetMethod("Remove").Invoke(originSet, new[] { resource });
                        }
                    }
                    break;

                case DataModificationItemAction.Undefined:
                    throw new NotImplementedException();
                }
            }

            return(Task.WhenAll());
        }