Is your feature request related to a problem? Please describe.
GET /dwapi/ecommerce/orders/search (Orders_SearchOrders) emits 81 query parameters, 5 of which are declared twice in the same operation:
| Parameter |
Occurrences |
PageSize |
2 |
FromCompletedDate |
2 |
ToCompletedDate |
2 |
ByCustomerNumber |
2 |
RetrieveMode |
2 |
The cause is in the action signature (Dynamicweb.Frontend.Classic.Api.Ecommerce/Controllers/OrdersController.cs):
[HttpGet, Route("search")]
public IActionResult SearchOrders([FromQuery] OrderSearchRequest request,
[FromQuery] OrderListViewModelSettings settings)
Two complex models are bound from the query string with no binder prefix on either. OrderSearchRequest declares PageSize, FromCompletedDate, ToCompletedDate, ByCustomerNumber, RetrieveMode; OrderListViewModelSettings declares the same five. NSwag flattens both models into the same parameter list, so each name is emitted once per model. Nested settings are namespaced (OrderSettings.PriceSettings.ShopId, …) and therefore don't collide — only the top-level properties of the second model do.
Why this is a problem:
-
The document is invalid OpenAPI. OpenAPI 3.0 requires parameters to be unique by name + in. Downstream tooling reacts unpredictably: NSwag/openapi-generator produce a client method with two identically named arguments (compile error) or silently drop one, and linters (Spectral, Redocly) fail the document.
-
Swagger UI renders two identical input boxes for each duplicated field, with no way for a consumer to tell which one is which or which one wins.
-
The duplicates are inert, which makes it worse. ASP.NET binds the same value into both objects, and then the controller immediately overwrites the settings copy:
settings.PageSize = request.PageSize;
settings.CurrentPage = request.Page;
settings.FromCompletedDate, settings.ToCompletedDate, settings.RetrieveMode and settings.ByCustomerNumber are bound but never read — only request.* feeds the search filter. So half the documented surface of this endpoint has no effect at all.
-
Passing the parameter twice (?PageSize=10&PageSize=25) does not error — the first value silently wins — so the ambiguity fails quietly rather than loudly.
Page vs CurrentPage
Also worth noting as context for the same root cause: paging is near-duplicated under two spellings (Page on the request vs CurrentPage on the settings), and both are documented.
Describe the solution you'd like
Every operation in the generated document should have parameters that are unique by name + location. Concretely, for this endpoint:
- Prefix or eliminate the second bound model. Either bind the view settings under a name —
[FromQuery(Name = "settings")] OrderListViewModelSettings settings, yielding settings.PageSize, settings.ShowPricesWithVat, … — or, preferably, stop binding OrderListViewModelSettings from the query string entirely and expose a slim API-specific settings model that omits the properties already carried by OrderSearchRequest. The latter also removes the four parameters the endpoint documents but ignores.
- Drop or collapse the redundant paging spelling so there is one
Page/PageSize pair on the endpoint, not two.
- Guard it in CI. There is currently no test that generates the OpenAPI document and asserts anything about it. A single test that builds the NSwag document and asserts
parameters are distinct by (name, in) for every operation would prevent this class of regression across the whole API, not just this endpoint.
- Please treat the querystring contract change as a versioning decision — if the current unprefixed names must keep working, accepting both the prefixed and legacy names for a deprecation window would avoid breaking existing consumers.
Additional context
- Verified against
https://staging-jayco.mydwsite.com/dwapi/api.json, info.version = 10.29.1-PreRelease.
- Scanned all 125 operations in that document:
Orders_SearchOrders is currently the only one with duplicate parameter names, so the fix is narrow.
- Related but separate concern from the same "bind several complex models from the query string" pattern: parameter explosion.
Orders_SearchOrders has 81 query parameters and Products_ExportProducts has 156, most of them deeply dotted (OrderSettings.OrderLineSettings.GroupInfoSettings.CurrencyCode). These operations are effectively unusable through Swagger UI even when the parameters are unique. A POST-with-body variant for the wide search/export operations would help here.
- Relevant files:
Dynamicweb.Frontend.Classic.Api.Ecommerce/Controllers/OrdersController.cs, Dynamicweb.Frontend.Classic.Api.Ecommerce/Controllers/OrderSearchRequest.cs, src/Features/Ecommerce/Dynamicweb.Ecommerce/Frontend/OrderListViewModelSettings.cs, and the document generation setup in Dynamicweb.Frontend.Classic.Api/ServiceCollectionExtensions.cs (AddOpenApiDocument).
Best Regards,
Nuno Aguiar
Is your feature request related to a problem? Please describe.
GET /dwapi/ecommerce/orders/search(Orders_SearchOrders) emits 81 query parameters, 5 of which are declared twice in the same operation:PageSizeFromCompletedDateToCompletedDateByCustomerNumberRetrieveModeThe cause is in the action signature (
Dynamicweb.Frontend.Classic.Api.Ecommerce/Controllers/OrdersController.cs):Two complex models are bound from the query string with no binder prefix on either.
OrderSearchRequestdeclaresPageSize,FromCompletedDate,ToCompletedDate,ByCustomerNumber,RetrieveMode;OrderListViewModelSettingsdeclares the same five. NSwag flattens both models into the same parameter list, so each name is emitted once per model. Nested settings are namespaced (OrderSettings.PriceSettings.ShopId, …) and therefore don't collide — only the top-level properties of the second model do.Why this is a problem:
The document is invalid OpenAPI. OpenAPI 3.0 requires parameters to be unique by
name+in. Downstream tooling reacts unpredictably: NSwag/openapi-generator produce a client method with two identically named arguments (compile error) or silently drop one, and linters (Spectral, Redocly) fail the document.Swagger UI renders two identical input boxes for each duplicated field, with no way for a consumer to tell which one is which or which one wins.
The duplicates are inert, which makes it worse. ASP.NET binds the same value into both objects, and then the controller immediately overwrites the settings copy:
settings.FromCompletedDate,settings.ToCompletedDate,settings.RetrieveModeandsettings.ByCustomerNumberare bound but never read — onlyrequest.*feeds the search filter. So half the documented surface of this endpoint has no effect at all.Passing the parameter twice (
?PageSize=10&PageSize=25) does not error — the first value silently wins — so the ambiguity fails quietly rather than loudly.Page vs CurrentPage
Also worth noting as context for the same root cause: paging is near-duplicated under two spellings (
Pageon the request vsCurrentPageon the settings), and both are documented.Describe the solution you'd like
Every operation in the generated document should have parameters that are unique by name + location. Concretely, for this endpoint:
[FromQuery(Name = "settings")] OrderListViewModelSettings settings, yieldingsettings.PageSize,settings.ShowPricesWithVat, … — or, preferably, stop bindingOrderListViewModelSettingsfrom the query string entirely and expose a slim API-specific settings model that omits the properties already carried byOrderSearchRequest. The latter also removes the four parameters the endpoint documents but ignores.Page/PageSizepair on the endpoint, not two.parametersare distinct by(name, in)for every operation would prevent this class of regression across the whole API, not just this endpoint.Additional context
https://staging-jayco.mydwsite.com/dwapi/api.json,info.version=10.29.1-PreRelease.Orders_SearchOrdersis currently the only one with duplicate parameter names, so the fix is narrow.Orders_SearchOrdershas 81 query parameters andProducts_ExportProductshas 156, most of them deeply dotted (OrderSettings.OrderLineSettings.GroupInfoSettings.CurrencyCode). These operations are effectively unusable through Swagger UI even when the parameters are unique. APOST-with-body variant for the wide search/export operations would help here.Dynamicweb.Frontend.Classic.Api.Ecommerce/Controllers/OrdersController.cs,Dynamicweb.Frontend.Classic.Api.Ecommerce/Controllers/OrderSearchRequest.cs,src/Features/Ecommerce/Dynamicweb.Ecommerce/Frontend/OrderListViewModelSettings.cs, and the document generation setup inDynamicweb.Frontend.Classic.Api/ServiceCollectionExtensions.cs(AddOpenApiDocument).Best Regards,
Nuno Aguiar