У меня есть конечная точка Rest, которая получает класс EntityInsertRequest
public class EntityInsertRequest
{
public string Description { get; set; }
public IEnumerable Fields { get; set; }
}
public class EntityFieldInsertRequest
{
public string DatabaseField { get; set; }
public string Description { get; set; }
}
Как я могу создать фильтр или переопределить инициализацию объекта, чтобы удалить объект по умолчанию из списка, в этом случае объект списка по умолчанию будет:
{
"databaseField": "",
"description": ""
}
и я бы отправил
{
"description": "FooBar",
"fields": [
{
"databaseField": "",
"description": ""
},
{
"databaseField": "Foo",
"description": "Bar"
}
]
}
Мне бы хотелось, чтобы его экземпляр создавался с пустым списком и динамически реплицировался для других конечных точек.
Я не могу изменить способ отправки и удалите объект на стороне отправителя, он должен находиться на серверной стороне.
Я пытался создать JsonConverter
public class NullableIEnumerableOverride : JsonConverter where T : class
{
public override bool CanConvert(Type typeToConvert)
{
return typeof(System.Collections.IEnumerable).IsAssignableFrom(typeToConvert) && typeToConvert != typeof(string) && typeToConvert.GenericTypeArguments[0].IsClass;
}
public override IEnumerable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var internalOptions = new JsonSerializerOptions(options);
var list = JsonSerializer.Deserialize(ref reader);
if (list == null || !list.Any())
{
return (IEnumerable)CreateEmptyInstance(typeToConvert);
}
//cant get properties of generic object with typeof(T).GetProperties()
//bool allFieldsAreDefault = list.All(item =>
//{
// var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
// return properties.All(prop =>
// {
// var value = prop.GetValue(item);
// var defaultValue = GetDefault(prop.PropertyType);
// return Equals(value, defaultValue);
// });
//});
//return allFieldsAreDefault ? (IEnumerable)CreateEmptyInstance(typeToConvert) : list;
return list;
}
private static object CreateEmptyInstance(Type typeToConvert)
{
if (typeToConvert.IsGenericType && typeof(IEnumerable).IsAssignableFrom(typeToConvert.GetGenericTypeDefinition()))
{
Type elementType = typeToConvert.GetGenericArguments()[0];
Type listType = typeof(List).MakeGenericType(elementType);
return Activator.CreateInstance(listType) ?? throw new InvalidOperationException($"Unable to create instance of type {listType}.");
}
throw new InvalidOperationException($"Type {typeToConvert} is not supported.");
}
public override void Write(Utf8JsonWriter writer, IEnumerable? value, JsonSerializerOptions options)
{
if (value == null)
{
writer.WriteNullValue();
return;
}
JsonSerializerOptions jsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
JsonSerializer.Serialize(writer, value, jsonOptions);
}
private object? GetDefault(Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
}
и в файле program.cs
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new NullableIEnumerableOverride());
});
и поскольку я хочу использовать его на других конечных точках и установить как общий объект в program.cs, я получаю следующую ошибку приведения:
System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[System.Object]' to type 'System.Collections.Generic.IEnumerable`1[Logic.Request.Entity.EntityFieldInsertRequest]'.
at System.Text.Json.ThrowHelper.ThrowInvalidCastException_DeserializeUnableToAssignValue(Type typeOfValue, Type declaredType)
at System.Text.Json.JsonSerializer.g__ThrowUnableToCastValue|50_0[T](Object value)
at System.Text.Json.JsonSerializer.UnboxOnRead[T](Object value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.ContinueDeserialize(ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync(Stream utf8Json, CancellationToken cancellationToken)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObjectAsync(Stream utf8Json, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value, Object container)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.c__DisplayClass0_0.d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
Подробнее здесь: https://stackoverflow.com/questions/790 ... rest-contr