首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从NetCoreApp2.1调用OData服务时的OData

从NetCoreApp2.1调用OData服务时的OData
EN

Stack Overflow用户
提问于 2018-10-29 10:55:40
回答 2查看 2.8K关注 0票数 4

我已经设置了一个多targetting (net4.5.2/netstandard2 2)类库,允许使用我们的企业OData服务之一。要访问这个OData服务,我们使用与OData v4客户端代码生成器(v7.5.0)一起生成的代理类

不幸的是,当我试图在Netcoreapp2.1应用程序中使用我的库时,当我试图枚举一个集合时,我就会遇到一个问题。

Container.MyDataSet.ToList();产生以下异常:

"System.NotSupportedException :此目标框架不能使您直接枚举数据服务查询。这是因为枚举会自动向数据服务发送同步请求。由于该框架只支持异步操作,因此必须调用BeginExecute和EndExecute方法来获得支持枚举的查询结果。“

在.Net 4.5.2应用程序中使用相同的多目标库时,我不会遇到这个问题。

查看一下Microsoft.OData.Client v7.5.0源代码,这种行为似乎是通过特定处理.Net核心案例来设计的。

我错过了什么吗?

下面的代码防止了这个问题,但它几乎无法使用:

代码语言:javascript
复制
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;

如何在不添加特定代码的情况下在OData核心应用程序中使用IQueryable?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-11-16 14:07:06

正如@PanagiotisKanavos所说,DataServiceQuery.ToString()将返回OData查询的uri。基于此,我编写了自己的IQueryable

代码语言:javascript
复制
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);
}

其中MyClient是一个实用程序类,它封装一个HttpClient,处理身份验证令牌,并执行结果反序列化。FinalType是跟踪我想要获取和反序列化的类型,因为我正在通过接口处理IQueryables。然后我写了我自己的IQueryProvider

代码语言:javascript
复制
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;

using Microsoft.OData.Client;

public class ODataLinqQueryProvider<T> : IQueryProvider
{
    private MyClient Client { get; set; }

    private DataServiceQuery<T> DataServiceQuery { get; set; }

    private Type FinalType { get; }

    public ODataLinqQueryProvider(
        DataServiceQuery<T> dsq,
        MyClient client,
        Type finalType)
    {
        this.DataServiceQuery = dsq;
        this.Client = client;
        this.FinalType = finalType;
    }

    public IQueryable CreateQuery(Expression expression)
    {
        return new ODataLinqQuery<T>(this.DataServiceQuery, this.Client, this.FinalType);
    }

    public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
    {
        var pro = new DataServiceQuery<TElement>(expression, this.DataServiceQuery.Provider as DataServiceQueryProvider);
        return new ODataLinqQuery<TElement>(pro, this.Client, this.FinalType);
    }

    public object Execute(Expression expression)
    {
        this.DataServiceQuery = new DataServiceQuery<T>(expression, this.DataServiceQuery.Provider as DataServiceQueryProvider);
        return this.Execute();
    }

    public TResult Execute<TResult>(Expression expression)
    {
        this.DataServiceQuery = new DataServiceQuery<T>(expression, this.DataServiceQuery.Provider as DataServiceQueryProvider);
        var res = this.Execute();
        if (typeof(IEnumerable).IsAssignableFrom(typeof(TResult)))
        {
            return (TResult)res;
        }
        else
        {
            return ((IEnumerable)res).Cast<TResult>().FirstOrDefault();
        }
    }

    private object Execute()
    {
        var result = Client.GetResult(typeof(OData<>).MakeGenericType(this.FinalType), HttpMethod.Get, new Uri(this.DataServiceQuery.ToString())) as OData;
        return result.Objects;
    }
}

如果Odata<>类仅用于OData结果的反序列化,而GetResult“只是”使用正确的身份验证头调用其基础HttpClientGetAsync方法,则等待并反序列化结果:

代码语言:javascript
复制
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; }
}

最后,我按以下方式公开了我的IQueryable

代码语言:javascript
复制
var myQueryable = new ODataLinqQuery<MyData>(this.Container.MyDataSet, myclient, typeof(MyData));

然后,我可以应用过滤器、orderby、top和skip,并获得与标准IQueryable一样的结果。我知道这个实现是不完整的,IQueryable到OData并不像大多数IQueryable到SQL那样完整,但是它达到了我所需要的最小值。

票数 0
EN

Stack Overflow用户

发布于 2018-11-13 02:35:02

正如错误消息中提到的,该平台只支持异步获取。即使在使用它之后,您也可能需要多次枚举结果--每次执行ToList()FirstOrDefault()或其他类似的System.Generics.Collections操作时,基本上都是获取集合的Enumerator并对其进行枚举。

我采用了这个解决方案:在从OData库中获取可枚举结果之后,我立即对它们进行枚举,并将它们放在由我实例化的另一个可枚举容器中(在本例中为Dictionary<string, MyAwesomeResult>)。

代码语言:javascript
复制
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);
}

然后,我使用实例化的容器--我不再需要对DataServiceQuery<MyAwesomeResult>.ExecuteAsync返回的枚举进行再次枚举。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53043994

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档