I have an ASP.NET Core Web API end point which takes (FromBody) The Search object defined below
public class Search {
public int PageSize {get;set;}
public Expression Query{get;set;}
}
Public class Expression {
public string Type {get;set;}
}
public class AndExpression {
public IList<Expression> Expressions {get;set;}
}
public class MatchesExpression {
public string FieldId {get;set;}
public string Value {get;set;}
public string Operator {get;set;}
}
So... if I post the following JSON to my endpoint
{ "pageSize":10, "query": { "fieldId": "body", "value": "cake", "operator": "matches" } }
I successfully get a Search Object, but the Query property is of type Expression, not MatchesExpression.
This is clearly a polymorphic issue.
This article (towards the end) gives a good example of a how to deal with this issue when your entire model is polymorphic.
https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-5.0
In my case, the property of my Model "Query" is polymorphic, so Im unsure how to build a ModelBinder for my Search object that will allow me to handle the Query Property
I Imagine, I need to write a model binder to construct the search object and then follow the pattern described for the property, however I cannot locate any examples of how to implement a model binder that isnt utterly trivial.
Any suggestions on how to achieve this? Good sources of information?
CodePudding user response:
So.. I gave up with ModelBInders (because Im using the FromBody attribute which isnt compatible with my aims).
Instead I wrote a System.Text.Json JsonConvertor to handle the polymorphism (see shonky code below)
using Searchy.Models;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace Searchy
{
public class ExpressionJsonConverter : JsonConverter<Expression>
{
public override Expression Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Utf8JsonReader readerClone = reader;
using (var jsonDocument = JsonDocument.ParseValue(ref readerClone))
{
if (!jsonDocument.RootElement.TryGetProperty("type", out var typeProperty))
{
throw new JsonException();
}
switch (typeProperty.GetString())
{
case "comparison":
return JsonSerializer.Deserialize<Comparison>(ref reader, options);
case "and":
return JsonSerializer.Deserialize<And>(ref reader, options);
}
}
return null;
}
public override void Write(
Utf8JsonWriter writer,
Expression expression,
JsonSerializerOptions options)
{
}
}
}
My Expression class also had the following attribue
[JsonConverter(typeof(ExpressionJsonConverter))]