无法使用$ filter来处理WCF数据服务中的开放类型

时间:2011-05-17 18:32:45

标签: wcf odata

我正在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表达式,并且它成功地提取了open类型的值。在这一点上,我不确定我需要实现什么方法或操作。在表达式访问者完成它的工作之后,表达式树看起来像这样:

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的建议,我将转换和比较方法的检查添加到我的表达式访问者,但找不到它们。以下是我的访问者代码:

    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块。

谢谢!

1 个答案:

答案 0 :(得分:0)

Vitek在这里提供了答案:http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/thread/bfb62cf5-48cc-4435-ae9a-76e4a13d762a

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

感谢你的帮助,Vitek!