Document and document type read API (#13853)
* Basic structure for document and document type read API * Handle unpublished, non-variant content * Expose content type key on ContentTypeSort * Add the remaining properties to document type (minus list view info, still pending) * Obsolete more ILocalizationService usage * Add URLs and template data to document view model * Clean up + add proprety type appearance * update submodule commit * front-end commit * latest front-end commit * latest commit * latest front-end commit * Rename content property to content value in view model layer * Add contextual JSON serialization as default JSON serializer * Add FIXME to content type sort + rearrange constructor parameters * Fix broken remark tag * Whitelist breakage for ContentTypeSort * Add variance info to property type output * Update src/Umbraco.Cms.Api.Management/Controllers/Document/ByKeyDocumentController.cs Co-authored-by: Bjarke Berg <mail@bergmania.dk> * Update src/Umbraco.Cms.Api.Management/Controllers/DocumentType/ByKeyDocumentTypeController.cs Co-authored-by: Bjarke Berg <mail@bergmania.dk> * Update src/Umbraco.Cms.Api.Management/Factories/ContentUrlFactory.cs Co-authored-by: Bjarke Berg <mail@bergmania.dk> * Add a few FIXME comments about async entity retrieval --------- Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com> Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
// FIXME: move away from Json.NET; this is a temporary fix that attempts to use System.Text.Json for management API operations, Json.NET for other operations
|
||||
public class ContextualJsonSerializer : IJsonSerializer
|
||||
{
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
private readonly IJsonSerializer _jsonNetSerializer;
|
||||
private readonly IJsonSerializer _systemTextSerializer;
|
||||
|
||||
public ContextualJsonSerializer(IRequestAccessor requestAccessor)
|
||||
{
|
||||
_requestAccessor = requestAccessor;
|
||||
_jsonNetSerializer = new JsonNetSerializer();
|
||||
_systemTextSerializer = new SystemTextJsonSerializer();
|
||||
}
|
||||
|
||||
public string Serialize(object? input) => ContextualizedSerializer().Serialize(input);
|
||||
|
||||
public T? Deserialize<T>(string input) => ContextualizedSerializer().Deserialize<T>(input);
|
||||
|
||||
public T? DeserializeSubset<T>(string input, string key) => throw new NotSupportedException();
|
||||
|
||||
private IJsonSerializer ContextualizedSerializer()
|
||||
{
|
||||
try
|
||||
{
|
||||
var requestedPath = _requestAccessor.GetRequestUrl()?.AbsolutePath;
|
||||
if (requestedPath != null)
|
||||
{
|
||||
// add white listed paths for the System.Text.Json config serializer here
|
||||
// - always use it for the new management API
|
||||
if (requestedPath.Contains("/umbraco/management/api/"))
|
||||
{
|
||||
return _systemTextSerializer;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// ignore - this whole thing is a temporary workaround, let's not make a fuss
|
||||
}
|
||||
|
||||
return _jsonNetSerializer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
// TODO: clean up all config editor serializers when we can migrate fully to System.Text.Json
|
||||
// FIXME: clean up all config editor serializers when we can migrate fully to System.Text.Json
|
||||
// - move this implementation to ConfigurationEditorJsonSerializer (delete the old implementation)
|
||||
// - use this implementation as the registered singleton (delete ContextualConfigurationEditorJsonSerializer)
|
||||
// - reuse the JsonObjectConverter implementation from management API (delete the local implementation - pending V12 branch update)
|
||||
@@ -21,9 +21,9 @@ public class SystemTextConfigurationEditorJsonSerializer : IConfigurationEditorJ
|
||||
// in some cases, configs aren't camel cased in the DB, so we have to resort to case insensitive
|
||||
// property name resolving when creating configuration objects (deserializing DB configs)
|
||||
PropertyNameCaseInsensitive = true,
|
||||
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString
|
||||
NumberHandling = JsonNumberHandling.AllowReadingFromString
|
||||
};
|
||||
_jsonSerializerOptions.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
|
||||
_jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||
_jsonSerializerOptions.Converters.Add(new JsonObjectConverter());
|
||||
}
|
||||
|
||||
@@ -32,73 +32,4 @@ public class SystemTextConfigurationEditorJsonSerializer : IConfigurationEditorJ
|
||||
public T? Deserialize<T>(string input) => JsonSerializer.Deserialize<T>(input, _jsonSerializerOptions);
|
||||
|
||||
public T? DeserializeSubset<T>(string input, string key) => throw new NotSupportedException();
|
||||
|
||||
// TODO: reuse the JsonObjectConverter implementation from management API
|
||||
private class JsonObjectConverter : System.Text.Json.Serialization.JsonConverter<object>
|
||||
{
|
||||
public override object Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options) =>
|
||||
ParseObject(ref reader);
|
||||
|
||||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
object objectToWrite,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
if (objectToWrite is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If an object is equals "new object()", Json.Serialize would recurse forever and cause a stack overflow
|
||||
// We have no good way of checking if its an empty object
|
||||
// which is why we try to check if the object has any properties, and thus will be empty.
|
||||
if (objectToWrite.GetType().Name is "Object" && !objectToWrite.GetType().GetProperties().Any())
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options);
|
||||
}
|
||||
}
|
||||
|
||||
private object ParseObject(ref Utf8JsonReader reader)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.StartArray)
|
||||
{
|
||||
var items = new List<object>();
|
||||
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
|
||||
{
|
||||
items.Add(ParseObject(ref reader));
|
||||
}
|
||||
|
||||
return items.ToArray();
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonTokenType.StartObject)
|
||||
{
|
||||
var jsonNode = JsonNode.Parse(ref reader);
|
||||
if (jsonNode is JsonObject jsonObject)
|
||||
{
|
||||
return jsonObject;
|
||||
}
|
||||
}
|
||||
|
||||
return reader.TokenType switch
|
||||
{
|
||||
JsonTokenType.True => true,
|
||||
JsonTokenType.False => false,
|
||||
JsonTokenType.Number when reader.TryGetInt32(out int i) => i,
|
||||
JsonTokenType.Number when reader.TryGetInt64(out long l) => l,
|
||||
JsonTokenType.Number => reader.GetDouble(),
|
||||
JsonTokenType.String when reader.TryGetDateTime(out DateTime datetime) => datetime,
|
||||
JsonTokenType.String => reader.GetString()!,
|
||||
_ => JsonDocument.ParseValue(ref reader).RootElement.Clone()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
public class SystemTextJsonSerializer : IJsonSerializer
|
||||
{
|
||||
private readonly JsonSerializerOptions _jsonSerializerOptions;
|
||||
|
||||
public SystemTextJsonSerializer()
|
||||
{
|
||||
_jsonSerializerOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
_jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||
// we may need to add JsonObjectConverter at some point, but for the time being things work fine without
|
||||
// _jsonSerializerOptions.Converters.Add(new JsonObjectConverter());
|
||||
}
|
||||
|
||||
public string Serialize(object? input) => JsonSerializer.Serialize(input, _jsonSerializerOptions);
|
||||
|
||||
public T? Deserialize<T>(string input) => JsonSerializer.Deserialize<T>(input, _jsonSerializerOptions);
|
||||
|
||||
public T? DeserializeSubset<T>(string input, string key) => throw new NotSupportedException();
|
||||
}
|
||||
Reference in New Issue
Block a user