Skip to content

Feat/serializer context decoupling #506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
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
29 changes: 20 additions & 9 deletions JsonApiDotnetCore.sln
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2010

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28606.126
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCore", "src\JsonApiDotNetCore\JsonApiDotNetCore.csproj", "{C0EC9E70-EB2E-436F-9D94-FA16FA774123}"
EndProject
Expand Down Expand Up @@ -41,13 +42,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OperationsExample", "src\Ex
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OperationsExampleTests", "test\OperationsExampleTests\OperationsExampleTests.csproj", "{9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceEntitySeparationExample", "src\Examples\ResourceEntitySeparationExample\ResourceEntitySeparationExample.csproj", "{F4097194-9415-418A-AB4E-315C5D5466AF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResourceEntitySeparationExample", "src\Examples\ResourceEntitySeparationExample\ResourceEntitySeparationExample.csproj", "{F4097194-9415-418A-AB4E-315C5D5466AF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceEntitySeparationExampleTests", "test\ResourceEntitySeparationExampleTests\ResourceEntitySeparationExampleTests.csproj", "{6DFA30D7-1679-4333-9779-6FB678E48EF5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResourceEntitySeparationExampleTests", "test\ResourceEntitySeparationExampleTests\ResourceEntitySeparationExampleTests.csproj", "{6DFA30D7-1679-4333-9779-6FB678E48EF5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GettingStarted", "src\Examples\GettingStarted\GettingStarted.csproj", "{DF9BFD82-D937-4907-B0B4-64670417115F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GettingStarted", "src\Examples\GettingStarted\GettingStarted.csproj", "{DF9BFD82-D937-4907-B0B4-64670417115F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscoveryTests", "test\DiscoveryTests\DiscoveryTests.csproj", "{09C0C8D8-B721-4955-8889-55CB149C3B5C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscoveryTests", "test\DiscoveryTests\DiscoveryTests.csproj", "{09C0C8D8-B721-4955-8889-55CB149C3B5C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -191,6 +192,18 @@ Global
{6DFA30D7-1679-4333-9779-6FB678E48EF5}.Release|x64.Build.0 = Release|Any CPU
{6DFA30D7-1679-4333-9779-6FB678E48EF5}.Release|x86.ActiveCfg = Release|Any CPU
{6DFA30D7-1679-4333-9779-6FB678E48EF5}.Release|x86.Build.0 = Release|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|x64.ActiveCfg = Debug|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|x64.Build.0 = Debug|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|x86.ActiveCfg = Debug|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|x86.Build.0 = Debug|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Release|Any CPU.Build.0 = Release|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Release|x64.ActiveCfg = Release|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Release|x64.Build.0 = Release|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Release|x86.ActiveCfg = Release|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Release|x86.Build.0 = Release|Any CPU
{09C0C8D8-B721-4955-8889-55CB149C3B5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09C0C8D8-B721-4955-8889-55CB149C3B5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09C0C8D8-B721-4955-8889-55CB149C3B5C}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand All @@ -203,8 +216,6 @@ Global
{09C0C8D8-B721-4955-8889-55CB149C3B5C}.Release|x64.Build.0 = Release|Any CPU
{09C0C8D8-B721-4955-8889-55CB149C3B5C}.Release|x86.ActiveCfg = Release|Any CPU
{09C0C8D8-B721-4955-8889-55CB149C3B5C}.Release|x86.Build.0 = Release|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,7 @@ Running tests locally requires access to a postgresql database.
If you have docker installed, this can be propped up via:

```bash
docker run --rm --name jsonapi-dotnet-core-testing \
-e POSTGRES_DB=JsonApiDotNetCoreExample \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
postgres
docker run --rm --name jsonapi-dotnet-core-testing -e POSTGRES_DB=JsonApiDotNetCoreExample -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres
```

And then to run the tests:
Expand Down
27 changes: 27 additions & 0 deletions src/Examples/GettingStarted/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49299/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"GettingStarted": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:49300/"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@ namespace JsonApiDotNetCoreExample.Controllers
{
public class TodoCollectionsController : JsonApiController<TodoItemCollection, Guid>
{

readonly IDbContextResolver _dbResolver;

public TodoCollectionsController(
IDbContextResolver contextResolver,
IJsonApiContext jsonApiContext,
IResourceService<TodoItemCollection, Guid> resourceService,
ILoggerFactory loggerFactory)
: base(jsonApiContext, resourceService, loggerFactory)
public TodoCollectionsController(
IDbContextResolver contextResolver,
IJsonApiContext jsonApiContext,
IResourceService<TodoItemCollection, Guid> resourceService,
ILoggerFactory loggerFactory)
: base(jsonApiContext, resourceService, loggerFactory)
{
_dbResolver = contextResolver;

}

[HttpPatch("{id}")]
Expand All @@ -40,4 +38,4 @@ public override async Task<IActionResult> PatchAsync(Guid id, [FromBody] TodoIte
}

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Data;
using JsonApiDotNetCore.Managers.Contracts;
using JsonApiDotNetCore.Services;
using JsonApiDotNetCoreExample.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace JsonApiDotNetCoreExample.Services
{
public class CustomArticleService : EntityResourceService<Article>
{
public CustomArticleService(
IJsonApiContext jsonApiContext,
IEntityRepository<Article> repository,
IJsonApiOptions jsonApiOptions,
IQueryManager queryManager,
IPageManager pageManager,
ILoggerFactory loggerFactory
) : base(jsonApiContext, repository, jsonApiOptions, queryManager, pageManager, loggerFactory)
{ }

public override async Task<Article> GetAsync(int id)
{
var newEntity = await base.GetAsync(id);
newEntity.Name = "None for you Glen Coco";
return newEntity;
}
}

}
11 changes: 8 additions & 3 deletions src/Examples/JsonApiDotNetCoreExample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
using Microsoft.EntityFrameworkCore;
using JsonApiDotNetCore.Extensions;
using System;
using System.ComponentModel.Design;
using JsonApiDotNetCoreExample.Models;
using JsonApiDotNetCore.Services;

namespace JsonApiDotNetCoreExample
{
Expand Down Expand Up @@ -43,7 +46,10 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services)
mvcBuilder,
discovery => discovery.AddCurrentAssembly());

return services.BuildServiceProvider();
var serviceProvider = services.BuildServiceProvider();


return serviceProvider;
}

public virtual void Configure(
Expand All @@ -53,9 +59,8 @@ public virtual void Configure(
AppDbContext context)
{
context.Database.EnsureCreated();

loggerFactory.AddConsole(Config.GetSection("Logging"));

var serviceProvider = app.ApplicationServices;
app.UseJsonApi();
}

Expand Down
2 changes: 1 addition & 1 deletion src/JsonApiDotNetCore/Builders/IDocumentBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace JsonApiDotNetCore.Builders
public interface IDocumentBuilder
{
/// <summary>
/// Builds a json:api document from the provided resource instance.
/// Builds a Json:Api document from the provided resource instance.
/// </summary>
/// <param name="entity">The resource to convert.</param>
Document Build(IIdentifiable entity);
Expand Down
32 changes: 32 additions & 0 deletions src/JsonApiDotNetCore/Configuration/IJsonApiOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Models;
using Newtonsoft.Json;

namespace JsonApiDotNetCore.Configuration
{
public interface IJsonApiOptions
{
/// <summary>
/// Whether or not the total-record count should be included in all document
/// level meta objects.
/// Defaults to false.
/// </summary>
/// <example>
/// <code>options.IncludeTotalRecordCount = true;</code>
/// </example>
bool IncludeTotalRecordCount { get; set; }
int DefaultPageSize { get; }
bool ValidateModelState { get; }
bool AllowClientGeneratedIds { get; }
JsonSerializerSettings SerializerSettings { get; }
bool EnableOperations { get; set; }
Link DefaultRelationshipLinks { get; set; }
NullAttributeResponseBehavior NullAttributeResponseBehavior { get; set; }
bool RelativeLinks { get; set; }
IResourceGraph ResourceGraph { get; set; }
bool AllowCustomQueryParameters { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace JsonApiDotNetCore.Configuration
/// <summary>
/// Global options
/// </summary>
public class JsonApiOptions
public class JsonApiOptions : IJsonApiOptions
{
/// <summary>
/// Provides an interface for formatting resource names by convention
Expand Down
3 changes: 3 additions & 0 deletions src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,11 @@ public virtual async Task<TEntity> CreateAsync(TEntity entity)
AttachRelationships(entity);
_dbSet.Add(entity);



await _context.SaveChangesAsync();


return entity;
}

Expand Down
10 changes: 8 additions & 2 deletions src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using JsonApiDotNetCore.Graph;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Internal.Generics;
using JsonApiDotNetCore.Managers;
using JsonApiDotNetCore.Managers.Contracts;
using JsonApiDotNetCore.Middleware;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Serialization;
Expand Down Expand Up @@ -64,7 +66,7 @@ public static IServiceCollection AddJsonApi(
{
var config = new JsonApiOptions();
configureOptions(config);

if(autoDiscover != null)
{
var facade = new ServiceDiscoveryFacade(services, config.ResourceGraphBuilder);
Expand Down Expand Up @@ -110,7 +112,9 @@ public static void AddJsonApiInternals(
}

if (jsonApiOptions.EnableOperations)
{
AddOperationServices(services);
}

services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>));
services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>));
Expand All @@ -136,7 +140,8 @@ public static void AddJsonApiInternals(
services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>));
services.AddScoped(typeof(IResourceService<,>), typeof(EntityResourceService<,>));

services.AddSingleton(jsonApiOptions);
services.AddSingleton<IJsonApiOptions>(jsonApiOptions);
services.AddTransient<IPageManager,PageManager>();
services.AddSingleton(jsonApiOptions.ResourceGraph);
services.AddScoped<IJsonApiContext, JsonApiContext>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Expand All @@ -156,6 +161,7 @@ public static void AddJsonApiInternals(
services.AddScoped<IDocumentBuilderOptionsProvider, DocumentBuilderOptionsProvider>();

// services.AddScoped<IActionFilter, TypeMatchFilter>();
services.AddScoped<IQueryManager, QueryManager>();
}

private static void AddOperationServices(IServiceCollection services)
Expand Down
19 changes: 18 additions & 1 deletion src/JsonApiDotNetCore/Graph/ServiceDiscoveryFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,11 @@ public ServiceDiscoveryFacade AddServices(Assembly assembly)

private void AddServices(Assembly assembly, ResourceDescriptor resourceDescriptor)
{

foreach(var serviceInterface in ServiceInterfaces)
RegisterServiceImplementations(assembly, serviceInterface, resourceDescriptor);


}

/// <summary>
Expand All @@ -174,16 +177,30 @@ private void AddRepositories(Assembly assembly, ResourceDescriptor resourceDescr
foreach(var serviceInterface in RepositoryInterfaces)
RegisterServiceImplementations(assembly, serviceInterface, resourceDescriptor);
}

public int i = 0;
private void RegisterServiceImplementations(Assembly assembly, Type interfaceType, ResourceDescriptor resourceDescriptor)
{



if (resourceDescriptor.IdType == typeof(Guid) && interfaceType.GetTypeInfo().GenericTypeParameters.Length == 1)
{
return ;
}
var genericArguments = interfaceType.GetTypeInfo().GenericTypeParameters.Length == 2
? new [] { resourceDescriptor.ResourceType, resourceDescriptor.IdType }
: new [] { resourceDescriptor.ResourceType };

var service = TypeLocator.GetGenericInterfaceImplementation(assembly, interfaceType, genericArguments);
if(service.implementation?.Name == "CustomArticleService" && genericArguments[0].Name != "Article")
{

service = TypeLocator.GetGenericInterfaceImplementation(assembly, interfaceType, genericArguments);
}
if (service.implementation != null)
{
_services.AddScoped(service.registrationInterface, service.implementation);
}
}
}
}
Loading