.net core System.NotSupportedException从NetCoreApp2.1调用OData服务时
我已经建立了一个多目标(net4.5.2/netstandard2)类库,允许使用我们的一个企业OData服务。 要访问此OData服务,我们使用 不幸的是,当尝试在Netcoreapp2.1应用程序中使用我的库时,我在尝试枚举集合时遇到了一个问题.net core System.NotSupportedException从NetCoreApp2.1调用OData服务时,.net-core,odata,.net Core,Odata,我已经建立了一个多目标(net4.5.2/netstandard2)类库,允许使用我们的一个企业OData服务。 要访问此OData服务,我们使用 不幸的是,当尝试在Netcoreapp2.1应用程序中使用我的库时,我在尝试枚举集合时遇到了一个问题 Container.MyDataSet.ToList()生成以下异常: “System.NotSupportedException:此目标框架未启用 您需要直接枚举数据服务查询。这是因为 枚举自动向数据发送同步请求 由于此框架仅支持异步操作, 您必须
Container.MyDataSet.ToList()代码>生成以下异常:
“System.NotSupportedException:此目标框架未启用
您需要直接枚举数据服务查询。这是因为
枚举自动向数据发送同步请求
由于此框架仅支持异步操作,
您必须调用BeginExecute和EndExecute方法来
获取支持枚举的查询结果。“
在.Net 4.5.2应用程序中使用相同的多目标库时,我不会遇到此问题
查看一下Microsoft.OData.Client v7.5.0源代码,这种行为似乎是通过对.Net核心案例的特定处理而设计的
我错过什么了吗
以下代码可防止此问题,但几乎不可用:
var query = (DataServiceQuery<MyData>)Container.MyDataSet;
var taskFactory = new TaskFactory<IEnumerable<MyData>>();
var t = taskFactory.FromAsync(query.BeginExecute(null, null), data => query.EndExecute(data));
t.ConfigureAwait(false);
IEnumerable<MyData> result = t.Result;
var query=(DataServiceQuery)Container.MyDataSet;
var taskFactory=new taskFactory();
var t=taskFactory.fromsync(query.BeginExecute(null,null),data=>query.EndExecute(data));
t、 配置等待(false);
IEnumerable result=t.result;
如何在不添加特定代码的情况下在.Net核心应用程序中使用OData IQueryable?如错误消息中所述,平台仅支持异步抓取。即使使用了它,也可能需要多次枚举结果——每次执行ToList()
、FirstOrDefault()
或其他类似的System.Generics.Collections
操作时,基本上都是获取集合的枚举数并对其进行枚举
我采用了这个解决方案:在我从OData库中获取可枚举结果之后,我立即对它们进行枚举,并将它们放在我实例化的另一个可枚举容器中(Dictionary
)
var resultsQuery = this.oDataClient.MyAwesomeResults
.AddQueryOption("$filter", "Name eq 'MyAwesomeName'")
.AddQueryOption("$top", "5")
.AddQueryOption("$skip", "2");
IEnumerable<MyAwesomeResult> resultsRaw = await
resultsQuery.ExecuteAsync();
var results = new Dictionary<string, MyAwesomeResult>();`
foreach (var resultRaw in resultsRaw)
{
results.Add(resultRaw.Key, resultRaw);
}
var resultsQuery=this.oDataClient.MyAwesomeResults
.AddQueryOption(“$filter”,“Name eq'MyAwesomeName'”)
.AddQueryOption(“$top”,“5”)
.AddQueryOption(“$skip”,“2”);
IEnumerable resultsRaw=等待
resultsQuery.ExecuteAsync();
var results=newdictionary()`
foreach(resultsRaw中的var resultRaw)
{
results.Add(resultRaw.Key,resultRaw);
}
然后我使用我实例化的容器——我不再需要再次枚举
DataServiceQuery.ExecuteAsync
正如@PanagiotisKanavosDataServiceQuery.ToString()
所说,将返回OData查询的uri。
基于此,我编写了自己的IQueryable
:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.OData.Client;
public class ODataLinqQuery<T> : IOrderedQueryable<T>
{
public IQueryProvider Provider { get; }
private DataServiceQuery<T> DataServiceQuery { get; }
public ODataLinqQuery(DataServiceQuery<T> dataServiceQuery, MyClient client, Type finalType)
{
this.DataServiceQuery = dataServiceQuery;
this.Provider = new ODataLinqQueryProvider<T>(dataServiceQuery, client, finalType);
}
public IEnumerator<T> GetEnumerator()
{
return this.Provider.Execute<IEnumerable<T>>(this.Expression).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.Provider.Execute<System.Collections.IEnumerable>(this.Expression).GetEnumerator();
}
public Expression Expression => this.DataServiceQuery.Expression;
public Type ElementType => typeof(T);
}
其中,Odata
类仅用于Odata结果的反序列化,GetResult
“just”使用正确的身份验证头调用其底层HttpClient
的GetAsync
方法,等待并反序列化结果:
using System.Collections.Generic;
using Newtonsoft.Json;
public class OData<T> : OData where T : class
{
public override IEnumerable<object> Objects => this.Value;
public List<T> Value { get; set; }
}
public class OData
{
[JsonProperty("@odata.context")]
public string Metadata { get; set; }
public virtual IEnumerable<object> Objects { get; set; }
}
然后我可以应用过滤器、orderby、top和skip,并像使用标准的IQueryable
一样获得结果。我知道这个实现是不完整的,OData的IQueryable
没有SQL的大多数IQueryable
那么完整,但它达到了我需要的最低限度。错误解释了问题所在。您试图将查询转换为列表,而不是结果。OData查询不是在调用ToList()
时执行的EF查询。实际问题似乎是如何在.NET Core中异步进行OData调用,而不是如何使用ToList()
,答案并不简单。说“一团糟”更合适。我可以在源代码中看到一个实际委托给TaskFactory.fromsync
的GetAllPagesAsync
git Turn
显示这是4年前的代码,以这种方式编写到target.NET4.0。可以安全地假设它也不使用HttpClient。您可以尝试其他生成器,或者将查询转换为URL,并使用HttpClient.GetAsync
异步调用它DataServiceQuery.ToString()将返回URI@PanagiotisKanavos我使用ToList()
用一个简单的例子来说明这个问题。你是正确的;它使用和底层HttpWebRequest。我会更精确地回答我的问题,看看我能用Uri实现什么。谢谢。我知道我可以枚举结果,但是如果不可靠的数据源是数千或百万行呢?关键是我不能将其表示为“标准”IQueryable
,我可以在其上透明地应用筛选器、排序、top和skip。您可以在发送OData请求之前使用ExecuteAsync()
。我已经更新了答案来说明这一部分。
using System.Collections.Generic;
using Newtonsoft.Json;
public class OData<T> : OData where T : class
{
public override IEnumerable<object> Objects => this.Value;
public List<T> Value { get; set; }
}
public class OData
{
[JsonProperty("@odata.context")]
public string Metadata { get; set; }
public virtual IEnumerable<object> Objects { get; set; }
}
var myQueryable = new ODataLinqQuery<MyData>(this.Container.MyDataSet, myclient, typeof(MyData));