Skip to content

Commit 1f8d0f4

Browse files
committed
feat(*): prepping for serialization
1 parent e900bac commit 1f8d0f4

File tree

10 files changed

+175
-5
lines changed

10 files changed

+175
-5
lines changed

src/JsonApiDotNetCore/Controllers/JsonApiController.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.AspNetCore.Mvc;
66
using Microsoft.EntityFrameworkCore;
77
using Microsoft.Extensions.Logging;
8+
using Newtonsoft.Json;
89

910
namespace JsonApiDotNetCore.Controllers
1011
{
@@ -25,7 +26,8 @@ public JsonApiController(
2526
_jsonApiContext = jsonApiContext;
2627

2728
_logger = loggerFactory.CreateLogger<JsonApiController<T>>();
28-
_logger.LogInformation("JsonApiController activated");
29+
_logger.LogInformation($@"JsonApiController activated with ContextGraph:
30+
{JsonConvert.SerializeObject(jsonApiContext.ContextGraph)}");
2931
}
3032

3133
public JsonApiController(
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
using JsonApiDotNetCore.Internal;
5+
using JsonApiDotNetCore.Serialization;
6+
using Microsoft.AspNetCore.Mvc.Formatters;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Newtonsoft.Json;
9+
10+
namespace JsonApiDotNetCore.Formatters
11+
{
12+
public class JsonApiInputFormatter : IInputFormatter
13+
{
14+
15+
public bool CanRead(InputFormatterContext context)
16+
{
17+
if (context == null)
18+
throw new ArgumentNullException(nameof(context));
19+
20+
var contentTypeString = context.HttpContext.Request.ContentType;
21+
22+
return string.IsNullOrEmpty(contentTypeString) || contentTypeString == "application/vnd.api+json";
23+
}
24+
25+
public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
26+
{
27+
if (context == null)
28+
throw new ArgumentNullException(nameof(context));
29+
30+
var request = context.HttpContext.Request;
31+
32+
if (request.ContentLength == 0)
33+
{
34+
return InputFormatterResult.SuccessAsync(null);
35+
}
36+
37+
try
38+
{
39+
var body = GetRequestBody(context.HttpContext.Request.Body);
40+
var contextGraph = context.HttpContext.RequestServices.GetService<IContextGraph>();
41+
var model = JsonApiDeSerializer.Deserialize(body, contextGraph);
42+
43+
return InputFormatterResult.SuccessAsync(model);
44+
}
45+
catch (JsonSerializationException)
46+
{
47+
context.HttpContext.Response.StatusCode = 422;
48+
return InputFormatterResult.FailureAsync();
49+
}
50+
}
51+
52+
private string GetRequestBody(Stream body)
53+
{
54+
using (var reader = new StreamReader(body))
55+
{
56+
return reader.ReadToEnd();
57+
}
58+
}
59+
}
60+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace JsonApiDotNetCore.Internal
4+
{
5+
public class AttrAttribute : Attribute
6+
{
7+
public AttrAttribute(string publicName)
8+
{
9+
PublicAttributeName = publicName;
10+
}
11+
12+
public string PublicAttributeName { get; set; }
13+
public string InternalAttributeName { get; set; }
14+
}
15+
}

src/JsonApiDotNetCore/Internal/ContextEntity.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public class ContextEntity
77
{
88
public string EntityName { get; set; }
99
public Type EntityType { get; set; }
10+
public List<AttrAttribute> Attributes { get; set; }
1011
public List<Relationship> Relationships { get; set; }
1112
}
1213
}

src/JsonApiDotNetCore/Internal/ContextGraph.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ public class ContextGraph<T> : IContextGraph where T : DbContext
99
{
1010
public List<ContextEntity> Entities { get; set; }
1111

12+
public ContextEntity GetContextEntity(string dbSetName)
13+
{
14+
return Entities
15+
.FirstOrDefault(e =>
16+
e.EntityName.ToLower() == dbSetName.ToLower());
17+
}
18+
1219
public object GetRelationship<TParent>(TParent entity, string relationshipName)
1320
{
1421
var parentEntityType = typeof(TParent);

src/JsonApiDotNetCore/Internal/ContextGraphBuilder.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,39 @@ private void _getFirstLevelEntities()
3232

3333
foreach(var property in contextProperties)
3434
{
35-
var type = property.PropertyType;
35+
var dbSetType = property.PropertyType;
3636

37-
if (type.GetTypeInfo().IsGenericType
38-
&& type.GetGenericTypeDefinition() == typeof(DbSet<>))
37+
if (dbSetType.GetTypeInfo().IsGenericType
38+
&& dbSetType.GetGenericTypeDefinition() == typeof(DbSet<>))
3939
{
40+
var entityType = dbSetType.GetGenericArguments()[0];
4041
entities.Add(new ContextEntity {
4142
EntityName = property.Name,
42-
EntityType = type.GetGenericArguments()[0]
43+
EntityType = entityType,
44+
Attributes = _getAttributes(entityType)
4345
});
4446
}
4547
}
4648

4749
_entities = entities;
4850
}
4951

52+
private List<AttrAttribute> _getAttributes(Type entityType)
53+
{
54+
var attributes = new List<AttrAttribute>();
55+
56+
var properties = entityType.GetProperties();
57+
58+
foreach(var prop in properties)
59+
{
60+
var attribute = (AttrAttribute)prop.GetCustomAttribute(typeof(AttrAttribute));
61+
if(attribute == null) continue;
62+
attribute.InternalAttributeName = prop.Name;
63+
attributes.Add(attribute);
64+
}
65+
return attributes;
66+
}
67+
5068
private void _loadRelationships()
5169
{
5270
_entities.ForEach(entity => {

src/JsonApiDotNetCore/Internal/IContextGraph.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ public interface IContextGraph
44
{
55
object GetRelationship<TParent>(TParent entity, string relationshipName);
66
string GetRelationshipName<TParent>(string relationshipName);
7+
ContextEntity GetContextEntity(string dbSetName);
78
}
89
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace JsonApiDotNetCore.Models
2+
{
3+
public class Document
4+
{
5+
public DocumentData Data { get; set; }
6+
}
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
3+
namespace JsonApiDotNetCore.Models
4+
{
5+
public class DocumentData
6+
{
7+
public string Type { get; set; }
8+
public string Id { get; set; }
9+
public Dictionary<string,object> Attributes { get; set; }
10+
}
11+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using JsonApiDotNetCore.Internal;
6+
using JsonApiDotNetCore.Models;
7+
using Newtonsoft.Json;
8+
9+
namespace JsonApiDotNetCore.Serialization
10+
{
11+
public static class JsonApiDeSerializer
12+
{
13+
public static object Deserialize(string requestBody, IContextGraph contextGraph)
14+
{
15+
var document = JsonConvert.DeserializeObject<Document>(requestBody);
16+
var contextEntity = contextGraph.GetContextEntity(document.Data.Type);
17+
18+
var entity = Activator.CreateInstance(contextEntity.EntityType);
19+
20+
entity = _setEntityAttributes(entity, contextEntity, document.Data.Attributes);
21+
22+
return null;
23+
}
24+
25+
private static object _setEntityAttributes(
26+
object entity, ContextEntity contextEntity, Dictionary<string, object> attributeValues)
27+
{
28+
var entityProperties = entity.GetType().GetProperties();
29+
30+
foreach(var attr in contextEntity.Attributes)
31+
{
32+
var entityProperty = entityProperties.FirstOrDefault(p => p.Name == attr.InternalAttributeName);
33+
34+
if(entityProperty == null)
35+
throw new ArgumentException($"{contextEntity.EntityType.Name} does not contain an attribute named {attr.InternalAttributeName}", nameof(entity));
36+
37+
object newValue;
38+
if (attributeValues.TryGetValue(attr.PublicAttributeName, out newValue))
39+
{
40+
Convert.ChangeType(newValue, entityProperty.PropertyType);
41+
entityProperty.SetValue(entity, newValue);
42+
}
43+
}
44+
45+
return entity;
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)