Skip to content
This repository was archived by the owner on Jan 5, 2020. It is now read-only.

Fix of bug #1

Merged
merged 2 commits into from
Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ namespace JsonApiDotNetCoreIssue.Controllers
[ApiController]
[Route("[controller]")]
[DisableRoutingConvention]
public class WeatherForecastController : BaseJsonApiController<WeatherForecastModel>
public class WeatherForecastController : BaseJsonApiController<WeatherForecast>
{
private readonly IResourceService<WeatherForecastModel, int> _resourceService;
private readonly IResourceService<WeatherForecast, int> _resourceService;

public WeatherForecastController(
IJsonApiContext jsonApiContext,
IResourceService<WeatherForecastModel, int> resourceService)
IResourceService<WeatherForecast, int> resourceService)
: base(jsonApiContext, resourceService)
{
_resourceService = resourceService;
Expand Down
80 changes: 80 additions & 0 deletions JsonApiDotNetCoreIssue/HooksDiscoveryOverride.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JsonApiDotNetCore.Hooks;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;
using Microsoft.Extensions.DependencyInjection;

namespace JsonApiDotNetCoreIssue
{
/// <summary>
/// The default implementation for IHooksDiscovery
/// </summary>
public class HooksDiscoveryOverride<TEntity> : IHooksDiscovery<TEntity> where TEntity : class, IIdentifiable
{
private readonly Type _boundResourceDefinitionType = typeof(ResourceDefinition<TEntity>);
private readonly ResourceHook[] _allHooks;
private readonly ResourceHook[] _databaseValuesAttributeAllowed =
{
ResourceHook.BeforeUpdate,
ResourceHook.BeforeUpdateRelationship,
ResourceHook.BeforeDelete
};

/// <inheritdoc/>
public ResourceHook[] ImplementedHooks { get; private set; }
public ResourceHook[] DatabaseValuesEnabledHooks { get; private set; }
public ResourceHook[] DatabaseValuesDisabledHooks { get; private set; }

public HooksDiscoveryOverride(IServiceProvider provider)
{
_allHooks = Enum.GetValues(typeof(ResourceHook))
.Cast<ResourceHook>()
.Where(h => h != ResourceHook.None)
.ToArray();
using (var scope = provider.CreateScope())
{
var containerType = scope.ServiceProvider.GetService(_boundResourceDefinitionType)?.GetType();
if (containerType == null || containerType == _boundResourceDefinitionType)
return;
DiscoverImplementedHooksForModel(containerType);
}
}

/// <summary>
/// Discovers the implemented hooks for a model.
/// </summary>
/// <returns>The implemented hooks for model.</returns>
void DiscoverImplementedHooksForModel(Type containerType)
{
var implementedHooks = new List<ResourceHook>();
var databaseValuesEnabledHooks = new List<ResourceHook> { ResourceHook.BeforeImplicitUpdateRelationship }; // this hook can only be used with enabled database values
var databaseValuesDisabledHooks = new List<ResourceHook>();
foreach (var hook in _allHooks)
{
var method = containerType.GetMethod(hook.ToString("G"));
if (method.DeclaringType == _boundResourceDefinitionType)
continue;

implementedHooks.Add(hook);
var attr = method.GetCustomAttributes(true).OfType<LoadDatabaseValues>().SingleOrDefault();
if (attr != null)
{
if (!_databaseValuesAttributeAllowed.Contains(hook))
{
throw new JsonApiSetupException($"DatabaseValuesAttribute cannot be used on hook" +
$"{hook.ToString("G")} in resource definition {containerType.Name}");
}
var targetList = attr.value ? databaseValuesEnabledHooks : databaseValuesDisabledHooks;
targetList.Add(hook);
}
}

ImplementedHooks = implementedHooks.ToArray();
DatabaseValuesDisabledHooks = databaseValuesDisabledHooks.ToArray();
DatabaseValuesEnabledHooks = databaseValuesEnabledHooks.ToArray();
}
}
}
5 changes: 4 additions & 1 deletion JsonApiDotNetCoreIssue/JsonApiDotNetCoreIssue.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.App">
<PrivateAssets Condition="'%(PackageReference.Version)' == ''">all</PrivateAssets>
<Publish Condition="'%(PackageReference.Version)' == ''">true</Publish>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.6" />
</ItemGroup>

Expand Down
7 changes: 6 additions & 1 deletion JsonApiDotNetCoreIssue/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading.Tasks;
using JsonApiDotNetCore.Data;
using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Hooks;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;
using Microsoft.AspNetCore.Builder;
Expand Down Expand Up @@ -33,7 +34,7 @@ public void ConfigureServices(IServiceCollection services)
{
options.UseInMemoryDatabase("WeatherForecasts");
})
.AddScoped<IResourceService<WeatherForecastModel, int>, WeatherForecastService>()
.AddScoped<IResourceService<WeatherForecast, int>, WeatherForecastService>()
.AddScoped<IEntityRepository<WeatherForecast>, WeatherForecastRepository>()
.AddScoped<IResourceMapper, WeatherForecastMapper>()
.AddScoped<ResourceDefinition<WeatherForecast>, WeatherForecastDefinition>()
Expand All @@ -42,6 +43,10 @@ public void ConfigureServices(IServiceCollection services)
options.EnableResourceHooks = true;
options.BuildResourceGraph(builder => builder.AddResource<WeatherForecastModel>());
}, services.AddMvcCore().SetCompatibilityVersion(CompatibilityVersion.Version_2_2));

// make sure this override is added AFTER you call AddJsonApi( .. ), because else it is overwritten by it
services.AddSingleton(typeof(IHooksDiscovery<>), typeof(HooksDiscoveryOverride<>));

}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
Expand Down
13 changes: 6 additions & 7 deletions JsonApiDotNetCoreIssue/WeatherForecastService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
using JsonApiDotNetCore.Hooks;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;
using Microsoft.Extensions.Logging;

namespace JsonApiDotNetCoreIssue
{
public class WeatherForecastService : EntityResourceService<WeatherForecastModel, WeatherForecast, int>
public class WeatherForecastService : EntityResourceService<WeatherForecast, int>
{
public WeatherForecastService(
IJsonApiContext jsonApiContext,
IEntityRepository<WeatherForecast, int> entityRepository,
IResourceHookExecutor hookExecutor,
IResourceMapper mapper)
: base(jsonApiContext, entityRepository, hookExecutor, mapper)
public WeatherForecastService(IJsonApiContext jsonApiContext,
IEntityRepository<WeatherForecast, int> entityRepository,
ILoggerFactory loggerFactory = null,
IResourceHookExecutor hookExecutor = null) : base(jsonApiContext, entityRepository, loggerFactory, hookExecutor)
{
}
}
Expand Down