Skip to content

Commit

Permalink
Add musician example for derived types deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
nolan.sedley committed Jun 8, 2020
1 parent abac941 commit 4e273ab
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 24 deletions.
9 changes: 9 additions & 0 deletions Controllers/MusiciansController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("musicians")]
public class MusiciansController : ControllerBase
{
public ActionResult Post(IEnumerable<Musician> musiciansToCreate) => Accepted(musiciansToCreate);
}
9 changes: 6 additions & 3 deletions DerivedTypesSerializationExample.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

</Project>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.4"/>
<PackageReference Include="JsonSubTypes" Version="1.7.0"/>
</ItemGroup>
</Project>
27 changes: 27 additions & 0 deletions Models/Musician.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using JsonSubTypes;
using Newtonsoft.Json;

// one possible solution is to use JsonSubTypes attributes
// [JsonConverter(typeof(JsonSubtypes), nameof(Musician.InstrumentType))]
// [JsonSubtypes.KnownSubType(typeof(Guitarist), "Guitar")]
// [JsonSubtypes.KnownSubType(typeof(Pianist), "Piano")]
public abstract class Musician
{
public abstract string InstrumentType { get; }
public string FirstName { get; set; }
public string LastName { get; set; }

public class Guitarist : Musician
{
public override string InstrumentType { get; } = "Guitar";
public int StringCount { get; set; }
public bool CanPlayWonderwall { get; set; }
}

public class Pianist : Musician
{
public override string InstrumentType { get; } = "Piano";
public int HandSpanRating { get; set; }
}
}

28 changes: 28 additions & 0 deletions MusicianCustomConverterExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

// You could write a custom JsonConverter to tell the serializer how to act.
public class MusicianConverter : JsonConverter<Musician>
{
public override Musician ReadJson(JsonReader reader, Type objectType, [AllowNull] Musician existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var typeDiscriminator = jObject["instrumentType"].Value<string>();
switch (typeDiscriminator)
{
case "Guitar":
return serializer.Deserialize<Musician.Guitarist>(reader);
case "Piano":
return serializer.Deserialize<Musician.Pianist>(reader);
default:
throw new NotSupportedException();
}
}

public override void WriteJson(JsonWriter writer, [AllowNull] Musician value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
9 changes: 1 addition & 8 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace DerivedTypesSerializationExample
{
public class Program
Expand All @@ -20,7 +13,7 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseStartup<Startup>();
});
}
}
29 changes: 16 additions & 13 deletions Startup.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JsonSubTypes;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;

namespace DerivedTypesSerializationExample
{
Expand All @@ -16,6 +13,19 @@ public class Startup
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.Converters.Add(
JsonSubtypesConverterBuilder
.Of(typeof(Musician), nameof(Musician.InstrumentType))
.RegisterSubtype(typeof(Musician.Guitarist), "Guitar")
.RegisterSubtype(typeof(Musician.Pianist), "Piano")
.SerializeDiscriminatorProperty()
.Build()
);
});
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
Expand All @@ -27,14 +37,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
}

app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
app.UseEndpoints(e => e.MapControllers());
}
}
}
18 changes: 18 additions & 0 deletions example-http-requests/post-musicians.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
POST http://localhost:5000/musicians HTTP/1.1
Content-Type: application/json

[
{
"instrumentType": "Guitar",
"stringCount": 6,
"canPlayWonderwall": true,
"firstName": "Noel",
"lastName": "Gallagher"
},
{
"instrumentType": "Piano",
"handSpanRating": 15,
"firstName": "Claude",
"lastName": "Debussy"
}
]

0 comments on commit 4e273ab

Please sign in to comment.