I have a simple azure function triggered by http:
[OpenApiOperation(operationId: "GetX", tags: new[] { nameof(GetXHttpTrigger) })]
[OpenApiParameter(name: "id", In = ParameterLocation.Path, Required = true, Type = typeof(Guid), Description = "X id.")]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(X), Description = "The OK response")]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.NotFound, contentType: "application/json", bodyType: typeof(StatusMessage), Description = "The NotFound response")]
[Function(nameof(GetXHttpTrigger))]
public async Task<HttpResponseData> Run(
[HttpTrigger(
AuthorizationLevel.Function,
"get",
Route = "Xs/{id}")]
HttpRequestData req,
Guid id,
CancellationToken cancellationToken)
where X is:
public class X
{
[System.Text.Json.Serialization.JsonPropertyName("combined_value")]
public string CombinedValue { get; set; }
..
The code that returns data to the caller looks like:
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync<X>(xData); // WriteAsJson is extension from Microsoft.Azure.Functions.Worker.Http
The data returned to the caller is correct:
{
"combined_value" : "1"
}
but the openId yaml generated schema (from http://localhost:port/api/openapi/{version}.{extension}
) ignores value configured in the attribute and generates just:
x:
type: object
properties:
combinedValue:
type: string
pay attention that combinedValue is "lowerCased" value from c# code. Any ideas why it might happen and how to force swagger to consider System.Text.Json.Serialization.JsonPropertyName attribute?
My host configuration is quite simple:
var host = Host.CreateDefaultBuilder()
.ConfigureFunctionsWorkerDefaults((context, builder) =>
{
// do nothing
})
.ConfigureOpenApi()
and this is what packages I have:
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.21.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.19.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.15.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.OpenApi" Version="1.5.1" />
plus some more project configuration:
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
UPDATE: If I configure Newtonsoft.Json.JsonPropertyAttribute
for c# class:
[Newtonsoft.Json.JsonProperty("combined_value")]
public string CombinedValue { get; set; }
The generated output will be correct:
x:
type: object
properties:
combined_value:
type: string
But I don't want to mix these 2 approaches, how to force swagger using System.Text.Json.Serialization
in this case?
Microsoft.Azure.Functions.Worker.Extensions.OpenApi
nuget has dependency on Newtonsoft.Json
and according to docs it does not support System.Text.Json
. You can switch completely to using Newtonsoft.Json
, as far as I udnerstand it can be done with the following (have not tried it):
.ConfigureFunctionsWorkerDefaults(worker =>
{
worker.UseNewtonsoftJson();
})
Then Newtonsoft.Json.JsonProperty
will be used for both serialization and OpenAPI generation.
Alternatively you can either use both types of attributes:
[System.Text.Json.Serialization.JsonPropertyName("combined_value")]
[Newtonsoft.Json.JsonProperty("combined_value")]
public string CombinedValue { get; set; }
Or add custom contract resolver so it will use attributes from one library for another (like is done here for System.Text.Json
-> Json.NET
, possibly will require configuring JsonConvert.DefaultSettings
, also similar can be done vice versa).
Also see System.Text.Json
Support issue @github.