Skip to content

Commit 824ef6b

Browse files
committed
see description
refactor the context add a resource repository for data access rename service to router add relational routing
1 parent 08761df commit 824ef6b

25 files changed

+426
-194
lines changed

JsonApiDotNetCore/Abstractions/IJsonApiResource.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
namespace JsonApiDotNetCore.Abstractions
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace JsonApiDotNetCore.Abstractions
25
{
36
public interface IJsonApiResource
47
{

JsonApiDotNetCore/Abstractions/IModel.cs

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using JsonApiDotNetCore.Configuration;
3+
using JsonApiDotNetCore.Routing;
4+
using Microsoft.AspNetCore.Http;
5+
6+
namespace JsonApiDotNetCore.Abstractions
7+
{
8+
public class JsonApiContext
9+
{
10+
public HttpContext HttpContext { get; }
11+
public Route Route { get; }
12+
public object DbContext { get; }
13+
public JsonApiModelConfiguration Configuration { get; }
14+
15+
public JsonApiContext(HttpContext httpContext, Route route, object dbContext, JsonApiModelConfiguration configuration)
16+
{
17+
HttpContext = httpContext;
18+
Route = route;
19+
DbContext = dbContext;
20+
Configuration = configuration;
21+
}
22+
23+
public Type GetJsonApiResourceType()
24+
{
25+
return Configuration.ResourceMapDefinitions[Route.BaseModelType];
26+
}
27+
}
28+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Linq;
4+
using System.Linq.Expressions;
5+
using System.Reflection;
6+
using JsonApiDotNetCore.Attributes;
7+
8+
namespace JsonApiDotNetCore.Abstractions
9+
{
10+
public static class ModelAccessor
11+
{
12+
public static Type GetTypeFromModelRelationshipName(object model, string relationshipName)
13+
{
14+
return model.GetType().GetProperties().Where(propertyInfo => propertyInfo.GetMethod.IsVirtual).ToList().FirstOrDefault(
15+
virtualProperty => virtualProperty.Name == relationshipName)?.PropertyType;
16+
}
17+
18+
}
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
3+
namespace JsonApiDotNetCore.Attributes
4+
{
5+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
6+
public class JsonApiIncludeAttribute : Attribute
7+
{
8+
}
9+
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using System.Collections.Generic;
13
using AutoMapper;
24

35
namespace JsonApiDotNetCore.Configuration
@@ -6,6 +8,6 @@ public interface IJsonApiModelConfiguration
68
{
79
void UseContext<T>();
810
void SetDefaultNamespace(string ns);
9-
void DefineResourceMapping(MapperConfiguration mapperConfiguration);
11+
void DefineResourceMapping(Action<Dictionary<Type,Type>> mapping);
1012
}
1113
}

JsonApiDotNetCore/Configuration/JsonApiModelConfiguration.cs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,29 @@ namespace JsonApiDotNetCore.Configuration
1313
public class JsonApiModelConfiguration : IJsonApiModelConfiguration
1414
{
1515
public string Namespace;
16-
public IMapper ResourceMaps;
16+
public IMapper ResourceMapper;
1717
public Type ContextType { get; set; }
18-
19-
private readonly List<RouteDefinition> _routes = new List<RouteDefinition>();
18+
public List<RouteDefinition> Routes = new List<RouteDefinition>();
19+
public Dictionary<Type, Type> ResourceMapDefinitions = new Dictionary<Type, Type>();
2020

2121
public void SetDefaultNamespace(string ns)
2222
{
2323
Namespace = ns;
2424
}
2525

26-
public void DefineResourceMapping(MapperConfiguration mapperConfiguration)
26+
public void DefineResourceMapping(Action<Dictionary<Type,Type>> mapping)
2727
{
28-
ResourceMaps = mapperConfiguration.CreateMapper();
28+
mapping.Invoke(ResourceMapDefinitions);
29+
30+
var mapConfiguration = new MapperConfiguration(cfg =>
31+
{
32+
foreach (var definition in ResourceMapDefinitions)
33+
{
34+
cfg.CreateMap(definition.Key, definition.Value);
35+
}
36+
});
37+
38+
ResourceMapper = mapConfiguration.CreateMapper();
2939
}
3040

3141
public void UseContext<T>()
@@ -55,22 +65,10 @@ private void LoadModelRoutesFromContext()
5565
ContextPropertyName = property.Name
5666
};
5767

58-
_routes.Add(route);
68+
Routes.Add(route);
5969
}
6070
});
6171
}
6272

63-
public Route GetRouteForRequest(HttpRequest request)
64-
{
65-
foreach (var rte in _routes)
66-
{
67-
PathString remainingPathString;
68-
if (request.Path.StartsWithSegments(new PathString(rte.PathString), StringComparison.OrdinalIgnoreCase, out remainingPathString))
69-
{
70-
return new Route(rte.ModelType, request.Method, remainingPathString, rte);
71-
}
72-
}
73-
return null;
74-
}
7573
}
7674
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using JsonApiDotNetCore.Abstractions;
3+
using JsonApiDotNetCore.Data;
4+
5+
namespace JsonApiDotNetCore.Controllers
6+
{
7+
public class ControllerBuilder
8+
{
9+
private readonly JsonApiContext _context;
10+
11+
public ControllerBuilder(JsonApiContext context)
12+
{
13+
_context = context;
14+
}
15+
16+
public JsonApiController BuildController()
17+
{
18+
return new JsonApiController(_context, new ResourceRepository(_context));
19+
}
20+
}
21+
}
Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,45 @@
1-
using System;
2-
using Microsoft.AspNetCore.Http;
1+
using JsonApiDotNetCore.Abstractions;
2+
using JsonApiDotNetCore.Data;
33
using Microsoft.AspNetCore.Mvc;
4-
using JsonApiDotNetCore.Services;
54

65
namespace JsonApiDotNetCore.Controllers
76
{
87
public class JsonApiController
98
{
10-
private HttpContext _httpContext;
11-
private readonly JsonApiContext _jsonApiContext;
9+
protected readonly JsonApiContext JsonApiContext;
10+
private readonly ResourceRepository _resourceRepository;
1211

13-
public JsonApiController(HttpContext context, JsonApiContext jsonApiContext)
12+
public JsonApiController(JsonApiContext jsonApiContext, ResourceRepository resourceRepository)
1413
{
15-
_jsonApiContext = jsonApiContext;
16-
_httpContext = context;
14+
JsonApiContext = jsonApiContext;
15+
_resourceRepository = resourceRepository;
1716
}
1817

1918
public ObjectResult Get()
2019
{
21-
var entities = _jsonApiContext.Get();
20+
var entities = _resourceRepository.Get();
2221
return new OkObjectResult(entities);
2322
}
2423

2524
public ObjectResult Get(string id)
2625
{
27-
var entity = _jsonApiContext.Get(id);
26+
var entity = _resourceRepository.Get(id);
2827
return new OkObjectResult(entity);
2928
}
3029

31-
public IActionResult Post(object entity)
30+
public ObjectResult Post(object entity)
3231
{
33-
return new OkResult();
32+
return new CreatedResult(JsonApiContext.HttpContext.Request.Path, entity);
3433
}
3534

36-
public IActionResult Put(string id, object entity)
35+
public ObjectResult Put(string id, object entity)
3736
{
38-
return new OkResult();
37+
return new OkObjectResult(entity);
3938
}
4039

41-
public IActionResult Delete(string id)
40+
public ObjectResult Delete(string id)
4241
{
43-
return new OkResult();
42+
return new OkObjectResult(null);
4443
}
4544
}
4645
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Linq.Expressions;
5+
using JsonApiDotNetCore.Abstractions;
6+
using System.Reflection;
7+
using JsonApiDotNetCore.Routing;
8+
using Microsoft.EntityFrameworkCore;
9+
10+
namespace JsonApiDotNetCore.Data
11+
{
12+
public class ResourceRepository
13+
{
14+
private readonly JsonApiContext _context;
15+
16+
public ResourceRepository(JsonApiContext context)
17+
{
18+
_context = context;
19+
}
20+
21+
public List<object> Get()
22+
{
23+
return (GetDbSetFromContext(_context.Route.BaseRouteDefinition.ContextPropertyName) as IEnumerable<object>)?.ToList();
24+
}
25+
26+
public object Get(string id)
27+
{
28+
var relationalRoute = _context.Route as RelationalRoute;
29+
if (relationalRoute == null)
30+
{
31+
return GetEntityById(id);
32+
}
33+
return GetRelated(id, relationalRoute.RelationshipName);
34+
}
35+
36+
private object GetRelated(string id, string relationshipName)
37+
{
38+
// HACK: this would rely on lazy loading to work...will probably fail
39+
var entity = GetEntityById(id);
40+
var entityType = entity.GetType();
41+
return entityType.GetProperties().FirstOrDefault(pi => pi.Name == relationshipName).GetValue(entity);
42+
}
43+
44+
private object GetDbSetFromContext(string propName)
45+
{
46+
var dbContext = _context.DbContext;
47+
return dbContext.GetType().GetProperties().FirstOrDefault(pI => pI.Name == propName)?.GetValue(dbContext, null);
48+
}
49+
50+
private object GetEntityById(string id)
51+
{
52+
// HACK: I _believe_ by casting to IEnumerable, we are loading all records into memory, if so... find a better way...
53+
// Also, we are making a BIG assumption that the resource has an attribute Id and not ResourceId which is allowed by EF
54+
return
55+
(GetDbSetFromContext(_context.Route.BaseRouteDefinition.ContextPropertyName) as IEnumerable<dynamic>)?
56+
.FirstOrDefault(x => x.Id.ToString() == id);
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)