, IHasMeta
{
public PersonResource(IResourceGraph graph) : base(graph) { }
@@ -20,5 +21,14 @@ public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary().ToList().ForEach(kvp => DisallowLocked(kvp.Value));
}
+
+
+ public Dictionary GetMeta()
+ {
+ return new Dictionary {
+ { "copyright", "Copyright 2015 Example Corp." },
+ { "authors", new string[] { "Jared Nance" } }
+ };
+ }
}
}
diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs
index e3b3100ddd..cd266303f3 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs
@@ -4,14 +4,13 @@
using JsonApiDotNetCore.Hooks;
using JsonApiDotNetCoreExample.Models;
using JsonApiDotNetCore.Internal;
+using JsonApiDotNetCore.Internal.Contracts;
namespace JsonApiDotNetCoreExample.Resources
{
public class TagResource : ResourceDefinition
{
- public TagResource(IResourceGraph graph) : base(graph)
- {
- }
+ public TagResource(IResourceGraph graph) : base(graph) { }
public override IEnumerable BeforeCreate(IEntityHashSet affected, ResourcePipeline pipeline)
{
diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs
index cfba9855d3..1c9f89a7fc 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs
@@ -4,6 +4,7 @@
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Hooks;
using JsonApiDotNetCoreExample.Models;
+using JsonApiDotNetCore.Internal.Contracts;
namespace JsonApiDotNetCoreExample.Resources
{
diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/UserResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/UserResource.cs
index ec54b6144e..f6810f086b 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Resources/UserResource.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Resources/UserResource.cs
@@ -3,16 +3,17 @@
using JsonApiDotNetCore.Models;
using JsonApiDotNetCoreExample.Models;
using JsonApiDotNetCore.Internal.Query;
-using JsonApiDotNetCore.Internal;
+using JsonApiDotNetCore.Internal.Contracts;
+using JsonApiDotNetCore.Services;
namespace JsonApiDotNetCoreExample.Resources
{
public class UserResource : ResourceDefinition
{
- public UserResource(IResourceGraph graph) : base(graph) { }
+ public UserResource(IResourceGraph graph, IExposedFieldExplorer fieldExplorer) : base(fieldExplorer, graph) { }
- protected override List OutputAttrs()
- => Remove(user => user.Password);
+ //protected override List OutputAttrs()
+ // => Remove(user => user.Password);
public override QueryFilters GetQueryFilters()
{
diff --git a/src/Examples/JsonApiDotNetCoreExample/Services/CustomArticleService.cs b/src/Examples/JsonApiDotNetCoreExample/Services/CustomArticleService.cs
new file mode 100644
index 0000000000..83bb43fd19
--- /dev/null
+++ b/src/Examples/JsonApiDotNetCoreExample/Services/CustomArticleService.cs
@@ -0,0 +1,39 @@
+using JsonApiDotNetCore.Configuration;
+using JsonApiDotNetCore.Data;
+using JsonApiDotNetCore.Hooks;
+using JsonApiDotNetCore.Internal;
+using JsonApiDotNetCore.Internal.Contracts;
+using JsonApiDotNetCore.Managers.Contracts;
+using JsonApiDotNetCore.Services;
+using JsonApiDotNetCoreExample.Models;
+using Microsoft.Extensions.Logging;
+using System.Threading.Tasks;
+
+namespace JsonApiDotNetCoreExample.Services
+{
+ public class CustomArticleService : EntityResourceService
+ {
+ public CustomArticleService(
+ IEntityRepository repository,
+ IJsonApiOptions jsonApiOptions,
+ IRequestContext queryManager,
+ IPageQueryService pageManager,
+ IResourceGraph resourceGraph,
+ IResourceHookExecutor resourceHookExecutor = null,
+ ILoggerFactory loggerFactory = null
+ ) : base(repository: repository, jsonApiOptions, queryManager, pageManager, resourceGraph:resourceGraph, loggerFactory, resourceHookExecutor)
+ { }
+
+ public override async Task GetAsync(int id)
+ {
+ var newEntity = await base.GetAsync(id);
+ if(newEntity == null)
+ {
+ throw new JsonApiException(404, "The entity could not be found");
+ }
+ newEntity.Name = "None for you Glen Coco";
+ return newEntity;
+ }
+ }
+
+}
diff --git a/src/Examples/JsonApiDotNetCoreExample/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startup.cs
index 44784f7eac..a784de13f6 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Startup.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Startup.cs
@@ -29,9 +29,6 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
var loggerFactory = new LoggerFactory();
loggerFactory.AddConsole(LogLevel.Warning);
-
- var mvcBuilder = services.AddMvcCore();
-
services
.AddSingleton(loggerFactory)
.AddDbContext(options => options.UseNpgsql(GetDbConnectionString()), ServiceLifetime.Transient)
@@ -40,9 +37,8 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services)
options.DefaultPageSize = 5;
options.IncludeTotalRecordCount = true;
options.EnableResourceHooks = true;
- options.LoadDatabaseValues = true;
+ options.LoaDatabaseValues = true;
},
- mvcBuilder,
discovery => discovery.AddCurrentAssembly());
return services.BuildServiceProvider();
@@ -55,9 +51,7 @@ public virtual void Configure(
AppDbContext context)
{
context.Database.EnsureCreated();
-
loggerFactory.AddConsole(Config.GetSection("Logging"));
-
app.UseJsonApi();
}
diff --git a/src/Examples/NoEntityFrameworkExample/Controllers/CustomTodoItemsController.cs b/src/Examples/NoEntityFrameworkExample/Controllers/CustomTodoItemsController.cs
index a6ded9749f..4e93d26bea 100644
--- a/src/Examples/NoEntityFrameworkExample/Controllers/CustomTodoItemsController.cs
+++ b/src/Examples/NoEntityFrameworkExample/Controllers/CustomTodoItemsController.cs
@@ -1,4 +1,6 @@
-using JsonApiDotNetCore.Controllers;
+using JsonApiDotNetCore.Configuration;
+using JsonApiDotNetCore.Controllers;
+using JsonApiDotNetCore.Internal.Contracts;
using JsonApiDotNetCore.Services;
using JsonApiDotNetCoreExample.Models;
using Microsoft.Extensions.Logging;
@@ -8,10 +10,11 @@ namespace NoEntityFrameworkExample.Controllers
public class CustomTodoItemsController : JsonApiController
{
public CustomTodoItemsController(
- IJsonApiContext jsonApiContext,
+ IJsonApiOptions jsonApiOptions,
+ IResourceGraph resourceGraph,
IResourceService resourceService,
ILoggerFactory loggerFactory)
- : base(jsonApiContext, resourceService, loggerFactory)
+ : base(jsonApiOptions, resourceGraph, resourceService, loggerFactory)
{ }
}
}
diff --git a/src/Examples/ReportsExample/Controllers/ReportsController.cs b/src/Examples/ReportsExample/Controllers/ReportsController.cs
index 6f431d9291..e421477c20 100644
--- a/src/Examples/ReportsExample/Controllers/ReportsController.cs
+++ b/src/Examples/ReportsExample/Controllers/ReportsController.cs
@@ -1,17 +1,20 @@
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using JsonApiDotNetCore.Controllers;
using JsonApiDotNetCore.Services;
-
+using JsonApiDotNetCore.Configuration;
+using JsonApiDotNetCore.Internal.Contracts;
+
namespace ReportsExample.Controllers
{
[Route("api/[controller]")]
public class ReportsController : BaseJsonApiController
{
- public ReportsController(
- IJsonApiContext jsonApiContext,
+ public ReportsController(
+ IJsonApiOptions jsonApiOptions,
+ IResourceGraph resourceGraph,
IGetAllService getAll)
- : base(jsonApiContext, getAll: getAll)
+ : base(jsonApiOptions, resourceGraph, getAll: getAll)
{ }
[HttpGet]
diff --git a/src/Examples/ReportsExample/Startup.cs b/src/Examples/ReportsExample/Startup.cs
index b71b7fa74a..4f49e87db6 100644
--- a/src/Examples/ReportsExample/Startup.cs
+++ b/src/Examples/ReportsExample/Startup.cs
@@ -27,8 +27,7 @@ public virtual void ConfigureServices(IServiceCollection services)
var mvcBuilder = services.AddMvcCore();
services.AddJsonApi(
opt => opt.Namespace = "api",
- mvcBuilder,
- discovery => discovery.AddCurrentAssembly());
+ discovery => discovery.AddCurrentAssembly(), mvcBuilder);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
diff --git a/src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs b/src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs
index 6809ace0bb..48d280f5cb 100644
--- a/src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs
+++ b/src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs
@@ -1,4 +1,6 @@
+using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Controllers;
+using JsonApiDotNetCore.Internal.Contracts;
using JsonApiDotNetCore.Services;
using JsonApiDotNetCoreExample.Models.Resources;
using Microsoft.Extensions.Logging;
@@ -8,10 +10,11 @@ namespace ResourceEntitySeparationExample.Controllers
public class CoursesController : JsonApiController
{
public CoursesController(
- IJsonApiContext jsonApiContext,
+ IJsonApiOptions jsonApiOptions,
+ IResourceGraph resourceGraph,
IResourceService resourceService,
ILoggerFactory loggerFactory)
- : base(jsonApiContext, resourceService, loggerFactory)
+ : base(jsonApiOptions, resourceGraph, resourceService, loggerFactory)
{ }
}
}
diff --git a/src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs b/src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs
index 08f3ab33ad..63310743ac 100644
--- a/src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs
+++ b/src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs
@@ -1,5 +1,7 @@
using System;
+using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Controllers;
+using JsonApiDotNetCore.Internal.Contracts;
using JsonApiDotNetCore.Services;
using JsonApiDotNetCoreExample.Models.Resources;
using Microsoft.Extensions.Logging;
@@ -9,10 +11,11 @@ namespace ResourceEntitySeparationExample.Controllers
public class DepartmentsController : JsonApiController
{
public DepartmentsController(
- IJsonApiContext jsonApiContext,
+ IJsonApiOptions jsonApiOptions,
+ IResourceGraph resourceGraph,
IResourceService resourceService,
ILoggerFactory loggerFactory)
- : base(jsonApiContext, resourceService, loggerFactory)
+ : base(jsonApiOptions, resourceGraph, resourceService, loggerFactory)
{ }
}
}
diff --git a/src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs b/src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs
index 34d5d33031..5f3551849a 100644
--- a/src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs
+++ b/src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs
@@ -1,4 +1,6 @@
+using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Controllers;
+using JsonApiDotNetCore.Internal.Contracts;
using JsonApiDotNetCore.Services;
using JsonApiDotNetCoreExample.Models.Resources;
using Microsoft.Extensions.Logging;
@@ -8,10 +10,11 @@ namespace ResourceEntitySeparationExample.Controllers
public class StudentsController : JsonApiController
{
public StudentsController(
- IJsonApiContext jsonApiContext,
+ IJsonApiOptions jsonApiOptions,
+ IResourceGraph resourceGraph,
IResourceService resourceService,
ILoggerFactory loggerFactory)
- : base(jsonApiContext, resourceService, loggerFactory)
+ : base(jsonApiOptions, resourceGraph, resourceService, loggerFactory)
{ }
}
}
diff --git a/src/Examples/ResourceEntitySeparationExample/Startup.cs b/src/Examples/ResourceEntitySeparationExample/Startup.cs
index a99febfee8..f87dea6935 100644
--- a/src/Examples/ResourceEntitySeparationExample/Startup.cs
+++ b/src/Examples/ResourceEntitySeparationExample/Startup.cs
@@ -43,18 +43,19 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services)
ServiceLifetime.Transient);
services.AddScoped>();
- var mvcBuilder = services.AddMvcCore();
services.AddJsonApi(options => {
options.Namespace = "api/v1";
options.DefaultPageSize = 10;
options.IncludeTotalRecordCount = true;
- options.BuildResourceGraph((builder) => {
+ options.EnableResourceHooks = false; // not supported with ResourceEntitySeparation
+ options.BuildResourceGraph((builder) =>
+ {
builder.AddResource("courses");
builder.AddResource("departments");
builder.AddResource("students");
});
- }, mvcBuilder);
+ });
services.AddAutoMapper();
services.AddScoped();
diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs
index ad52aeb8bb..55f9357476 100644
--- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs
+++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs
@@ -1,354 +1,372 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using JsonApiDotNetCore.Extensions;
-using JsonApiDotNetCore.Internal;
-using JsonApiDotNetCore.Models;
-using JsonApiDotNetCore.Services;
-
-namespace JsonApiDotNetCore.Builders
-{
- ///
- public class DocumentBuilder : IDocumentBuilder
- {
- private readonly IJsonApiContext _jsonApiContext;
- private readonly IResourceGraph _resourceGraph;
- private readonly IRequestMeta _requestMeta;
- private readonly DocumentBuilderOptions _documentBuilderOptions;
- private readonly IScopedServiceProvider _scopedServiceProvider;
-
- public DocumentBuilder(
- IJsonApiContext jsonApiContext,
- IRequestMeta requestMeta = null,
- IDocumentBuilderOptionsProvider documentBuilderOptionsProvider = null,
- IScopedServiceProvider scopedServiceProvider = null)
- {
- _jsonApiContext = jsonApiContext;
- _resourceGraph = jsonApiContext.ResourceGraph;
- _requestMeta = requestMeta;
- _documentBuilderOptions = documentBuilderOptionsProvider?.GetDocumentBuilderOptions() ?? new DocumentBuilderOptions();
- _scopedServiceProvider = scopedServiceProvider;
- }
-
- ///
- public Document Build(IIdentifiable entity)
- {
- var contextEntity = _resourceGraph.GetContextEntity(entity.GetType());
-
- var resourceDefinition = _scopedServiceProvider?.GetService(contextEntity.ResourceType) as IResourceDefinition;
- var document = new Document
- {
- Data = GetData(contextEntity, entity, resourceDefinition),
- Meta = GetMeta(entity)
- };
-
- if (ShouldIncludePageLinks(contextEntity))
- document.Links = _jsonApiContext.PageManager.GetPageLinks(new LinkBuilder(_jsonApiContext));
-
- document.Included = AppendIncludedObject(document.Included, contextEntity, entity);
-
- return document;
- }
-
- ///
- public Documents Build(IEnumerable entities)
- {
- var entityType = entities.GetElementType();
- var contextEntity = _resourceGraph.GetContextEntity(entityType);
- var resourceDefinition = _scopedServiceProvider?.GetService(contextEntity.ResourceType) as IResourceDefinition;
-
- var enumeratedEntities = entities as IList ?? entities.ToList();
- var documents = new Documents
- {
- Data = new List(),
- Meta = GetMeta(enumeratedEntities.FirstOrDefault())
- };
-
- if (ShouldIncludePageLinks(contextEntity))
- documents.Links = _jsonApiContext.PageManager.GetPageLinks(new LinkBuilder(_jsonApiContext));
-
- foreach (var entity in enumeratedEntities)
- {
- documents.Data.Add(GetData(contextEntity, entity, resourceDefinition));
- documents.Included = AppendIncludedObject(documents.Included, contextEntity, entity);
- }
-
- return documents;
- }
-
- private Dictionary GetMeta(IIdentifiable entity)
- {
- var builder = _jsonApiContext.MetaBuilder;
- if (_jsonApiContext.Options.IncludeTotalRecordCount && _jsonApiContext.PageManager.TotalRecords != null)
- builder.Add("total-records", _jsonApiContext.PageManager.TotalRecords);
-
- if (_requestMeta != null)
- builder.Add(_requestMeta.GetMeta());
-
- if (entity != null && entity is IHasMeta metaEntity)
- builder.Add(metaEntity.GetMeta(_jsonApiContext));
-
- var meta = builder.Build();
- if (meta.Count > 0)
- return meta;
-
- return null;
- }
-
- private bool ShouldIncludePageLinks(ContextEntity entity) => entity.Links.HasFlag(Link.Paging);
-
- private List AppendIncludedObject(List includedObject, ContextEntity contextEntity, IIdentifiable entity)
- {
- var includedEntities = GetIncludedEntities(includedObject, contextEntity, entity);
- if (includedEntities?.Count > 0)
- {
- includedObject = includedEntities;
- }
-
- return includedObject;
- }
-
- [Obsolete("You should specify an IResourceDefinition implementation using the GetData/3 overload.")]
- public ResourceObject GetData(ContextEntity contextEntity, IIdentifiable entity)
- => GetData(contextEntity, entity, resourceDefinition: null);
-
- ///
- public ResourceObject GetData(ContextEntity contextEntity, IIdentifiable entity, IResourceDefinition resourceDefinition = null)
- {
- var data = new ResourceObject
- {
- Type = contextEntity.EntityName,
- Id = entity.StringId
- };
-
- if (_jsonApiContext.IsRelationshipPath)
- return data;
-
- data.Attributes = new Dictionary();
-
- var resourceAttributes = resourceDefinition?.GetOutputAttrs(entity) ?? contextEntity.Attributes;
- resourceAttributes.ForEach(attr =>
- {
- var attributeValue = attr.GetValue(entity);
- if (ShouldIncludeAttribute(attr, attributeValue))
- {
- data.Attributes.Add(attr.PublicAttributeName, attributeValue);
- }
- });
-
- if (contextEntity.Relationships.Count > 0)
- AddRelationships(data, contextEntity, entity);
-
- return data;
- }
- private bool ShouldIncludeAttribute(AttrAttribute attr, object attributeValue, RelationshipAttribute relationship = null)
- {
- return OmitNullValuedAttribute(attr, attributeValue) == false
- && attr.InternalAttributeName != nameof(Identifiable.Id)
- && ((_jsonApiContext.QuerySet == null
- || _jsonApiContext.QuerySet.Fields.Count == 0)
- || _jsonApiContext.QuerySet.Fields.Contains(relationship != null ?
- $"{relationship.InternalRelationshipName}.{attr.InternalAttributeName}" :
- attr.InternalAttributeName));
- }
-
- private bool OmitNullValuedAttribute(AttrAttribute attr, object attributeValue)
- {
- return attributeValue == null && _documentBuilderOptions.OmitNullValuedAttributes;
- }
-
- private void AddRelationships(ResourceObject data, ContextEntity contextEntity, IIdentifiable entity)
- {
- data.Relationships = new Dictionary();
- contextEntity.Relationships.ForEach(r =>
- data.Relationships.Add(
- r.PublicRelationshipName,
- GetRelationshipData(r, contextEntity, entity)
- )
- );
- }
-
- private RelationshipData GetRelationshipData(RelationshipAttribute attr, ContextEntity contextEntity, IIdentifiable entity)
- {
- var linkBuilder = new LinkBuilder(_jsonApiContext);
-
- var relationshipData = new RelationshipData();
-
- if (_jsonApiContext.Options.DefaultRelationshipLinks.HasFlag(Link.None) == false && attr.DocumentLinks.HasFlag(Link.None) == false)
- {
- relationshipData.Links = new Links();
- if (attr.DocumentLinks.HasFlag(Link.Self))
- relationshipData.Links.Self = linkBuilder.GetSelfRelationLink(contextEntity.EntityName, entity.StringId, attr.PublicRelationshipName);
-
- if (attr.DocumentLinks.HasFlag(Link.Related))
- relationshipData.Links.Related = linkBuilder.GetRelatedRelationLink(contextEntity.EntityName, entity.StringId, attr.PublicRelationshipName);
- }
-
- // this only includes the navigation property, we need to actually check the navigation property Id
- var navigationEntity = _jsonApiContext.ResourceGraph.GetRelationshipValue(entity, attr);
- if (navigationEntity == null)
- relationshipData.SingleData = attr.IsHasOne
- ? GetIndependentRelationshipIdentifier((HasOneAttribute)attr, entity)
- : null;
- else if (navigationEntity is IEnumerable)
- relationshipData.ManyData = GetRelationships((IEnumerable