/// <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));
        }
        /// <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     = targetApiType.GetQualifiedMethod(expectedMethodName);

            if (expectedMethod == null)
            {
                var actualMethodName = expectedMethodName.Replace(dataModification.ExpectedResourceType.Name, dataModification.ResourceSetName);
                var actualMethod     = targetApiType.GetQualifiedMethod(actualMethodName);
                if (actualMethod != null)
                {
                    Trace.WriteLine($"Restier Filter expected'{expectedMethodName}' but found '{actualMethodName}'. Your method will not be called until you correct the method name.");
                }

                return(Task.CompletedTask);
            }

            if (!expectedMethod.IsFamily && !expectedMethod.IsFamilyOrAssembly)
            {
                Trace.WriteLine($"Restier Filter found '{expectedMethod}' but it is inaccessible due to its protection level. Your method will not be called until you change it to 'protected internal'.");
                return(Task.CompletedTask);
            }

            if (expectedMethod.ReturnType != typeof(void) && !typeof(Task).IsAssignableFrom(expectedMethod.ReturnType))
            {
                Trace.WriteLine($"Restier Filter found '{expectedMethod}' but it does not return void or a Task. Your method will not be called until you correct the return type.");
                return(Task.CompletedTask);
            }

            object target = null;

            if (!expectedMethod.IsStatic)
            {
                target = context.Api;
                if (target == null || !targetApiType.IsInstanceOfType(target))
                {
                    Trace.WriteLine("The Restier API is of the incorrect type.");
                    return(Task.CompletedTask);
                }
            }

            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);
                }
            }

            Trace.WriteLine($"Restier Authorizer found '{expectedMethod}', but it has an incorrect number of arguments or the types don't match. The number of arguments should be 1.");
            return(Task.CompletedTask);
        }
Exemple #3
0
        /// <inheritdoc/>
        public Task <bool> AuthorizeAsync(SubmitContext context, ChangeSetItem item, CancellationToken cancellationToken)
        {
            Ensure.NotNull(context, nameof(context));
            Ensure.NotNull(item, nameof(item));
            var result = true;

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

            if (method == null)
            {
                return(Task.FromResult(result));
            }

            if (!method.IsFamily && !method.IsFamilyOrAssembly)
            {
                Trace.WriteLine($"Restier Authorizer found '{methodName}' but it is unaccessible due to its protection level. Your method will not be called until you change it to 'protected internal'.");
                return(Task.FromResult(result));
            }

            if (method.ReturnType != returnType)
            {
                Trace.WriteLine($"Restier Authorizer found '{methodName}' but it does not return a boolean value. Your method will not be called until you correct the return type.");
                return(Task.FromResult(result));
            }

            object target = null;

            if (!method.IsStatic)
            {
                target = context.Api;
                if (!targetApiType.IsInstanceOfType(target))
                {
                    Trace.WriteLine("The Restier API is of the incorrect type.");
                    return(Task.FromResult(result));
                }
            }

            var parameters = method.GetParameters();

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

            Trace.WriteLine($"Restier Authorizer found '{methodName}', but it has an incorrect number of arguments. The number of arguments should be 0.");
            return(Task.FromResult(result));
        }
        /// <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     = targetApiType.GetQualifiedMethod(expectedMethodName);

            if (!IsUsable(expectedMethod))
            {
                if (expectedMethod != null)
                {
                    Trace.WriteLine($"Restier Filter found '{expectedMethodName}' but it is unaccessible due to its protection level. Your method will not be called until you change it to 'protected internal'.");
                }
                else
                {
                    var actualMethodName = expectedMethodName.Replace(dataModification.ExpectedResourceType.Name, dataModification.ResourceSetName);
                    var actualMethod     = targetApiType.GetQualifiedMethod(actualMethodName);
                    if (actualMethod != null)
                    {
                        Trace.WriteLine($"BREAKING: Restier Filter expected'{expectedMethodName}' but found '{actualMethodName}'. Your method will not be called until you correct the method name.");
                    }
                }
            }
            else
            {
                object target = null;
                if (!expectedMethod.IsStatic)
                {
                    target = context.Api;
                    if (target == null || !targetApiType.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());
        }
        private Expression AppendOnFilterExpression(QueryExpressionContext context, IEdmEntitySet entitySet, IEdmEntityType entityType)
        {
            var expectedMethodName = ConventionBasedMethodNameFactory.GetEntitySetMethodName(entitySet, RestierPipelineState.Submit, RestierEntitySetOperation.Filter);
            var expectedMethod     = targetType.GetQualifiedMethod(expectedMethodName);

            if (expectedMethod == null || (!expectedMethod.IsFamily && !expectedMethod.IsFamilyOrAssembly))
            {
                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(entitySet.Name, entityType.Name);
                    var actualMethod     = targetType.GetQualifiedMethod(actualMethodName);
                    if (actualMethod != null)
                    {
                        Debug.WriteLine($"BREAKING: Restier Filter expected'{expectedMethodName}' but found '{actualMethodName}'. Please correct the method name.");
                    }
                }
                return(null);
            }

            var parameter = expectedMethod.GetParameters().SingleOrDefault();

            if (parameter == null || parameter.ParameterType != expectedMethod.ReturnType)
            {
                return(null);
            }

            object apiBase = null;

            if (!expectedMethod.IsStatic)
            {
                apiBase = context.QueryContext.Api;
                if (apiBase == null || !targetType.IsInstanceOfType(apiBase))
                {
                    return(null);
                }
            }

            // The LINQ expression built below has three cases
            // For navigation property, just add a where condition from OnFilter method
            // For collection property, will be like "Param_0.Prop.AsQueryable().Where(...)"
            // For collection property of derived type, will be like "Param_0.Prop.AsQueryable().Where(...).OfType()"
            var  returnType = context.VisitedNode.Type.FindGenericType(typeof(IQueryable <>));
            var  enumerableQueryParameter = (object)context.VisitedNode;
            Type elementType = null;

            if (returnType == null)
            {
                // This means append for properties model reference
                var collectionType = context.VisitedNode.Type.FindGenericType(typeof(ICollection <>));
                if (collectionType == null)
                {
                    return(null);
                }

                elementType = collectionType.GetGenericArguments()[0];
                returnType  = typeof(IQueryable <>).MakeGenericType(elementType);

                enumerableQueryParameter = Expression.Call(ExpressionHelperMethods.QueryableAsQueryableGeneric.MakeGenericMethod(elementType), context.VisitedNode);
            }
            else
            {
                elementType = returnType.GetGenericArguments()[0];
            }

            var queryType = typeof(EnumerableQuery <>).MakeGenericType(elementType);
            var query     = Activator.CreateInstance(queryType, enumerableQueryParameter);

            if (!(expectedMethod.Invoke(apiBase, new object[] { query }) is IQueryable result))
            {
                return(null);
            }

            if (expectedMethod.ReturnType == returnType)
            {
                if (result != query)
                {
                    return(result.Expression);
                }
            }
            else
            {
                // This means calling onFilter against derived type and based type is returned
                // Need to convert back to derived type with OfType
                result = ExpressionHelpers.OfType(result, elementType);
                return(result.Expression);
            }

            return(null);
        }