OData / odata.net

ODataLib: Open Data Protocol - .NET Libraries and Frameworks
https://docs.microsoft.com/odata
Other
675 stars 348 forks source link

Bad performance while using OData client vs using HttpClient on Android #3010

Closed marcmognol closed 4 days ago

marcmognol commented 1 week ago

Short summary (3-5 sentences) describing the issue.

I'm in the process to develop an application for my company. This application will connect to OData endpoints. To achieve my goal, I followed the Microsoft documentation https://learn.microsoft.com/en-us/odata/client/getting-started to connect my project to our OData endpoint.

But, I'm experiencing very bad performance while using the application, even in Release mode.

I've got the idea to use classic HttpClient to compare the performance, and HttpClient is 2x faster than OData client.

Assemblies affected

Which assemblies and versions are known to be affected e.g. OData .Net lib 7.x 7.21.3

Reproduce steps

The simplest set of steps to reproduce the issue. If possible, reference a commit that demonstrates the issue.

  1. Clone the reproduction project repository (https://github.com/marcmognol/Maui.OData.PerformanceIssue/)
  2. Run the application with Android emulator (MAUI workload is required)
  3. Click on HttpClient button (multiple times)
  4. Click on ODATA button (multiple times)
  5. Compare request response time

Expected result

What would happen if there wasn't a bug.

Same performance whatever I use HttpClient or OData client.

Actual result

What is actually happening.

341830954-d27cea9a-bf5c-44ab-b4a7-e758e5b2c033

Additional detail

Related to Issue https://github.com/dotnet/maui/issues/23185 Optional, details of the root cause if known. Delete this section if you have no additional details to add.

WanjohiSammy commented 1 week ago

@marcmognol

Modify your codeto the following and compare:

public static async Task<IEnumerable<Person>> GetAsync()
{
    var serviceRoot = "https://services.odata.org/V4/(S(r5behdg3orwkze3bmwcnjwqm))/TripPinServiceRW/";
    var context = new DefaultContainer(new Uri(serviceRoot));

    return await context.People.ExecuteAsync();
    //foreach (var person in people)
    //{
    //    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
    //}
}
marcmognol commented 1 week ago

@WanjohiSammy

Thank you for your support, and suggestion but without the foreach, I can see the same results. Marc

WanjohiSammy commented 1 week ago

@marcmognol

Try foreach in both and compare. It won't be fair to compare one with a loop and the other without. One without loop will be ~O(1) and the other with loop will be ~O(n).

marcmognol commented 1 week ago

@WanjohiSammy Yes you're right. I've tried with foreach on HttpClient as well and I've same performance results.

WanjohiSammy commented 1 week ago

@marcmognol please close the issue if you are queries have been answered.

marcmognol commented 1 week ago

Sorry but when I say "same performance", I am saying that bad performance still happened even with the foreach.

So issue is still there and should be kept opened.

WanjohiSammy commented 1 week ago

@marcmognol I have modified your code a little bit trying to reproduce the perf issue:

http client

public static async Task<ODataResponse?> GetAsync()
{
    var url = "https://services.odata.org/V4/(S(r5behdg3orwkze3bmwcnjwqm))/TripPinServiceRW/People";
    var httpClient = new HttpClient();
    var response = await httpClient.GetFromJsonAsync<ODataResponse>(url);

    if(response?.Value is People[] people)
    {
        foreach (var person in people)
        {
            Console.WriteLine(person.UserName);
        }
    }

    return response;
}

OData Client

public static async Task<IEnumerable<Person>?> GetAsync()
{
    var serviceRoot = "https://services.odata.org/V4/(S(r5behdg3orwkze3bmwcnjwqm))/TripPinServiceRW/";
    var context = new DefaultContainer(new Uri(serviceRoot));

    var people = await context.People.ExecuteAsync();
    if(people != null)
    {
        foreach (var person in people)
        {
            Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
        }
    }

    return people;
}

However, I do not much see difference in terms of perf as shown below:

image

Try update as above and click as many times as possible.

WanjohiSammy commented 1 week ago

@marcmognol

ODL 7.0 ODataClient does not use HttpClient by default. To use httpClient with OData you can do something like this:

context.HttpRequestTransportMode = HttpRequestTransportMode.HttpClient;

var serviceRoot = "https://services.odata.org/V4/(S(r5behdg3orwkze3bmwcnjwqm))/TripPinServiceRW/";
var context = new DefaultContainer(new Uri(serviceRoot));
context.HttpRequestTransportMode = HttpRequestTransportMode.HttpClient;

More about it: HttpRequestTransportMode

marcmognol commented 4 days ago

Hi @WanjohiSammy

Thank you very much, I'll give a try for HttpClient.

Thanks