Skip to content

feat(dotnet-sdk): Added support for generating a client interface#652

Closed
CharlieDigital wants to merge 1 commit intoopenfga:mainfrom
CharlieDigital:feat/dotnet-sdk-add-interface
Closed

feat(dotnet-sdk): Added support for generating a client interface#652
CharlieDigital wants to merge 1 commit intoopenfga:mainfrom
CharlieDigital:feat/dotnet-sdk-add-interface

Conversation

@CharlieDigital
Copy link
Copy Markdown

@CharlieDigital CharlieDigital commented Oct 25, 2025

Description

What problem is being solved?

It is currently not possible to mock the OpenFgaClient in unit tests in .NET as its methods are not virtual and it does not provide an interface for mocking

How is it being solved?

This PR adds a template to generate an interface and adds the interface to the generated OpenFgaClient which will allow unit tests to provide a mock using the interface IOpenFgaClient instead.

What changes are made to solve it?

  • Added a new template file config/clients/dotnet/template/Client/IClient.mustache
  • Updated config/clients/dotnet/config.overrides.json to include the new .mustache file
  • Updated config/clients/dotnet/template/Client/Client.mustache to implement the interface
  • Updated the Makefile to use latest OpenAPI generator which includes support for .NET 9

References

Review Checklist

  • I have clicked on "allow edits by maintainers".
  • I have added documentation for new/changed functionality in this PR or in a PR to openfga.dev [Provide a link to any relevant PRs in the references section above]
  • The correct base branch is being used, if not main
  • I have added tests to validate that the change in functionality is working as expected

Summary by CodeRabbit

  • New Features

    • .NET SDK now exposes a client interface contract, enabling easier unit testing and custom implementations.
  • Chores

    • Updated OpenAPI code generator version and related dependencies.
    • Enhanced code generation templates for improved .NET SDK client and model scaffolding.

Copilot AI review requested due to automatic review settings October 25, 2025 17:17
@CharlieDigital CharlieDigital requested a review from a team as a code owner October 25, 2025 17:17
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla bot commented Oct 25, 2025

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: cchen-motion / name: Charles Chen (59337d1)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 25, 2025

Walkthrough

This PR updates the .NET SDK client generation by bumping the OpenAPI generator version from v6.4.0 to v7.15.0, updating the API reference commit, introducing a new IClient interface to abstract the SDK client, and adding two new model templates for write request operations (deletes and writes).

Changes

Cohort / File(s) Summary
Build Configuration
Makefile
Updated OPEN_API_REF commit hash and OPENAPI_GENERATOR_CLI_DOCKER_TAG version to v7.15.0
Client Interface Abstraction
config/clients/dotnet/config.overrides.json, config/clients/dotnet/template/Client/Client.mustache, config/clients/dotnet/template/Client/IClient.mustache
Added new IClient interface template mapping; updated Client class to implement I{{appShortName}}Client; introduced new public interface with properties (StoreId, AuthorizationModelId) and async methods for Stores, Authorization Models, Relationship Tuples, Relationship Queries, and Assertions operations
Model Templates
config/clients/dotnet/template/modelWriteRequestDeletes.mustache, config/clients/dotnet/template/modelWriteRequestWrites.mustache
Added two new model template generators with support for serialization (ToJson/FromJson), equality/hash code generation, validation scaffolding (maxLength, minLength, maximum, minimum, pattern), nested enum definitions (OnMissingEnum, OnDuplicateEnum), and AdditionalProperties dictionary

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • IClient interface method signatures: verify async patterns, CancellationToken handling consistency, and request/options type correctness across all 19 methods
  • Model template logic: validate serialization round-trip correctness (ToJson/FromJson), equality implementation (property-wise and AdditionalProperties comparison), and validation constraint application
  • Integration: ensure Client.mustache implementation correctly satisfies the new IClient interface contract

Possibly related PRs

Suggested labels

enhancement, dotnet-sdk

Suggested reviewers

  • evansims
  • ewanharris

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Added support for generating a client interface" directly corresponds to the primary objective of this pull request, which is to enable mocking in .NET unit tests by generating an interface for the OpenFgaClient. The changes include adding a new IClient.mustache template, updating the Client.mustache template to implement the interface, and updating the configuration to include the new template file. The title clearly and specifically summarizes this main change without unnecessary noise or vague language. While the changeset also includes Makefile updates and two additional model template files, these appear to be supporting changes, and the title effectively captures the core feature being introduced.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds interface support to the .NET SDK generator to enable mocking of the OpenFGA client in unit tests. The change addresses the issue where the OpenFgaClient class lacked an interface, making it difficult to create test doubles.

Key Changes:

  • Created a new interface IOpenFgaClient that defines the public API contract
  • Updated the client class to implement this interface
  • Upgraded OpenAPI Generator to v7.15.0 to support .NET 9

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
config/clients/dotnet/template/Client/IClient.mustache New template file that generates the IOpenFgaClient interface with all public client methods
config/clients/dotnet/template/Client/Client.mustache Updated to implement the new IOpenFgaClient interface
config/clients/dotnet/config.overrides.json Added configuration mapping for the new interface template file
Makefile Updated OpenAPI generator version and API reference commit
config/clients/dotnet/template/modelWriteRequestWrites.mustache New template file for WriteRequest writes model generation
config/clients/dotnet/template/modelWriteRequestDeletes.mustache New template file for WriteRequest deletes model generation

Comment on lines +1 to +63
{{>partial_header}}

using System;
using System.Collections.Generic;
using System.Linq;
{{#validatable}}
using System.ComponentModel.DataAnnotations;
{{/validatable}}
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;


namespace {{packageName}}.{{modelPackage}}
{
{{#models}}
{{#model}}
/// <summary>
/// {{description}}{{^description}}{{classname}}{{/description}}
/// </summary>
[DataContract(Name = "{{{name}}}")]
{{#discriminator}}
[JsonConverter(typeof(JsonSubtypes), "{{{discriminatorName}}}")]
{{#mappedModels}}
[JsonSubtypes.KnownSubType(typeof({{{modelName}}}), "{{{mappingName}}}")]
{{/mappedModels}}
{{/discriminator}}
public {{#isEnum}}{{^isArray}}{{>visibility}}{{/isArray}}{{/isEnum}}{{^isEnum}}partial {{/isEnum}}class {{{classname}}}{{#parent}} : {{{.}}}{{/parent}}{{^parent}} : IEquatable<{{classname}}>{{#validatable}}, IValidatableObject{{/validatable}}{{/parent}}
{
/// <summary>
/// Defines OnDuplicate behavior
/// </summary>
public enum OnDuplicateEnum
{
/// <summary>
/// Enum Error for value: error
/// </summary>
[EnumMember(Value = "error")]
Error = 1,

/// <summary>
/// Enum Ignore for value: ignore
/// </summary>
[EnumMember(Value = "ignore")]
Ignore = 2
}

{{#vars}}
{{#isEnum}}
{{#allowableValues}}
/// <summary>
/// {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
/// </summary>
{{#description}}
/// <value>{{.}}</value>
{{/description}}
{{#isContainer}}
[DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})]
{{/isContainer}}
public {{#isArray}}{{#uniqueItems}}HashSet{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}{{#isMap}}Dictionary{{/isMap}}<string, {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>{{^isContainer}}{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}{{/isContainer}} {{name}} { get; set; }
{{^isContainer}}
{{>modelInnerEnum}}
{{/isContainer}}
Copy link

Copilot AI Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The entire new file modelWriteRequestWrites.mustache appears to be a standard model template that duplicates the existing model generation logic with only a minor variation (OnDuplicate enum vs OnMissing enum). Consider using a shared base template with parameters to avoid maintaining duplicate code across multiple template files.

Suggested change
{{>partial_header}}
using System;
using System.Collections.Generic;
using System.Linq;
{{#validatable}}
using System.ComponentModel.DataAnnotations;
{{/validatable}}
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace {{packageName}}.{{modelPackage}}
{
{{#models}}
{{#model}}
/// <summary>
/// {{description}}{{^description}}{{classname}}{{/description}}
/// </summary>
[DataContract(Name = "{{{name}}}")]
{{#discriminator}}
[JsonConverter(typeof(JsonSubtypes), "{{{discriminatorName}}}")]
{{#mappedModels}}
[JsonSubtypes.KnownSubType(typeof({{{modelName}}}), "{{{mappingName}}}")]
{{/mappedModels}}
{{/discriminator}}
public {{#isEnum}}{{^isArray}}{{>visibility}}{{/isArray}}{{/isEnum}}{{^isEnum}}partial {{/isEnum}}class {{{classname}}}{{#parent}} : {{{.}}}{{/parent}}{{^parent}} : IEquatable<{{classname}}>{{#validatable}}, IValidatableObject{{/validatable}}{{/parent}}
{
/// <summary>
/// Defines OnDuplicate behavior
/// </summary>
public enum OnDuplicateEnum
{
/// <summary>
/// Enum Error for value: error
/// </summary>
[EnumMember(Value = "error")]
Error = 1,
/// <summary>
/// Enum Ignore for value: ignore
/// </summary>
[EnumMember(Value = "ignore")]
Ignore = 2
}
{{#vars}}
{{#isEnum}}
{{#allowableValues}}
/// <summary>
/// {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
/// </summary>
{{#description}}
/// <value>{{.}}</value>
{{/description}}
{{#isContainer}}
[DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})]
{{/isContainer}}
public {{#isArray}}{{#uniqueItems}}HashSet{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}{{#isMap}}Dictionary{{/isMap}}<string, {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>{{^isContainer}}{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}{{/isContainer}} {{name}} { get; set; }
{{^isContainer}}
{{>modelInnerEnum}}
{{/isContainer}}
{{>modelWriteRequestWritesBase
enumName="OnDuplicateEnum"
enumSummary="Defines OnDuplicate behavior"
enumValues=[
{ "name": "Error", "value": "error", "summary": "Enum Error for value: error" },
{ "name": "Ignore", "value": "ignore", "summary": "Enum Ignore for value: ignore" }
]
}}
{{/isContainer}}

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +14
{{>partial_header}}

using System;
using System.Collections.Generic;
using System.Linq;
{{#validatable}}
using System.ComponentModel.DataAnnotations;
{{/validatable}}
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;


namespace {{packageName}}.{{modelPackage}}
Copy link

Copilot AI Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The entire new file modelWriteRequestDeletes.mustache appears to be a standard model template that duplicates the existing model generation logic with only a minor variation (OnMissing enum vs OnDuplicate enum). Consider using a shared base template with parameters to avoid maintaining duplicate code across multiple template files.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
config/clients/dotnet/config.overrides.json (1)

14-14: Bump packageVersion for the new public interface.

Adding IOpenFgaClient is a feature; update the package version to signal the change and comply with versioning guidelines.

-  "packageVersion": "0.7.0",
+  "packageVersion": "0.8.0",

As per coding guidelines.

🧹 Nitpick comments (6)
Makefile (1)

35-36: Optional: pin golangci-lint image to a concrete version.

Using latest-alpine is non-deterministic; consider a specific tag (e.g., v1.xx.x-alpine) to stabilize CI.

config/clients/dotnet/template/modelWriteRequestDeletes.mustache (2)

248-271: Guard against null AdditionalProperties in equality/hash.

Public setter allows null assignment causing NREs.

Either coalesce in comparisons or initialize via property:

-        public IDictionary<string, object> AdditionalProperties { get; set; }
+        public IDictionary<string, object> AdditionalProperties { get; set; } = new Dictionary<string, object>();

And in Equals:

-                && (this.AdditionalProperties.Count == input.AdditionalProperties.Count && this.AdditionalProperties.All(kv => input.AdditionalProperties.ContainsKey(kv.Key) && Equals(kv.Value, input.AdditionalProperties[kv.Key])));
+                && ((this.AdditionalProperties ?? new Dictionary<string, object>()).Count
+                    == (input.AdditionalProperties ?? new Dictionary<string, object>()).Count)
+                && (this.AdditionalProperties ?? new Dictionary<string, object>()).All(kv =>
+                       (input.AdditionalProperties ?? new Dictionary<string, object>()).ContainsKey(kv.Key)
+                    && Equals(kv.Value, (input.AdditionalProperties ?? new Dictionary<string, object>())[kv.Key])));

170-172: Optional: prefer JsonElement for extension data.

System.Text.Json commonly uses IDictionary<string, JsonElement> for extension data; reduces boxing and surprises on deserialization.

-        public IDictionary<string, object> AdditionalProperties { get; set; }
+        public IDictionary<string, JsonElement> AdditionalProperties { get; set; }
config/clients/dotnet/template/modelWriteRequestWrites.mustache (2)

248-271: Null-safety for AdditionalProperties in Equals/GetHashCode.

Avoid NRE if consumer sets it to null.

Same coalescing/property-initializer approach as proposed in deletes template.


170-172: Optional: use JsonElement for extension data.

Aligns with STJ defaults and avoids boxing.

-        public IDictionary<string, object> AdditionalProperties { get; set; }
+        public IDictionary<string, JsonElement> AdditionalProperties { get; set; }
config/clients/dotnet/template/Client/IClient.mustache (1)

37-189: Standardize comment formatting.

The file uses inconsistent comment styles: some methods use /** on a single line (lines 37, 43, 50, 55) while others use multi-line /** ... */ format (lines 64+). For better consistency and maintainability, standardize to one format throughout.

Consider using C# XML documentation comments (///) instead, which would provide IntelliSense support:

-/**
- * ListStores - Get a paginated list of stores.
- */
+/// <summary>
+/// ListStores - Get a paginated list of stores.
+/// </summary>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d15c31e and 59337d1.

📒 Files selected for processing (6)
  • Makefile (1 hunks)
  • config/clients/dotnet/config.overrides.json (1 hunks)
  • config/clients/dotnet/template/Client/Client.mustache (1 hunks)
  • config/clients/dotnet/template/Client/IClient.mustache (1 hunks)
  • config/clients/dotnet/template/modelWriteRequestDeletes.mustache (1 hunks)
  • config/clients/dotnet/template/modelWriteRequestWrites.mustache (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
config/**/*.mustache

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Validate mustache syntax and variable references across all template files, including CHANGELOG.md.mustache

Files:

  • config/clients/dotnet/template/Client/Client.mustache
  • config/clients/dotnet/template/modelWriteRequestWrites.mustache
  • config/clients/dotnet/template/Client/IClient.mustache
  • config/clients/dotnet/template/modelWriteRequestDeletes.mustache
config/**/*.{json,mustache}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Never hardcode API keys or credentials in configuration or template files

Files:

  • config/clients/dotnet/template/Client/Client.mustache
  • config/clients/dotnet/config.overrides.json
  • config/clients/dotnet/template/modelWriteRequestWrites.mustache
  • config/clients/dotnet/template/Client/IClient.mustache
  • config/clients/dotnet/template/modelWriteRequestDeletes.mustache
Makefile

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Makefile: Update OPEN_API_REF in the Makefile when targeting new OpenFGA API versions
Update Docker image tags in the Makefile when upgrading build tools
Use official, tagged Docker images for containerized builds

Files:

  • Makefile
config/clients/*/config.overrides.json

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

config/clients/*/config.overrides.json: Always update the packageVersion in each language-specific config.overrides.json when making version changes
Maintain FOSSA compliance notice IDs in each language’s config.overrides.json

Files:

  • config/clients/dotnet/config.overrides.json
config/{common/config.base.json,clients/*/config.overrides.json}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Ensure consistent versioning across base and language override configuration files to avoid version conflicts

Files:

  • config/clients/dotnet/config.overrides.json
🧠 Learnings (2)
📚 Learning: 2025-09-04T17:35:34.111Z
Learnt from: CR
PR: openfga/sdk-generator#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-04T17:35:34.111Z
Learning: Applies to Makefile : Update OPEN_API_REF in the Makefile when targeting new OpenFGA API versions

Applied to files:

  • Makefile
📚 Learning: 2025-09-04T17:35:34.111Z
Learnt from: CR
PR: openfga/sdk-generator#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-04T17:35:34.111Z
Learning: Applies to Makefile : Update Docker image tags in the Makefile when upgrading build tools

Applied to files:

  • Makefile
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-test-dotnet-sdk
🔇 Additional comments (10)
config/clients/dotnet/template/modelWriteRequestDeletes.mustache (1)

6-11: Ensure required usings are present for discriminators and validation.

Attributes reference JsonSubtypes and Regex, but no using for JsonSubTypes/Regex is declared here.

If not provided by {{>partial_header}}, add:

 {{#validatable}}
 using System.ComponentModel.DataAnnotations;
+using System.Text.RegularExpressions;
 {{/validatable}}
+using JsonSubTypes;

Also applies to: 21-27

config/clients/dotnet/template/modelWriteRequestWrites.mustache (1)

6-11: Ensure usings for JsonSubtypes and Regex exist.

Template uses JsonSubtypes and Regex without visible usings here.

Add if not in {{>partial_header}}:

 {{#validatable}}
 using System.ComponentModel.DataAnnotations;
+using System.Text.RegularExpressions;
 {{/validatable}}
+using JsonSubTypes;

Also applies to: 21-27

config/clients/dotnet/config.overrides.json (1)

69-72: Mapping for IClient looks correct.

The new SupportingFiles entry will emit src/OpenFga.Sdk/Client/IClient.cs as intended.

Makefile (2)

5-5: Docker tag v7.15.0 verified to exist.

The openapitools/openapi-generator-cli:v7.15.0 tag has been confirmed on Docker Hub and will not cause CI pull failures.


3-3: OPEN_API_REF bump verified.

The spec file is reachable at the commit hash and exposes a valid OpenAPI 2.0 specification with version 1.x. No issues found.

config/clients/dotnet/template/Client/Client.mustache (1)

22-22: Signature parity verified — templates are correctly aligned.

All public method and property signatures declared in I{{appShortName}}Client are properly implemented in {{appShortName}}Client with matching return types, parameters, and async contracts. Interface and implementation maintain complete parity across 18 methods and 2 properties. Private helper methods (e.g., ProcessWriteChunksAsync, GetStoreId, MapOnDuplicateWrites) are correctly excluded from the interface. The Dispose() method properly implements the IDisposable contract.

config/clients/dotnet/template/Client/IClient.mustache (4)

1-21: LGTM!

The header, imports, and namespace declarations are correctly structured. The mustache variable references ({{>partial_header}} and {{packageName}}) follow proper syntax, and the conditional compilation directives appropriately handle framework-specific concerns.


23-31: LGTM!

The properties correctly use nullable reference types and provide mutable access, which is appropriate for client configuration (store ID and authorization model ID can be set after client instantiation).


88-90: Verify nullable return type is intentional.

The ReadLatestAuthorizationModel method returns Task<ReadAuthorizationModelResponse?> (nullable response). This differs from other methods like ReadAuthorizationModel (line 81) which returns non-nullable Task<ReadAuthorizationModelResponse>.

Confirm this is intentional—likely indicating that the latest model may not exist. If so, ensure the implementing class and consumers handle the null case appropriately.


1-22: Mustache syntax is valid.

The mustache template syntax is correct:

  • Partial reference {{>partial_header}} (line 1)
  • Variable references {{packageName}} (lines 11-20) and {{appShortName}} (line 22)

All mustache tags are properly formed with no unclosed or malformed constructs.

Based on coding guidelines.

Comment on lines +57 to +61
{{#isContainer}}
[DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})]
{{/isContainer}}
public {{#isArray}}{{#uniqueItems}}HashSet{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}{{#isMap}}Dictionary{{/isMap}}<string, {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>{{^isContainer}}{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}{{/isContainer}} {{name}} { get; set; }
{{^isContainer}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix invalid generic type generation for enum containers.

Arrays shouldn’t get a Dictionary key parameter. Current template yields e.g. List<string, T>, which won’t compile.

Apply:

-        public {{#isArray}}{{#uniqueItems}}HashSet{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}{{#isMap}}Dictionary{{/isMap}}<string, {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>{{^isContainer}}{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}{{/isContainer}} {{name}} { get; set; }
+        public {{#isArray}}
+            {{#uniqueItems}}HashSet{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}<{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>
+        {{/isArray}}
+        {{#isMap}}
+            Dictionary<string, {{{
+              datatypeWithEnum
+            }}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>
+        {{/isMap}}
+        {{^isContainer}}
+            {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}
+        {{/isContainer}} {{name}} { get; set; }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{{#isContainer}}
[DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})]
{{/isContainer}}
public {{#isArray}}{{#uniqueItems}}HashSet{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}{{#isMap}}Dictionary{{/isMap}}<string, {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>{{^isContainer}}{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}{{/isContainer}} {{name}} { get; set; }
{{^isContainer}}
{{#isContainer}}
[DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})]
{{/isContainer}}
public {{#isArray}}
{{#uniqueItems}}HashSet{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}<{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>
{{/isArray}}
{{#isMap}}
Dictionary<string, {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>
{{/isMap}}
{{^isContainer}}
{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}
{{/isContainer}} {{name}} { get; set; }
{{^isContainer}}
🤖 Prompt for AI Agents
In config/clients/dotnet/template/modelWriteRequestDeletes.mustache lines 57-61,
the template incorrectly emits a Dictionary-style generic parameter for array
containers (producing e.g. List<string, T>), causing invalid C# generics; change
the conditional logic so Dictionary is emitted only when isMap is true and
arrays/collections emit a single generic type (List<T> or HashSet<T>) and maps
emit Dictionary<string, TValue>; ensure the mustache blocks nest/branch so the
key type ("string") is only included for isMap and the value type uses
{{{datatypeWithEnum}}} or {{{dataType}}} as currently used for non-container
types.

Comment on lines +57 to +61
{{#isContainer}}
[DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})]
{{/isContainer}}
public {{#isArray}}{{#uniqueItems}}HashSet{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}{{#isMap}}Dictionary{{/isMap}}<string, {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}>{{^isContainer}}{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}{{/isContainer}} {{name}} { get; set; }
{{^isContainer}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix invalid generic type generation for enum containers.

Same issue as deletes template: arrays currently render List<string, T>.

Apply the same conditional generic fix as suggested for the deletes template.

🤖 Prompt for AI Agents
In config/clients/dotnet/template/modelWriteRequestWrites.mustache around lines
57 to 61, the template is producing invalid generics like List<string, T> for
enum containers; change the conditional rendering so arrays render a single
generic (List<T> or HashSet<T> depending on uniqueItems) and maps render
Dictionary<string, T>, using {{{datatypeWithEnum}}} (falling back to
{{{dataType}}}) as the single type parameter; ensure the non-container branch
stays as just the type, and reuse the same conditional generic logic used in the
deletes template to avoid emitting two generic type arguments.

@CharlieDigital
Copy link
Copy Markdown
Author

Going to redo this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants