Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.NotSupportedException when calling OData service from NetCoreApp2.1

I have set up a multi targetting (net4.5.2/netstandard2) class library allowing to consume one of our enterprise OData services. To access this OData service we use a proxy class generated with the OData v4 Client Code Generator (v7.5.0)

Unfortunately, when trying to use my library in a Netcoreapp2.1 application I encounter an issue as soon as I try to enumerate a collection.

Container.MyDataSet.ToList(); produces the following exception :

"System.NotSupportedException : This target framework does not enable you to directly enumerate over a data service query. This is because enumeration automatically sends a synchronous request to the data service. Because this framework only supports asynchronous operations, you must instead call the BeginExecute and EndExecute methods to obtain a query result that supports enumeration."

I do not encounter this issue when using this same multitarget library in a .Net 4.5.2 application.

Having a look at the Microsoft.OData.Client v7.5.0 source code, this behaviour seems to be by design with specific handling of the .Net Core case.

Did I miss something ?

The following code prevents the issue, but it is barely usable :

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;

How can I use an OData IQueryable in .Net Core application without adding specific code ?

like image 308
jbl Avatar asked Sep 05 '25 03:09

jbl


1 Answers

As mentioned in the error message, the platform only supports asynchronous fetches. Even after you use that, you will likely need to enumerate over the results multiple times -- everytime you perform a ToList(), FirstOrDefault() or other similar System.Generics.Collections operations, you are essentially getting the Enumerator of the collection and enumerating over it.

I adopted this solution: immediately after I fetch enumerable results from the OData libraries I enumerate over them and put them in another enumerable container (Dictionary<string, MyAwesomeResult> in this case) instantiated by me.

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);
}

Then I use the container I instantiated -- I no longer need to enumerate again over the enumerable returned by DataServiceQuery<MyAwesomeResult>.ExecuteAsync.

like image 131
Jeetesh Mangwani Avatar answered Sep 07 '25 22:09

Jeetesh Mangwani