Example #1
0
        private Expression AppendOnFilterExpression(QueryExpressionContext context, IEdmEntitySet entitySet, IEdmEntityType entityType)
        {
            var expectedMethodName = ConventionBasedMethodNameFactory.GetEntitySetMethodName(entitySet, RestierPipelineState.Submit, RestierEntitySetOperation.Filter);
            var expectedMethod     = targetApiType.GetQualifiedMethod(expectedMethodName);

            if (expectedMethod == null || (!expectedMethod.IsFamily && !expectedMethod.IsFamilyOrAssembly))
            {
                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(entitySet.Name, entityType.Name);
                    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.");
                    }
                }
                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 || !targetApiType.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);
        }