无法使$filter与WCF数据服务中的打开类型一起工作

无法使$filter与WCF数据服务中的打开类型一起工作,wcf,odata,Wcf,Odata,我正在WCF中构建一个数据服务,我使用反射和开放类型的组合,因为一些数据元素需要动态创建。大多数情况下一切都很好,但我无法让过滤器处理开放类型值 我得到的错误是: <message xml:lang="en-US">An error occurred while processing this request.</message> <innererror> <message>The method or operation is no

我正在WCF中构建一个数据服务,我使用反射和开放类型的组合,因为一些数据元素需要动态创建。大多数情况下一切都很好,但我无法让过滤器处理开放类型值

我得到的错误是:

  <message xml:lang="en-US">An error occurred while processing this request.</message>
  <innererror>
    <message>The method or operation is not implemented.</message>
    <type>System.NotImplementedException</type>
    <stacktrace>   at lambda_method(Closure , GeographyProvider )&#xD;
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()&#xD;
   at System.Data.Services.DataService`1.SerializeResponseBody(RequestDescription description, IDataService dataService)&#xD;
   at System.Data.Services.DataService`1.HandleRequest()</stacktrace>
  </innererror>
我正在使用一个表达式访问者重写LINQ表达式,它成功地提取了开放类型的值。此时,我不确定需要实现什么方法或操作。表达式访问者完成其工作后,表达式树如下所示:

Alteryx.Web.API.DatasetProvider+<GetDatasets>d__0.Where(element => 
(element.Variant == "AGSSTD_701000")).SelectMany(element => 
    ConvertChecked(element.Geographies)).Where(element => 
        (element.Key == "County")).SelectMany(element => 
            ConvertChecked(element.Geographies)).Where(element => 
                (element.Key == "36")).SelectMany(element => 
                    ConvertChecked(element.Geographies)).Where(it => 
                        Convert(((Invoke((o, name) => GetOpenValue(o, name), it, "POPCY") >= Convert(100000)) == True)))}
我在GetOpenValue方法中设置了一个断点,它被调用并返回正确的值。你有没有想过我该从这里走到哪里

根据Vitek的建议,我在expression visitor中添加了转换和比较方法的检查,但没有找到它们。以下是我的访客代码:

    static readonly MethodInfo GetValueOpenPropertyMethodInfo =
        typeof(OpenTypeMethods)
        .GetMethod(
            "GetValue",
            BindingFlags.Static | BindingFlags.Public,
            null,
            new Type[] { typeof(object), typeof(string) },
            null
        );

    static readonly MethodInfo OpenConvertMethodInfo =
        typeof(OpenTypeMethods)
        .GetMethod(
            "Convert",
            BindingFlags.Static | BindingFlags.Public,
            null,
            new Type[] { typeof(object), typeof(ResourceType) },
            null
        );

    static readonly MethodInfo GreaterThanOrEqualMethodInfo =
        typeof(OpenTypeMethods)
        .GetMethod(
            "GreaterThanOrEqual",
            BindingFlags.Static | BindingFlags.Public,
            null,
            new Type[] { typeof(object), typeof(object) },
            null
        );

    static readonly MethodInfo EqualMethodInfo =
        typeof(OpenTypeMethods)
        .GetMethod(
            "Equal",
            BindingFlags.Static | BindingFlags.Public,
            null,
            new Type[] { typeof(object), typeof(object) },
            null
        );

        static readonly Expression<Func<object, string, object>> GetValueOpenReplacement =
        (o, name) => GetOpenValue(o, name);


    static object GetOpenValue(object o, string name)
    {
        return (o as OpenDataProvider).GetValue(name);
    }

        static readonly Expression<Func<object, object, object>> GetGreaterThanOrEqualReplacement =
        (left, right) => GetOpenGreaterThanOrEqual(left, right);


    static object GetOpenGreaterThanOrEqual(object left, object right)
    {
        string s = left.ToString();
        return true;
    }

        static readonly Expression<Func<object, object, object>> GetEqualReplacement =
        (left, right) => GetOpenEqual(left, right);


    static object GetOpenEqual(object left, object right)
    {
        string s = left.ToString();
        return true;
    }

    protected override Expression VisitMethodCall(
        MethodCallExpression node
    )
    {
        if (node.Method == GetValueOpenPropertyMethodInfo)
        {
            // Arguments[0] - the resource to get property from 
            // Arguments[1] - the ResourceProperty to get 
            // Invoke the replacement expression, passing the 
            // appropriate parameters. 

            if (node.Arguments[0].Type.BaseType == typeof(OpenDataProvider))
            {
                OpenDataProvider.RequestValue(((ConstantExpression)node.Arguments[1]).Value.ToString());
            }

            return Expression.Invoke(
               Expression.Quote(GetValueOpenReplacement),
               node.Arguments[0],
               node.Arguments[1]
            );
        }
        else if (node.Method == OpenConvertMethodInfo)
        {
            // Arguments[0] – the resource 
            // Arguments[1] – the ResourceType 
            // no need to do anything, so just 
            // return the argument 
            return this.Visit(node.Arguments[0]);
        }
        else if (node.Method == GreaterThanOrEqualMethodInfo)
        {
            // Invoke the replacement expression, passing the 
            // appropriate parameters. 

            return Expression.Invoke(
               Expression.Quote(GetGreaterThanOrEqualReplacement),
               node.Arguments[0],
               node.Arguments[1]
            );
        }
        else if (node.Method == EqualMethodInfo)
        {
            // Invoke the replacement expression, passing the 
            // appropriate parameters. 

            return Expression.Invoke(
               Expression.Quote(GetEqualReplacement),
               node.Arguments[0],
               node.Arguments[1]
            );
        }

        return base.VisitMethodCall(node);
    }
我在VisitMethodCall方法中的所有if块中都设置了断点,但只调用了GetValueOpenProperty块


谢谢

Vitek在此提供了答案:

总之,ExpressionVisitor需要覆盖VisitBinary方法中的OpenTypeMethods


谢谢你的帮助,维泰克

您是否尝试在异常时在调试器中停止并在调试器中捕获该异常?也许它会向你展示更多。综上所述,假设您的GetOpenValue实现按预期工作,并且您确实替换了Visitor中对OpenTypeMethods.GetValue的所有调用,我看不出有任何错误。事实上,一个想法是,转换或比较运算符也可以表示为对OpenTypeMethods的调用,你确定你没有把那些留在树上吗?嗨,维泰克。谢谢你的回复。我尝试过使用调试器,但是异常并没有停止执行,即使我请求在抛出异常时中断。我曾尝试在OpenTypeMethods上替换Convert和GreaterThanOrEqual方法,但两种方法似乎都没有被调用。也许我对它们的定义是错误的。如果ExpressionVisitor代码仍然不起作用,我会再试一次,并发布我的ExpressionVisitor代码。在上面添加了更多详细信息-谢谢!我还不知道失败的原因,只是上面代码风格的一个注释:为什么要使用Invoke和funcs?这看起来太复杂了。难道不是一个简单的表达式。调用就足够了吗?虽然它不应该改变功能。