Skip to content

[draft] Feat/serializer context decoupling #512

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

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ See [the documentation](https://json-api-dotnet.github.io/#/) for detailed usage

```csharp
public class Article : Identifiable
{
{
[Attr("name")]
public string Name { get; set; }
}
Expand Down Expand Up @@ -91,7 +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
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Exporters;
using BenchmarkDotNet.Attributes.Jobs;
using System;

namespace Benchmarks.LinkBuilder
{
[MarkdownExporter, SimpleJob(launchCount : 3, warmupCount : 10, targetCount : 20), MemoryDiagnoser]
[MarkdownExporter, SimpleJob(launchCount: 3, warmupCount: 10, targetCount: 20), MemoryDiagnoser]
public class LinkBuilder_GetNamespaceFromPath_Benchmarks
{
private const string PATH = "/api/some-really-long-namespace-path/resources/current/articles";
Expand All @@ -14,7 +15,7 @@ public class LinkBuilder_GetNamespaceFromPath_Benchmarks
public void UsingSplit() => GetNamespaceFromPath_BySplitting(PATH, ENTITY_NAME);

[Benchmark]
public void Current() => GetNameSpaceFromPath_Current(PATH, ENTITY_NAME);
public void Current() => GetNameSpaceFromPathCurrent(PATH, ENTITY_NAME);

public static string GetNamespaceFromPath_BySplitting(string path, string entityName)
{
Expand All @@ -32,7 +33,38 @@ public static string GetNamespaceFromPath_BySplitting(string path, string entity
return nSpace;
}

public static string GetNameSpaceFromPath_Current(string path, string entityName)
=> JsonApiDotNetCore.Builders.LinkBuilder.GetNamespaceFromPath(path, entityName);
public static string GetNameSpaceFromPathCurrent(string path, string entityName)
{

var entityNameSpan = entityName.AsSpan();
var pathSpan = path.AsSpan();
const char delimiter = '/';
for (var i = 0; i < pathSpan.Length; i++)
{
if (pathSpan[i].Equals(delimiter))
{
var nextPosition = i + 1;
if (pathSpan.Length > i + entityNameSpan.Length)
{
var possiblePathSegment = pathSpan.Slice(nextPosition, entityNameSpan.Length);
if (entityNameSpan.SequenceEqual(possiblePathSegment))
{
// check to see if it's the last position in the string
// or if the next character is a /
var lastCharacterPosition = nextPosition + entityNameSpan.Length;

if (lastCharacterPosition == pathSpan.Length || pathSpan.Length >= lastCharacterPosition + 2 && pathSpan[lastCharacterPosition].Equals(delimiter))
{
return pathSpan.Slice(0, i).ToString();
}
}
}
}
}

return string.Empty;


}
}
}
4 changes: 2 additions & 2 deletions benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Running;
using Benchmarks.JsonApiContext;
using Benchmarks.LinkBuilder;
using Benchmarks.Query;
Expand All @@ -10,7 +10,7 @@ class Program {
static void Main(string[] args) {
var switcher = new BenchmarkSwitcher(new[] {
typeof(JsonApiDeserializer_Benchmarks),
typeof(JsonApiSerializer_Benchmarks),
//typeof(JsonApiSerializer_Benchmarks),
typeof(QueryParser_Benchmarks),
typeof(LinkBuilder_GetNamespaceFromPath_Benchmarks),
typeof(ContainsMediaTypeParameters_Benchmarks),
Expand Down
11 changes: 6 additions & 5 deletions benchmarks/Query/QueryParser_Benchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using BenchmarkDotNet.Attributes.Jobs;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Managers.Contracts;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;
using Microsoft.AspNetCore.Http.Internal;
Expand All @@ -21,14 +22,14 @@ public class QueryParser_Benchmarks {
private const string DESCENDING_SORT = "-" + ATTRIBUTE;

public QueryParser_Benchmarks() {
var controllerContextMock = new Mock<IControllerContext>();
controllerContextMock.Setup(m => m.RequestEntity).Returns(new ContextEntity {
var requestMock = new Mock<IRequestManager>();
requestMock.Setup(m => m.GetContextEntity()).Returns(new ContextEntity {
Attributes = new List<AttrAttribute> {
new AttrAttribute(ATTRIBUTE, ATTRIBUTE)
}
});
var options = new JsonApiOptions();
_queryParser = new BenchmarkFacade(controllerContextMock.Object, options);
_queryParser = new BenchmarkFacade(requestMock.Object, options);
}

[Benchmark]
Expand Down Expand Up @@ -58,8 +59,8 @@ private void Run(int iterations, Action action) {
// this facade allows us to expose and micro-benchmark protected methods
private class BenchmarkFacade : QueryParser {
public BenchmarkFacade(
IControllerContext controllerContext,
JsonApiOptions options) : base(controllerContext, options) { }
IRequestManager requestManager,
JsonApiOptions options) : base(requestManager, options) { }

public void _ParseSortParameters(string value) => base.ParseSortParameters(value);
}
Expand Down
98 changes: 49 additions & 49 deletions benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Exporters;
using JsonApiDotNetCore.Builders;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Internal.Generics;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Serialization;
using JsonApiDotNetCore.Services;
using Moq;
using Newtonsoft.Json.Serialization;

namespace Benchmarks.Serialization {
[MarkdownExporter]
public class JsonApiSerializer_Benchmarks {
private const string TYPE_NAME = "simple-types";
private static readonly SimpleType Content = new SimpleType();

private readonly JsonApiSerializer _jsonApiSerializer;

public JsonApiSerializer_Benchmarks() {
var resourceGraphBuilder = new ResourceGraphBuilder();
resourceGraphBuilder.AddResource<SimpleType>(TYPE_NAME);
var resourceGraph = resourceGraphBuilder.Build();

var jsonApiContextMock = new Mock<IJsonApiContext>();
jsonApiContextMock.SetupAllProperties();
jsonApiContextMock.Setup(m => m.ResourceGraph).Returns(resourceGraph);
jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary<AttrAttribute, object>());

var jsonApiOptions = new JsonApiOptions();
jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions);

var genericProcessorFactoryMock = new Mock<IGenericProcessorFactory>();

var documentBuilder = new DocumentBuilder(jsonApiContextMock.Object);
_jsonApiSerializer = new JsonApiSerializer(jsonApiContextMock.Object, documentBuilder);
}

[Benchmark]
public object SerializeSimpleObject() => _jsonApiSerializer.Serialize(Content);

private class SimpleType : Identifiable {
[Attr("name")]
public string Name { get; set; }
}
}
}
//using System.Collections.Generic;
//using BenchmarkDotNet.Attributes;
//using BenchmarkDotNet.Attributes.Exporters;
//using JsonApiDotNetCore.Builders;
//using JsonApiDotNetCore.Configuration;
//using JsonApiDotNetCore.Internal.Generics;
//using JsonApiDotNetCore.Models;
//using JsonApiDotNetCore.Serialization;
//using JsonApiDotNetCore.Services;
//using Moq;
//using Newtonsoft.Json.Serialization;

//namespace Benchmarks.Serialization {
// [MarkdownExporter]
// public class JsonApiSerializer_Benchmarks {
// private const string TYPE_NAME = "simple-types";
// private static readonly SimpleType Content = new SimpleType();

// private readonly JsonApiSerializer _jsonApiSerializer;

// public JsonApiSerializer_Benchmarks() {
// var resourceGraphBuilder = new ResourceGraphBuilder();
// resourceGraphBuilder.AddResource<SimpleType>(TYPE_NAME);
// var resourceGraph = resourceGraphBuilder.Build();

// var jsonApiContextMock = new Mock<IJsonApiContext>();
// jsonApiContextMock.SetupAllProperties();
// jsonApiContextMock.Setup(m => m.ResourceGraph).Returns(resourceGraph);
// jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary<AttrAttribute, object>());

// var jsonApiOptions = new JsonApiOptions();
// jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions);

// var genericProcessorFactoryMock = new Mock<IGenericProcessorFactory>();

// var documentBuilder = new DocumentBuilder(jsonApiContextMock.Object);
// _jsonApiSerializer = new JsonApiSerializer(jsonApiContextMock.Object, documentBuilder);
// }

// [Benchmark]
// public object SerializeSimpleObject() => _jsonApiSerializer.Serialize(Content);

// private class SimpleType : Identifiable {
// [Attr("name")]
// public string Name { get; set; }
// }
// }
//}
3 changes: 3 additions & 0 deletions docs/obsoletes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# For v5

* Anything to do with JsonApiContext, make it internal and fix anything related to it.
5 changes: 5 additions & 0 deletions markdownlint.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"MD033": {
"allowed_elements": [ "p", "img", "p" ]
}
}
11 changes: 7 additions & 4 deletions src/Examples/GettingStarted/Controllers/ArticlesController.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using GettingStarted.Models;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Controllers;
using JsonApiDotNetCore.Internal.Contracts;
using JsonApiDotNetCore.Services;

namespace GettingStarted
{
public class ArticlesController : JsonApiController<Article>
{
public ArticlesController(
IJsonApiContext jsonApiContext,
IResourceService<Article> resourceService)
: base(jsonApiContext, resourceService)
IJsonApiOptions jsonApiOptions,
IResourceGraph resourceGraph,
IResourceService<Article> resourceService)
: base(jsonApiOptions, resourceGraph, resourceService)
{ }
}
}
}
11 changes: 7 additions & 4 deletions src/Examples/GettingStarted/Controllers/PeopleController.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using GettingStarted.Models;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Controllers;
using JsonApiDotNetCore.Internal.Contracts;
using JsonApiDotNetCore.Services;

namespace GettingStarted
{
public class PeopleController : JsonApiController<Person>
{
public PeopleController(
IJsonApiContext jsonApiContext,
IResourceService<Person> resourceService)
: base(jsonApiContext, resourceService)
IJsonApiOptions jsonApiOptions,
IResourceGraph resourceGraph,
IResourceService<Person> resourceService)
: base(jsonApiOptions, resourceGraph, resourceService)
{ }
}
}
}
44 changes: 24 additions & 20 deletions src/Examples/GettingStarted/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56042/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56042/",
"sslPort": 0
}
},
"GettingStarted": {
"commandName": "Project",
"launchBrowser": true
"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
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Internal.Contracts;
using JsonApiDotNetCore.Models;

namespace GettingStarted.ResourceDefinitionExample
Expand All @@ -18,4 +19,4 @@ public ModelDefinition(IResourceGraph graph) : base(graph)
protected override List<AttrAttribute> OutputAttrs()
=> Remove(model => model.DontExpose);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
using GettingStarted.Models;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Controllers;
using JsonApiDotNetCore.Internal.Contracts;
using JsonApiDotNetCore.Services;

namespace GettingStarted.ResourceDefinitionExample
{
public class ModelsController : JsonApiController<Model>
{
public ModelsController(
IJsonApiContext jsonApiContext,
IResourceService<Model> resourceService)
: base(jsonApiContext, resourceService)
IJsonApiOptions jsonApiOptions,
IResourceGraph resourceGraph,
IResourceService<Model> resourceService)
: base(jsonApiOptions, resourceGraph, resourceService)
{ }
}
}
}
Loading