Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Umbraco.Cms.Api.Management.OpenApi;
namespace Umbraco.Cms.Api.Common.OpenApi;

/// <summary>
/// Marker interface that ensure the type have a "$type" discriminator in the open api schema.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ namespace Umbraco.Cms.Api.Common.Serialization;
public interface IUmbracoJsonTypeInfoResolver : IJsonTypeInfoResolver
{
IEnumerable<Type> FindSubTypes(Type type);

string? GetTypeDiscriminatorValue(Type type);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System.Collections.Concurrent;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Cms.Core.Composing;
using Umbraco.Extensions;

namespace Umbraco.Cms.Api.Common.Serialization;

Expand All @@ -15,6 +18,14 @@ public UmbracoJsonTypeInfoResolver(ITypeFinder typeFinder)

public IEnumerable<Type> FindSubTypes(Type type)
{
JsonDerivedTypeAttribute[] explicitJsonDerivedTypes = type
.GetCustomAttributes<JsonDerivedTypeAttribute>(false)
.ToArray();
if (explicitJsonDerivedTypes.Any())
{
return explicitJsonDerivedTypes.Select(a => a.DerivedType);
}

if (type.IsInterface is false)
{
// IMPORTANT: do NOT return an empty enumerable here. it will cause nullability to fail on reference
Expand All @@ -33,6 +44,24 @@ public IEnumerable<Type> FindSubTypes(Type type)
return result;
}

public string? GetTypeDiscriminatorValue(Type type)
{
JsonDerivedTypeAttribute? jsonDerivedTypeAttribute = type
.GetBaseTypes(false)
.WhereNotNull()
.SelectMany(baseType => baseType.GetCustomAttributes<JsonDerivedTypeAttribute>(false))
.FirstOrDefault(attr => attr.DerivedType == type);

if (jsonDerivedTypeAttribute is not null)
{
// IMPORTANT: do NOT perform fallback to type.Name here - it will work for the schema generation,
// but not for the actual serialization, and then it's only going to cause confusion.
return jsonDerivedTypeAttribute.TypeDiscriminator?.ToString();
}

return typeof(IOpenApiDiscriminator).IsAssignableFrom(type) ? type.Name : null;
}

public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo result = base.GetTypeInfo(type, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Cms.Api.Common.Serialization;
using Umbraco.Cms.Api.Management.DependencyInjection;
using Umbraco.Cms.Api.Management.OpenApi;
Expand Down Expand Up @@ -34,8 +35,8 @@ public void Configure(SwaggerGenOptions swaggerGenOptions)
swaggerGenOptions.UseOneOfForPolymorphism();

// Ensure all types that implements the IOpenApiDiscriminator have a $type property in the OpenApi schema with the default value (The class name) that is expected by the server
swaggerGenOptions.SelectDiscriminatorNameUsing(type => typeof(IOpenApiDiscriminator).IsAssignableFrom(type) ? "$type" : null);
swaggerGenOptions.SelectDiscriminatorValueUsing(type => typeof(IOpenApiDiscriminator).IsAssignableFrom(type) ? type.Name : null);
swaggerGenOptions.SelectDiscriminatorNameUsing(type => _umbracoJsonTypeInfoResolver.GetTypeDiscriminatorValue(type) is not null ? "$type" : null);
swaggerGenOptions.SelectDiscriminatorValueUsing(_umbracoJsonTypeInfoResolver.GetTypeDiscriminatorValue);


swaggerGenOptions.AddSecurityDefinition(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Umbraco.Cms.Api.Management.OpenApi;
using Umbraco.Cms.Api.Common.OpenApi;

namespace Umbraco.Cms.Api.Management.ViewModels.UserGroup.Permissions;

Expand Down