Description
Description
The past weeks I have been trying to implement several features of our existing API using JsonApiDotNetCore. Starting out with custom services and repositories, I am now trying to make more use of hooks. One thing that I'm stuck at is the hook support for reading lists.
Consider the next method in DefaultResourceService
:
public virtual async Task<IEnumerable<TResource>> GetAsync()
{
_hookExecutor?.BeforeRead<TResource>(ResourcePipeline.Get);
var entityQuery = _repository.Get();
entityQuery = ApplyFilter(entityQuery);
entityQuery = ApplySort(entityQuery);
entityQuery = ApplyInclude(entityQuery);
entityQuery = ApplySelect(entityQuery);
if (!IsNull(_hookExecutor, entityQuery))
{
var entities = await _repository.ToListAsync(entityQuery);
_hookExecutor.AfterRead(entities, ResourcePipeline.Get);
entityQuery = _hookExecutor.OnReturn(entities, ResourcePipeline.Get).AsQueryable();
}
if (_options.IncludeTotalRecordCount)
_pageManager.TotalRecords = await _repository.CountAsync(entityQuery);
// pagination should be done last since it will execute the query
var pagedEntities = await ApplyPageQueryAsync(entityQuery);
return pagedEntities;
}
The first thing to notice is that whenever you start to use a hook (OnReturn in my case), paging no longer works server-side. This is unacceptable for large tables. I think that if the hook subscriber really needs the query executed, it should do so itself and live with the consequences.
Something else I found is that hooks cannot be generic. It's unclear to me if that is a bug or by design. To illustrate, the following works:
services.AddScoped<ResourceDefinition<Video>, VideoResourceHookContainer>();
public class VideoResourceHookContainer : TypeEmbeddedIdResourceHookContainer<Video> { }
public class TypeEmbeddedIdResourceHookContainer<TResource>
: ResourceDefinition<TResource>
where TResource : class, IIdentifiable<long>
{
// ...
}
but the following does not:
services.AddScoped<ResourceDefinition<Video>, TypeEmbeddedIdResourceHookContainer<Video>>();
public class TypeEmbeddedIdResourceHookContainer<TResource>
: ResourceDefinition<TResource>
where TResource : class, IIdentifiable<long>
{
// ...
}
Finally, the documentation on the interfaces in IResourceHookExecutor.cs is wrong. For example, IReadHookExecutor contains: "Wrapper interface for all Before execution methods." Also the file contains the misspelling "appropiate" multiple times.
Environment
Latest commit in develop branch.