Skip to content

Commit e073db1

Browse files
committed
C# client: fix default values for DateTime etc, numeric and boolean defaults were not applied
1 parent feeaf4a commit e073db1

6 files changed

Lines changed: 176 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Changed
1515

16+
- C# client: default value initialization for DateTime/Date/Time properties did not compile [#7404](https://github.com/microsoft/kiota/issues/7404)
17+
- C# client: default value initialization for numeric/boolean properties was missing [#7404](https://github.com/microsoft/kiota/issues/7404)
1618
- Fixed a bug where OpenAPI schemas with `format` but without `type` keyword would generate `UntypedNode` instead of proper types. [#7315](https://github.com/microsoft/kiota/issues/7315)
1719
- Fixed a bug where discriminator mappings for oneOf types with allOf-inherited schemas would incorrectly use schema names as keys instead of resolving the base type discriminator mappings. [#7339](https://github.com/microsoft/kiota/issues/7339)
1820
- Fixed TypeScript enum imports to use `import type` for type aliases to support `verbatimModuleSyntax`. [#7332](https://github.com/microsoft/kiota/pull/7332)

src/Kiota.Builder/KiotaBuilder.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,14 @@ openApiExtension is OpenApiPrimaryErrorMessageExtension primaryErrorMessageExten
12121212
!string.IsNullOrEmpty(stringDefaultValue) &&
12131213
!"null".Equals(stringDefaultValue, StringComparison.OrdinalIgnoreCase))
12141214
prop.DefaultValue = $"\"{stringDefaultValue}\"";
1215+
else if (kind == CodePropertyKind.Custom &&
1216+
propertySchema?.Default is JsonValue stringDefaultJsonValue2 &&
1217+
!stringDefaultJsonValue2.IsJsonNullSentinel() &&
1218+
(stringDefaultJsonValue2.GetValueKind() == JsonValueKind.Number || stringDefaultJsonValue2.GetValueKind() == JsonValueKind.True || stringDefaultJsonValue2.GetValueKind() == JsonValueKind.False))
1219+
{
1220+
//Values not placed in quotes (number and boolean): just forwared the value.
1221+
prop.DefaultValue = stringDefaultJsonValue2.ToString();
1222+
}
12151223

12161224
if (existingType == null)
12171225
{

src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho
253253
.ThenBy(static x => x.Name))
254254
{
255255
var defaultValue = propWithDefault.DefaultValue;
256-
if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum)
256+
var propertyType = propWithDefault.Type as CodeType;
257+
if (propertyType != null && propertyType.TypeDefinition is CodeEnum)
257258
{
258259
defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}";
259260
}
@@ -262,10 +263,31 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho
262263
{ // avoid setting null as a string.
263264
defaultValue = NullValueString;
264265
}
265-
else if (propWithDefault.Type is CodeType propType && propType.Name.Equals("boolean", StringComparison.OrdinalIgnoreCase))
266+
else if (propertyType != null && propertyType.Name.Equals("boolean", StringComparison.OrdinalIgnoreCase))
266267
{
267268
defaultValue = defaultValue.TrimQuotes();
268269
}
270+
else if (propertyType != null && propertyType.Name.Equals("date", StringComparison.OrdinalIgnoreCase))
271+
{
272+
defaultValue = $"new Date(DateTimeOffset.Parse({defaultValue}).Date)";
273+
}
274+
else if (propertyType != null && propertyType.Name.Equals("datetimeoffset", StringComparison.OrdinalIgnoreCase))
275+
{
276+
defaultValue = $"DateTimeOffset.Parse({defaultValue})";
277+
}
278+
else if (propertyType != null && propertyType.Name.Equals("time", StringComparison.OrdinalIgnoreCase))
279+
{
280+
defaultValue = $"new Time(DateTimeOffset.Parse({defaultValue}).DateTime)";
281+
}
282+
else if (propertyType != null && propertyType.Name.Equals("guid", StringComparison.OrdinalIgnoreCase))
283+
{
284+
defaultValue = $"Guid.Parse({defaultValue})";
285+
}
286+
else if (propertyType != null && propertyType.Name.Equals("float", StringComparison.OrdinalIgnoreCase))
287+
{
288+
//Append "f" to the float value:
289+
defaultValue = $"{defaultValue}f";
290+
}
269291
else if (defaultValue.StartsWith('"') && defaultValue.EndsWith('"'))
270292
{
271293
// cannot use TrimQuotes() as it would greedily remove the explicitly set quotes on both ends of the string

tests/Kiota.Builder.IntegrationTests/GenerateSample.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,5 +235,27 @@ public async Task GeneratesUritemplateHintsAsync(GenerationLanguage language)
235235

236236
}
237237
}
238+
/// <summary>
239+
/// Test for https://github.com/microsoft/kiota/issues/7404
240+
/// Tests assignment of default values in model classes.
241+
/// </summary>
242+
/// <param name="language"></param>
243+
/// <returns></returns>
244+
[InlineData(GenerationLanguage.CSharp)]
245+
[Theory]
246+
public async Task GeneratesModelWithDefaultValuesAsync(GenerationLanguage language)
247+
{
248+
var logger = LoggerFactory.Create(builder =>
249+
{
250+
}).CreateLogger<KiotaBuilder>();
251+
252+
var configuration = new GenerationConfiguration
253+
{
254+
Language = language,
255+
OpenAPIFilePath = GetAbsolutePath("ModelWithDefaultValues.json"),
256+
OutputPath = $".\\Generated\\ModelWithDefaultValues\\{language}",
257+
};
258+
await new KiotaBuilder(logger, configuration, _httpClient).GenerateClientAsync(new());
259+
}
238260
private static string GetAbsolutePath(string relativePath) => Path.Combine(Directory.GetCurrentDirectory(), relativePath);
239261
}

tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
</ItemGroup>
3030

3131
<ItemGroup>
32+
<None Update="ModelWithDefaultValues.json">
33+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
34+
</None>
3235
<None Update="ResponseWithMultipleReturnFormats.yaml">
3336
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3437
</None>
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
{
2+
"openapi": "3.0.4",
3+
"info": {
4+
"title": "Weather forecast v1",
5+
"description": "This is a Web API for Weather forecast operations",
6+
"version": "v1"
7+
},
8+
"paths": {
9+
"/api/v1/WeatherForecast": {
10+
"get": {
11+
"tags": [
12+
"WeatherForecast"
13+
],
14+
"responses": {
15+
"200": {
16+
"description": "OK",
17+
"content": {
18+
"text/plain": {
19+
"schema": {
20+
"type": "array",
21+
"items": {
22+
"$ref": "#/components/schemas/WeatherForecast"
23+
}
24+
}
25+
},
26+
"application/json": {
27+
"schema": {
28+
"type": "array",
29+
"items": {
30+
"$ref": "#/components/schemas/WeatherForecast"
31+
}
32+
}
33+
},
34+
"text/json": {
35+
"schema": {
36+
"type": "array",
37+
"items": {
38+
"$ref": "#/components/schemas/WeatherForecast"
39+
}
40+
}
41+
}
42+
}
43+
}
44+
}
45+
}
46+
}
47+
},
48+
"components": {
49+
"schemas": {
50+
"WeatherForecast": {
51+
"type": "object",
52+
"properties": {
53+
"dateValue": {
54+
"type": "string",
55+
"format": "date-time",
56+
"default": "1900-01-01T00:00:00"
57+
},
58+
"dateOnlyValue": {
59+
"type": "string",
60+
"format": "date",
61+
"default": "1900-01-01"
62+
},
63+
"guidValue": {
64+
"type": "string",
65+
"format": "uuid",
66+
"default": "00000000-0000-0000-0000-000000000000"
67+
},
68+
"timeValue": {
69+
"type": "string",
70+
"format": "time",
71+
"default": "00:00:00"
72+
},
73+
"temperatureC": {
74+
"type": "integer",
75+
"format": "int32",
76+
"default": 15
77+
},
78+
"temperatureF": {
79+
"type": "integer",
80+
"format": "int32",
81+
"readOnly": true
82+
},
83+
"summary": {
84+
"type": "string",
85+
"default": "Test",
86+
"nullable": true
87+
},
88+
"doubleValue": {
89+
"type": "number",
90+
"format": "double",
91+
"default": 25.5
92+
},
93+
"decimalValue": {
94+
"type": "number",
95+
"format": "double",
96+
"default": 25.5
97+
},
98+
"floatValue": {
99+
"type": "number",
100+
"format": "float",
101+
"default": 25.5
102+
},
103+
"boolValue": {
104+
"type": "boolean",
105+
"default": true
106+
}
107+
},
108+
"additionalProperties": false
109+
}
110+
}
111+
},
112+
"tags": [
113+
{
114+
"name": "WeatherForecast"
115+
}
116+
]
117+
}

0 commit comments

Comments
 (0)