无法使$filter与WCF数据服务中的打开类型一起工作
我正在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
<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 )
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
at System.Data.Services.DataService`1.SerializeResponseBody(RequestDescription description, IDataService dataService)
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?这看起来太复杂了。难道不是一个简单的表达式。调用就足够了吗?虽然它不应该改变功能。