contentful / contentful.net

.NET Library for Contentful's Content Delivery and Management API
MIT License
94 stars 55 forks source link

Duplicate entries in a multi reference field are not deserialized properly #356

Closed chamook closed 2 weeks ago

chamook commented 2 weeks ago

I have an entry with a multi reference field that might contain duplicate entries. Newer versions of the library return null for the repeated entries instead of the expected object.

I saw this issue and can get it to work as expected by using 8.0.1

This is my first time working with Contentful, so by all means tell me that I'm holding it wrong if that's the case 😅 but I think the regression between versions hints at it being a real issue and not just me

Test Code:

public sealed record Divider(string Direction);
public sealed record TestPage(IReadOnlyList<dynamic> Components);
public sealed class TestController(
    ILogger<TestController> Logger,
    IContentfulClient ContentfulClient)
    : Controller
{
    [HttpGet("/test-contentful")]
    public async Task<IActionResult> Test()
    {
        Logger.LogInformation("Testing contentful...");
        var results =
            await ContentfulClient.GetEntries<TestPage>(
                queryString: "?content_type=staticPage&fields.slug=test-page&include=2");

        foreach(var result in results)
        {
            foreach(var component in result.Components)
            {
                if(component.sys.contentType.sys.id == "divider")
                {
                    string direction = component.ToObject<Divider>().Direction;
                    Logger.LogInformation("Direction: {direction}", direction);
                }
            }
        }

        return NoContent();
    }
}

Test Results:

8.2.0:

dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5250
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/<redacted>/Frontend.WebApp
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.
info: Frontend.WebApp.Controllers.TestController[0]
      Testing contentful...
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[100]
      Start processing HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[100]
      Sending HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[101]
      Received HTTP response headers after 381.1223ms - 200
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[101]
      End processing HTTP request after 397.4424ms - 200
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: up
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: down
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference
         at CallSite.Target(Closure, CallSite, Object)
         at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
         at CallSite.Target(Closure, CallSite, Object)
         at Frontend.WebApp.Controllers.TestController.Test() in /Users/adamguest/Development/<redacted>/Frontend.WebApp/Controllers/TestController.cs:line 24
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
^Cinfo: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...

8.3.0

dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5250
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/<redacted>/Frontend.WebApp
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.
info: Frontend.WebApp.Controllers.TestController[0]
      Testing contentful...
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[100]
      Start processing HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[100]
      Sending HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[101]
      Received HTTP response headers after 167.227ms - 200
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[101]
      End processing HTTP request after 173.0682ms - 200
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: up
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: down
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference
         at CallSite.Target(Closure, CallSite, Object)
         at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
         at CallSite.Target(Closure, CallSite, Object)
         at Frontend.WebApp.Controllers.TestController.Test() in /Users/<redacted>/Frontend.WebApp/Controllers/TestController.cs:line 24
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
^Cinfo: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...

8.1.0

dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5250
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/<redacted>/Frontend.WebApp
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.
info: Frontend.WebApp.Controllers.TestController[0]
      Testing contentful...
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[100]
      Start processing HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[100]
      Sending HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[101]
      Received HTTP response headers after 369.3334ms - 200
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[101]
      End processing HTTP request after 379.0272ms - 200
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: up
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: down
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference
         at CallSite.Target(Closure, CallSite, Object)
         at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
         at CallSite.Target(Closure, CallSite, Object)
         at Frontend.WebApp.Controllers.TestController.Test() in /Users/<redacted>/Frontend.WebApp/Controllers/TestController.cs:line 24
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
^Cinfo: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...

8.0.1

dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5250
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/<redacted>/Frontend.WebApp
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.
info: Frontend.WebApp.Controllers.TestController[0]
      Testing contentful...
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[100]
      Start processing HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[100]
      Sending HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[101]
      Received HTTP response headers after 152.0309ms - 200
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[101]
      End processing HTTP request after 158.0424ms - 200
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: up
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: down
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: up
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: down
^Cinfo: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...

Raw API Response:

{
  "sys": {
    "type": "Array"
  },
  "total": 1,
  "skip": 0,
  "limit": 100,
  "items": [
    {
      "metadata": {
        "tags": [],
        "concepts": []
      },
      "sys": {
        "space": {
          "sys": {
            "type": "Link",
            "linkType": "Space",
            "id": "<redacted>"
          }
        },
        "id": "2KvTQ2iohtJXV0gENsUWvt",
        "type": "Entry",
        "createdAt": "2024-10-22T13:10:19.325Z",
        "updatedAt": "2024-10-22T13:10:19.325Z",
        "environment": {
          "sys": {
            "id": "redesign",
            "type": "Link",
            "linkType": "Environment"
          }
        },
        "publishedVersion": 4,
        "revision": 1,
        "contentType": {
          "sys": {
            "type": "Link",
            "linkType": "ContentType",
            "id": "staticPage"
          }
        },
        "locale": "en-US"
      },
      "fields": {
        "pageTitle": "Test Page",
        "slug": "test-page",
        "components": [
          {
            "sys": {
              "type": "Link",
              "linkType": "Entry",
              "id": "70k6l0o29mMmHObcy1u5w3"
            }
          },
          {
            "sys": {
              "type": "Link",
              "linkType": "Entry",
              "id": "54ClnXSbTXmy0MAYW7DoPx"
            }
          },
          {
            "sys": {
              "type": "Link",
              "linkType": "Entry",
              "id": "70k6l0o29mMmHObcy1u5w3"
            }
          },
          {
            "sys": {
              "type": "Link",
              "linkType": "Entry",
              "id": "54ClnXSbTXmy0MAYW7DoPx"
            }
          }
        ]
      }
    }
  ],
  "includes": {
    "Entry": [
      {
        "metadata": {
          "tags": [],
          "concepts": []
        },
        "sys": {
          "space": {
            "sys": {
              "type": "Link",
              "linkType": "Space",
              "id": "<redacted>"
            }
          },
          "id": "54ClnXSbTXmy0MAYW7DoPx",
          "type": "Entry",
          "createdAt": "2024-10-21T10:04:39.241Z",
          "updatedAt": "2024-10-21T10:04:39.241Z",
          "environment": {
            "sys": {
              "id": "redesign",
              "type": "Link",
              "linkType": "Environment"
            }
          },
          "publishedVersion": 2,
          "revision": 1,
          "contentType": {
            "sys": {
              "type": "Link",
              "linkType": "ContentType",
              "id": "divider"
            }
          },
          "locale": "en-US"
        },
        "fields": {
          "direction": "down"
        }
      },
      {
        "metadata": {
          "tags": [],
          "concepts": []
        },
        "sys": {
          "space": {
            "sys": {
              "type": "Link",
              "linkType": "Space",
              "id": "<redacted>"
            }
          },
          "id": "70k6l0o29mMmHObcy1u5w3",
          "type": "Entry",
          "createdAt": "2024-10-21T10:04:26.165Z",
          "updatedAt": "2024-10-21T10:04:26.165Z",
          "environment": {
            "sys": {
              "id": "redesign",
              "type": "Link",
              "linkType": "Environment"
            }
          },
          "publishedVersion": 2,
          "revision": 1,
          "contentType": {
            "sys": {
              "type": "Link",
              "linkType": "ContentType",
              "id": "divider"
            }
          },
          "locale": "en-US"
        },
        "fields": {
          "direction": "up"
        }
      }
    ]
  }
}
Roblinde commented 2 weeks ago

@chamook Thanks for the detailed issue! I'll have a look and see if I can figure out what's going wrong here.

Roblinde commented 2 weeks ago

@chamook just looking at the test-classes I see you're using this has some weird issues where json.net turns it into a JObject which can't be used to actually deserialize into a strong type or resolve references. If you use a strong type with strongly typed properties do you run into the same issue?

chamook commented 2 weeks ago

Changing TestPage to:

public sealed record TestPage(IReadOnlyList<Divider> Components);

and adjusting the test code to work with that can get all the items successfully on 8.3.0:

dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5250
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/some-path/Frontend.WebApp
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.
info: Frontend.WebApp.Controllers.TestController[0]
      Testing contentful...
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[100]
      Start processing HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[100]
      Sending HTTP request GET https://cdn.contentful.com/spaces/<redacted>/environments/redesign/entries?content_type=staticPage&fields.slug=test-page&include=2
info: System.Net.Http.HttpClient.ContentfulClient.ClientHandler[101]
      Received HTTP response headers after 171.6556ms - 200
info: System.Net.Http.HttpClient.ContentfulClient.LogicalHandler[101]
      End processing HTTP request after 182.9215ms - 200
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: up
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: down
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: up
info: Frontend.WebApp.Controllers.TestController[0]
      Direction: down

Is there a preferred way of dealing with references to heterogenous content types that isn't using dynamic? Because that would be great 😀

Roblinde commented 2 weeks ago

Ah great, yeah the dynamics has been a headache unfortunately. However if you have a scenario where you get a number of different content types returned in a single request and want to turn them all into their respective type you need to use a ContentTypeResolver. Here's an example that should still be reasonably up to date: https://www.contentful.com/developers/docs/net/tutorials/using-net-cda-sdk/#get-entries-of-multiple-types-or-by-interface

Hope this helps!

chamook commented 2 weeks ago

That works 😀

Thank you very much for your help!