diff --git a/.travis.yml b/.travis.yml
index 7ac38bba9f..9c5e937589 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,12 @@
language: csharp
dist: trusty
sudo: required
-services:
+services:
- postgresql
before_script:
- psql -c 'create database JsonApiDotNetCoreExample;' -U postgres
mono: none
-dotnet: 2.1.105 # https://www.microsoft.com/net/download/linux
+dotnet: 2.1.300 # https://www.microsoft.com/net/download/linux
branches:
only:
- master
diff --git a/Directory.Build.props b/Directory.Build.props
index 346835dd6c..0d034e0c5d 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -4,28 +4,27 @@
netcoreapp2.0
netstandard2.0
- 2.0.1
+ 2.1.0
- 2.0.0
- 2.0.0
- 2.0.0
+ 2.1.0
+ 2.1.0
+ 2.1.0
- 2.0.1
- 2.0.1
+ 2.1.0
+ 2.1.0
- 3.2.6
- 2.0.0
+ 4.0.0
+ 2.1.0
- 4.4.0
+ 4.5.0
- 15.3.0-preview-20170427-09
- 1.1.2
- 2.3.0-beta3-build3705
- 15.0.3
- 4.7.99
+ 15.7.2
+ 2.3.1
+ 22.1.2
+ 4.8.3
diff --git a/README.md b/README.md
index 2250ef4568..81ebba79bf 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,14 @@ These are some steps you can take to help you understand what this project is an
- [The json:api specification](http://jsonapi.org/format/)
- [Demo [Video]](https://youtu.be/KAMuo6K7VcE)
- [Our documentation](https://json-api-dotnet.github.io)
-- Check out the examples in the next section
+- [Check out the example projects](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/src/Examples)
+
+## Related Projects
+
+- [Performance Reports](https://github.com/json-api-dotnet/PerformanceReports)
+- [JsonApiDotNetCore.MongoDb](https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb)
+- [JsonApiDotNetCore.Marten](https://github.com/wayne-o/JsonApiDotNetCore.Marten)
+- [Todo List App](https://github.com/json-api-dotnet/TodoListExample)
## Examples
diff --git a/benchmarks/Benchmarks.csproj b/benchmarks/Benchmarks.csproj
index 1e8b227f3c..60a9a8bf42 100644
--- a/benchmarks/Benchmarks.csproj
+++ b/benchmarks/Benchmarks.csproj
@@ -5,11 +5,11 @@
Benchmarks
-
+
-
+
diff --git a/src/Examples/JsonApiDotNetCoreExample/Controllers/Restricted/ReadOnlyController.cs b/src/Examples/JsonApiDotNetCoreExample/Controllers/Restricted/ReadOnlyController.cs
index 57fafc8fc6..2515b1ea7a 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Controllers/Restricted/ReadOnlyController.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Controllers/Restricted/ReadOnlyController.cs
@@ -5,7 +5,7 @@ namespace JsonApiDotNetCoreExample.Controllers.Restricted
{
[Route("[controller]")]
[HttpReadOnly]
- public class ReadOnlyController : Controller
+ public class ReadOnlyController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok();
@@ -22,7 +22,7 @@ public class ReadOnlyController : Controller
[Route("[controller]")]
[NoHttpPost]
- public class NoHttpPostController : Controller
+ public class NoHttpPostController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok();
@@ -39,7 +39,7 @@ public class NoHttpPostController : Controller
[Route("[controller]")]
[NoHttpPatch]
- public class NoHttpPatchController : Controller
+ public class NoHttpPatchController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok();
@@ -56,7 +56,7 @@ public class NoHttpPatchController : Controller
[Route("[controller]")]
[NoHttpDelete]
- public class NoHttpDeleteController : Controller
+ public class NoHttpDeleteController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok();
diff --git a/src/Examples/JsonApiDotNetCoreExample/Controllers/TestValuesController.cs b/src/Examples/JsonApiDotNetCoreExample/Controllers/TestValuesController.cs
index 3443d34b74..a29295c426 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Controllers/TestValuesController.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Controllers/TestValuesController.cs
@@ -3,7 +3,7 @@
namespace JsonApiDotNetCoreExample.Controllers
{
[Route("[controller]")]
- public class TestValuesController : Controller
+ public class TestValuesController : ControllerBase
{
[HttpGet]
public IActionResult Get()
diff --git a/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsCustomController.cs b/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsCustomController.cs
index de784c129a..f5f3e111d9 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsCustomController.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsCustomController.cs
@@ -33,17 +33,12 @@ public CustomJsonApiController(
}
public class CustomJsonApiController
- : Controller where T : class, IIdentifiable
+ : ControllerBase where T : class, IIdentifiable
{
private readonly ILogger _logger;
private readonly IResourceService _resourceService;
private readonly IJsonApiContext _jsonApiContext;
- protected IActionResult UnprocessableEntity()
- {
- return new StatusCodeResult(422);
- }
-
protected IActionResult Forbidden()
{
return new StatusCodeResult(403);
diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj
index 94e2a404a9..fd657e83bf 100755
--- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj
+++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj
@@ -26,8 +26,4 @@
-
-
-
-
diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs
index c86425b00c..c9788bf82f 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs
@@ -1,4 +1,4 @@
-//
+//
using JsonApiDotNetCoreExample.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
@@ -7,6 +7,7 @@
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using System;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace JsonApiDotNetCoreExample.Migrations
{
diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs
index ba19b62ef6..cc696f54bf 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs
@@ -1,7 +1,8 @@
-using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace JsonApiDotNetCoreExample.Migrations
{
diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs
index c0794103fe..08c284393e 100755
--- a/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs
@@ -1,4 +1,4 @@
-//
+//
using JsonApiDotNetCoreExample.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
@@ -7,6 +7,7 @@
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using System;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace JsonApiDotNetCoreExample.Migrations
{
diff --git a/src/Examples/JsonApiDotNetCoreExample/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startup.cs
index 1388004a55..2c7574e1a2 100644
--- a/src/Examples/JsonApiDotNetCoreExample/Startup.cs
+++ b/src/Examples/JsonApiDotNetCoreExample/Startup.cs
@@ -28,20 +28,17 @@ public Startup(IHostingEnvironment env)
public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
var loggerFactory = new LoggerFactory();
- loggerFactory.AddConsole(LogLevel.Trace);
- services.AddSingleton(loggerFactory);
+ loggerFactory.AddConsole(LogLevel.Warning);
- services.AddDbContext(options =>
- {
- options.UseNpgsql(GetDbConnectionString());
- }, ServiceLifetime.Transient);
-
- services.AddJsonApi(opt =>
- {
- opt.Namespace = "api/v1";
- opt.DefaultPageSize = 5;
- opt.IncludeTotalRecordCount = true;
- });
+ services
+ .AddSingleton(loggerFactory)
+ .AddDbContext(options =>
+ options.UseNpgsql(GetDbConnectionString()), ServiceLifetime.Transient)
+ .AddJsonApi(options => {
+ options.Namespace = "api/v1";
+ options.DefaultPageSize = 5;
+ options.IncludeTotalRecordCount = true;
+ });
var provider = services.BuildServiceProvider();
var appContext = provider.GetRequiredService();
@@ -60,11 +57,10 @@ public virtual void Configure(
context.Database.EnsureCreated();
loggerFactory.AddConsole(Config.GetSection("Logging"));
- loggerFactory.AddDebug();
app.UseJsonApi();
}
public string GetDbConnectionString() => Config["Data:DefaultConnection"];
}
-}
\ No newline at end of file
+}
diff --git a/src/Examples/JsonApiDotNetCoreExample/appsettings.json b/src/Examples/JsonApiDotNetCoreExample/appsettings.json
index 578225ef14..c468439079 100755
--- a/src/Examples/JsonApiDotNetCoreExample/appsettings.json
+++ b/src/Examples/JsonApiDotNetCoreExample/appsettings.json
@@ -5,9 +5,9 @@
"Logging": {
"IncludeScopes": false,
"LogLevel": {
- "Default": "Trace",
- "System": "Trace",
- "Microsoft": "Trace"
+ "Default": "Warning",
+ "System": "Warning",
+ "Microsoft": "Warning"
}
}
}
diff --git a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj
index eed5f1b09e..efdaa68e5b 100755
--- a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj
+++ b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/src/Examples/NoEntityFrameworkExample/Startup.cs b/src/Examples/NoEntityFrameworkExample/Startup.cs
index dfba27ddd9..711b54cfa3 100755
--- a/src/Examples/NoEntityFrameworkExample/Startup.cs
+++ b/src/Examples/NoEntityFrameworkExample/Startup.cs
@@ -1,4 +1,4 @@
-using JsonApiDotNetCore.Extensions;
+using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Services;
using JsonApiDotNetCoreExample.Data;
using JsonApiDotNetCoreExample.Models;
@@ -31,7 +31,7 @@ public Startup(IHostingEnvironment env)
public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
- var mvcBuilder = services.AddMvc();
+ var mvcBuilder = services.AddMvcCore();
services.AddJsonApi(options => {
options.Namespace = "api/v1";
@@ -55,7 +55,6 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, AppDbContext context)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
- loggerFactory.AddDebug();
context.Database.EnsureCreated();
diff --git a/src/Examples/OperationsExample/OperationsExample.csproj b/src/Examples/OperationsExample/OperationsExample.csproj
index 69ad5653ce..efb3f2b3d4 100644
--- a/src/Examples/OperationsExample/OperationsExample.csproj
+++ b/src/Examples/OperationsExample/OperationsExample.csproj
@@ -8,7 +8,7 @@
-
+
@@ -27,8 +27,4 @@
-
-
-
-
diff --git a/src/Examples/OperationsExample/Startup.cs b/src/Examples/OperationsExample/Startup.cs
index c11a3e9d26..a889ad85d6 100644
--- a/src/Examples/OperationsExample/Startup.cs
+++ b/src/Examples/OperationsExample/Startup.cs
@@ -27,7 +27,7 @@ public Startup(IHostingEnvironment env)
public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
var loggerFactory = new LoggerFactory();
- loggerFactory.AddConsole(LogLevel.Trace);
+ loggerFactory.AddConsole(LogLevel.Warning);
services.AddSingleton(loggerFactory);
@@ -47,7 +47,6 @@ public virtual void Configure(
context.Database.EnsureCreated();
loggerFactory.AddConsole(Config.GetSection("Logging"));
- loggerFactory.AddDebug();
app.UseJsonApi();
}
diff --git a/src/Examples/OperationsExample/appsettings.json b/src/Examples/OperationsExample/appsettings.json
index 0d77cd40f2..73030b1743 100644
--- a/src/Examples/OperationsExample/appsettings.json
+++ b/src/Examples/OperationsExample/appsettings.json
@@ -5,9 +5,9 @@
"Logging": {
"IncludeScopes": false,
"LogLevel": {
- "Default": "Trace",
- "System": "Trace",
- "Microsoft": "Trace"
+ "Default": "Warning",
+ "System": "Warning",
+ "Microsoft": "Warning"
}
}
}
diff --git a/src/Examples/ReportsExample/ReportsExample.csproj b/src/Examples/ReportsExample/ReportsExample.csproj
index bd4b402071..24c01b9a8d 100644
--- a/src/Examples/ReportsExample/ReportsExample.csproj
+++ b/src/Examples/ReportsExample/ReportsExample.csproj
@@ -13,11 +13,11 @@
-
+
-
+
diff --git a/src/Examples/ReportsExample/Startup.cs b/src/Examples/ReportsExample/Startup.cs
index 72710681b9..fe476c0406 100644
--- a/src/Examples/ReportsExample/Startup.cs
+++ b/src/Examples/ReportsExample/Startup.cs
@@ -25,7 +25,7 @@ public Startup(IHostingEnvironment env)
public virtual void ConfigureServices(IServiceCollection services)
{
- var mvcBuilder = services.AddMvc();
+ var mvcBuilder = services.AddMvcCore();
services.AddJsonApi(opt =>
{
opt.BuildContextGraph(builder =>
diff --git a/src/Examples/ReportsExample/appsettings.json b/src/Examples/ReportsExample/appsettings.json
index 125f7a4ae9..5766595e6d 100644
--- a/src/Examples/ReportsExample/appsettings.json
+++ b/src/Examples/ReportsExample/appsettings.json
@@ -2,7 +2,7 @@
"Logging": {
"IncludeScopes": false,
"LogLevel": {
- "Default": "Information"
+ "Default": "Warning"
}
}
}
diff --git a/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs b/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs
index d8effd4fe3..fe014bced5 100644
--- a/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs
+++ b/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs
@@ -1,11 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
namespace JsonApiDotNetCore.Builders
{
public interface IDocumentBuilderOptionsProvider
{
- DocumentBuilderOptions GetDocumentBuilderOptions();
+ DocumentBuilderOptions GetDocumentBuilderOptions();
}
}
diff --git a/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs b/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs
index 1b10140f5e..125d38b5fc 100644
--- a/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs
+++ b/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs
@@ -1,19 +1,34 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
namespace JsonApiDotNetCore.Configuration
{
+ ///
+ /// Allows null attributes to be ommitted from the response payload
+ ///
public struct NullAttributeResponseBehavior
{
+ /// Do not serialize null attributes
+ ///
+ /// Allow clients to override the serialization behavior through a query parmeter.
+ ///
+ /// ```
+ /// GET /articles?omitNullValuedAttributes=true
+ /// ```
+ ///
+ ///
public NullAttributeResponseBehavior(bool omitNullValuedAttributes = false, bool allowClientOverride = false)
{
OmitNullValuedAttributes = omitNullValuedAttributes;
AllowClientOverride = allowClientOverride;
}
+ ///
+ /// Do not include null attributes in the response payload.
+ ///
public bool OmitNullValuedAttributes { get; }
+
+ ///
+ /// Allows clients to specify a `omitNullValuedAttributes` boolean query param to control
+ /// serialization behavior.
+ ///
public bool AllowClientOverride { get; }
- // ...
}
}
diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs b/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs
index 6fff3a22c8..8c3099dde1 100644
--- a/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs
+++ b/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs
@@ -5,13 +5,8 @@
namespace JsonApiDotNetCore.Controllers
{
- public abstract class JsonApiControllerMixin : Controller
+ public abstract class JsonApiControllerMixin : ControllerBase
{
- protected IActionResult UnprocessableEntity()
- {
- return new StatusCodeResult(422);
- }
-
protected IActionResult Forbidden()
{
return new StatusCodeResult(403);
@@ -23,18 +18,19 @@ protected IActionResult Error(Error error)
{
Errors = new List { error }
};
- var result = new ObjectResult(errorCollection);
- result.StatusCode = error.StatusCode;
- return result;
+ return new ObjectResult(errorCollection)
+ {
+ StatusCode = error.StatusCode
+ };
}
protected IActionResult Errors(ErrorCollection errors)
{
- var result = new ObjectResult(errors);
- result.StatusCode = GetErrorStatusCode(errors);
-
- return result;
+ return new ObjectResult(errors)
+ {
+ StatusCode = GetErrorStatusCode(errors)
+ };
}
private int GetErrorStatusCode(ErrorCollection errors)
diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs
index c3b667bc7d..f6db9f0d06 100644
--- a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs
+++ b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs
@@ -8,7 +8,7 @@ namespace JsonApiDotNetCore.Controllers
///
/// A controller to be used for bulk operations as defined in the json:api 1.1 specification
///
- public class JsonApiOperationsController : Controller
+ public class JsonApiOperationsController : ControllerBase
{
private readonly IOperationsProcessor _operationsProcessor;
diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs
index 807d21c018..5e8eeefdd1 100644
--- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs
+++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs
@@ -20,23 +20,23 @@ namespace JsonApiDotNetCore.Extensions
// ReSharper disable once InconsistentNaming
public static class IServiceCollectionExtensions
{
- public static void AddJsonApi(this IServiceCollection services)
+ public static IServiceCollection AddJsonApi(this IServiceCollection services)
where TContext : DbContext
{
- var mvcBuilder = services.AddMvc();
- AddJsonApi(services, (opt) => { }, mvcBuilder);
+ var mvcBuilder = services.AddMvcCore();
+ return AddJsonApi(services, opt => { }, mvcBuilder);
}
- public static void AddJsonApi(this IServiceCollection services, Action options)
+ public static IServiceCollection AddJsonApi(this IServiceCollection services, Action options)
where TContext : DbContext
{
- var mvcBuilder = services.AddMvc();
- AddJsonApi(services, options, mvcBuilder);
+ var mvcBuilder = services.AddMvcCore();
+ return AddJsonApi(services, options, mvcBuilder);
}
- public static void AddJsonApi(this IServiceCollection services,
+ public static IServiceCollection AddJsonApi(this IServiceCollection services,
Action options,
- IMvcBuilder mvcBuilder) where TContext : DbContext
+ IMvcCoreBuilder mvcBuilder) where TContext : DbContext
{
var config = new JsonApiOptions();
@@ -52,11 +52,12 @@ public static void AddJsonApi(this IServiceCollection services,
});
AddJsonApiInternals(services, config);
+ return services;
}
- public static void AddJsonApi(this IServiceCollection services,
+ public static IServiceCollection AddJsonApi(this IServiceCollection services,
Action options,
- IMvcBuilder mvcBuilder)
+ IMvcCoreBuilder mvcBuilder)
{
var config = new JsonApiOptions();
@@ -70,6 +71,7 @@ public static void AddJsonApi(this IServiceCollection services,
});
AddJsonApiInternals(services, config);
+ return services;
}
public static void AddJsonApiInternals(
diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj
index 4f52a23002..7019a8e6cc 100755
--- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj
+++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj
@@ -1,6 +1,6 @@
- 2.2.5
+ 2.3.1
$(NetStandardVersion)
JsonApiDotNetCore
JsonApiDotNetCore
@@ -17,12 +17,13 @@
-
+
-
+
-
+
+
diff --git a/src/JsonApiDotNetCore/Models/AttrAttribute.cs b/src/JsonApiDotNetCore/Models/AttrAttribute.cs
index db61cb56ea..f63d48ab70 100644
--- a/src/JsonApiDotNetCore/Models/AttrAttribute.cs
+++ b/src/JsonApiDotNetCore/Models/AttrAttribute.cs
@@ -5,6 +5,26 @@ namespace JsonApiDotNetCore.Models
{
public class AttrAttribute : Attribute
{
+ ///
+ /// Defines a public attribute exposed by the API
+ ///
+ ///
+ /// How this attribute is exposed through the API
+ /// Prevent PATCH requests from updating the value
+ /// Prevent filters on this attribute
+ /// Prevent this attribute from being sorted by
+ ///
+ ///
+ ///
+ ///
+ /// public class Author : Identifiable
+ /// {
+ /// [Attr("name")]
+ /// public string Name { get; set; }
+ /// }
+ ///
+ ///
+ ///
public AttrAttribute(string publicName, bool isImmutable = false, bool isFilterable = true, bool isSortable = true)
{
PublicAttributeName = publicName;
@@ -13,27 +33,58 @@ public AttrAttribute(string publicName, bool isImmutable = false, bool isFiltera
IsSortable = isSortable;
}
- internal AttrAttribute(string publicName, string internalName, bool isImmutable = false)
+ public AttrAttribute(string publicName, string internalName, bool isImmutable = false)
{
PublicAttributeName = publicName;
InternalAttributeName = internalName;
IsImmutable = isImmutable;
}
+ ///
+ /// How this attribute is exposed through the API
+ ///
public string PublicAttributeName { get; }
+
+ ///
+ /// The internal property name this attribute belongs to.
+ ///
public string InternalAttributeName { get; internal set; }
+
+ ///
+ /// Prevents PATCH requests from updating the value.
+ ///
public bool IsImmutable { get; }
+
+ ///
+ /// Whether or not this attribute can be filtered on via a query string filters.
+ /// Attempts to filter on an attribute with `IsFilterable == false` will return
+ /// an HTTP 400 response.
+ ///
public bool IsFilterable { get; }
+
+ ///
+ /// Whether or not this attribute can be sorted on via a query string sort.
+ /// Attempts to filter on an attribute with `IsSortable == false` will return
+ /// an HTTP 400 response.
+ ///
public bool IsSortable { get; }
+ ///
+ /// Get the value of the attribute for the given object.
+ /// Returns null if the attribute does not belong to the
+ /// provided object.
+ ///
public object GetValue(object entity)
{
return entity
.GetType()
.GetProperty(InternalAttributeName)
- .GetValue(entity);
+ ?.GetValue(entity);
}
+ ///
+ /// Sets the value of the attribute on the given object.
+ ///
public void SetValue(object entity, object newValue)
{
var propertyInfo = entity
diff --git a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs
index c2d7594400..877df29146 100644
--- a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs
+++ b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs
@@ -2,16 +2,40 @@ namespace JsonApiDotNetCore.Models
{
public class HasManyAttribute : RelationshipAttribute
{
+ ///
+ /// Create a HasMany relational link to another entity
+ ///
+ ///
+ /// The relationship name as exposed by the API
+ /// Which links are available. Defaults to
+ /// Whether or not this relationship can be included using the ?include=public-name query string
+ ///
+ ///
+ ///
+ ///
+ /// public class Author : Identifiable
+ /// {
+ /// [HasMany("articles"]
+ /// public virtual List Articles { get; set; }
+ /// }
+ ///
+ ///
+ ///
public HasManyAttribute(string publicName, Link documentLinks = Link.All, bool canInclude = true)
: base(publicName, documentLinks, canInclude)
{ }
+ ///
+ /// Sets the value of the property identified by this attribute
+ ///
+ /// The target object
+ /// The new property value
public override void SetValue(object entity, object newValue)
{
var propertyInfo = entity
.GetType()
.GetProperty(InternalRelationshipName);
-
+
propertyInfo.SetValue(entity, newValue);
}
}
diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs
index 20d119ff07..500101cc62 100644
--- a/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs
+++ b/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs
@@ -65,7 +65,11 @@ private string GetErrorJson(object responseObject, ILogger logger)
}
else
{
- logger?.LogInformation("Response was not a JSONAPI entity. Serializing as plain JSON.");
+ if (logger?.IsEnabled(LogLevel.Information) == true)
+ {
+ logger.LogInformation("Response was not a JSONAPI entity. Serializing as plain JSON.");
+ }
+
return JsonConvert.SerializeObject(responseObject);
}
}
diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs
index 642ee00a57..a3094eb8f9 100644
--- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs
+++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs
@@ -89,8 +89,10 @@ public virtual async Task
diff --git a/test/JsonApiDotNetCoreExampleTests/appsettings.json b/test/JsonApiDotNetCoreExampleTests/appsettings.json
index e65cee8d0d..c468439079 100644
--- a/test/JsonApiDotNetCoreExampleTests/appsettings.json
+++ b/test/JsonApiDotNetCoreExampleTests/appsettings.json
@@ -5,9 +5,9 @@
"Logging": {
"IncludeScopes": false,
"LogLevel": {
- "Default": "Error",
- "System": "Information",
- "Microsoft": "Information"
+ "Default": "Warning",
+ "System": "Warning",
+ "Microsoft": "Warning"
}
}
}
diff --git a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj
index f1d4044e0b..c0500c3bbd 100644
--- a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj
+++ b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj
@@ -17,11 +17,11 @@
-
+
-
+
diff --git a/test/NoEntityFrameworkTests/appsettings.json b/test/NoEntityFrameworkTests/appsettings.json
index 01f85e6699..c468439079 100644
--- a/test/NoEntityFrameworkTests/appsettings.json
+++ b/test/NoEntityFrameworkTests/appsettings.json
@@ -5,9 +5,9 @@
"Logging": {
"IncludeScopes": false,
"LogLevel": {
- "Default": "Debug",
- "System": "Information",
- "Microsoft": "Information"
+ "Default": "Warning",
+ "System": "Warning",
+ "Microsoft": "Warning"
}
}
}
diff --git a/test/OperationsExampleTests/Add/AddTests.cs b/test/OperationsExampleTests/Add/AddTests.cs
index 39e9e8a2a6..47aba439d6 100644
--- a/test/OperationsExampleTests/Add/AddTests.cs
+++ b/test/OperationsExampleTests/Add/AddTests.cs
@@ -156,7 +156,7 @@ public async Task Can_Create_Author_With_Article()
Assert.Equal(author.Name, lastAuthor.Name);
// article validation
- Assert.Equal(1, lastAuthor.Articles.Count);
+ Assert.Single(lastAuthor.Articles);
Assert.Equal(article.Name, lastAuthor.Articles[0].Name);
Assert.Equal(articleOperationResult.DataObject.Id, lastAuthor.Articles[0].StringId);
}
diff --git a/test/OperationsExampleTests/Get/GetByIdTests.cs b/test/OperationsExampleTests/Get/GetByIdTests.cs
index 1dee2867ce..1056082895 100644
--- a/test/OperationsExampleTests/Get/GetByIdTests.cs
+++ b/test/OperationsExampleTests/Get/GetByIdTests.cs
@@ -36,14 +36,14 @@ public async Task Can_Get_Author_By_Id()
};
// act
- var result = await PatchAsync("api/bulk", content);
+ var (response, data) = await PatchAsync("api/bulk", content);
// assert
- Assert.NotNull(result.response);
- Assert.NotNull(result.data);
- Assert.Equal(HttpStatusCode.OK, result.response.StatusCode);
- Assert.Equal(1, result.data.Operations.Count);
- Assert.Equal(author.Id.ToString(), result.data.Operations.Single().DataObject.Id);
+ Assert.NotNull(response);
+ Assert.NotNull(data);
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Single(data.Operations);
+ Assert.Equal(author.Id.ToString(), data.Operations.Single().DataObject.Id);
}
[Fact]
@@ -69,7 +69,7 @@ public async Task Get_Author_By_Id_Returns_404_If_NotFound()
Assert.NotNull(response);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
Assert.NotNull(data);
- Assert.Equal(1, data.Errors.Count);
+ Assert.Single(data.Errors);
Assert.True(data.Errors[0].Detail.Contains("authors"), "The error detail should contain the name of the entity that could not be found.");
Assert.True(data.Errors[0].Detail.Contains(authorId), "The error detail should contain the entity id that could not be found");
Assert.True(data.Errors[0].Title.Contains("operation[0]"), "The error title should contain the operation identifier that failed");
diff --git a/test/OperationsExampleTests/Get/GetRelationshipTests.cs b/test/OperationsExampleTests/Get/GetRelationshipTests.cs
index 03f276da17..8599e92a1e 100644
--- a/test/OperationsExampleTests/Get/GetRelationshipTests.cs
+++ b/test/OperationsExampleTests/Get/GetRelationshipTests.cs
@@ -43,7 +43,7 @@ public async Task Can_Get_Article_Author()
Assert.NotNull(response);
Assert.NotNull(data);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- Assert.Equal(1, data.Operations.Count);
+ Assert.Single(data.Operations);
var resourceObject = data.Operations.Single().DataObject;
Assert.Equal(author.Id.ToString(), resourceObject.Id);
Assert.Equal("authors", resourceObject.Type);
diff --git a/test/OperationsExampleTests/Get/GetTests.cs b/test/OperationsExampleTests/Get/GetTests.cs
index bf1c15e3a4..78e7eeb976 100644
--- a/test/OperationsExampleTests/Get/GetTests.cs
+++ b/test/OperationsExampleTests/Get/GetTests.cs
@@ -44,7 +44,7 @@ public async Task Can_Get_Authors()
Assert.NotNull(result.response);
Assert.NotNull(result.data);
Assert.Equal(HttpStatusCode.OK, result.response.StatusCode);
- Assert.Equal(1, result.data.Operations.Count);
+ Assert.Single(result.data.Operations);
Assert.Equal(expectedCount, result.data.Operations.Single().DataList.Count);
}
}
diff --git a/test/OperationsExampleTests/OperationsExampleTests.csproj b/test/OperationsExampleTests/OperationsExampleTests.csproj
index 13f68faf5a..c2c70d6e54 100644
--- a/test/OperationsExampleTests/OperationsExampleTests.csproj
+++ b/test/OperationsExampleTests/OperationsExampleTests.csproj
@@ -10,11 +10,11 @@
-
+
-
-
+
+
diff --git a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs
index 05dea7f29d..191711651d 100644
--- a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs
+++ b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs
@@ -68,7 +68,7 @@ public async Task Cannot_Create_Author_If_Article_Creation_Fails()
// for now, it is up to application implementations to perform validation and
// provide the proper HTTP response code
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
- Assert.Equal(1, data.Errors.Count);
+ Assert.Single(data.Errors);
Assert.Contains("operation[1] (add)", data.Errors[0].Title);
var dbAuthors = await context.Authors.Where(a => a.Name == author.Name).ToListAsync();
diff --git a/test/OperationsExampleTests/Update/UpdateTests.cs b/test/OperationsExampleTests/Update/UpdateTests.cs
index c5d0f20900..c5d220b2f5 100644
--- a/test/OperationsExampleTests/Update/UpdateTests.cs
+++ b/test/OperationsExampleTests/Update/UpdateTests.cs
@@ -52,7 +52,7 @@ public async Task Can_Update_Author()
Assert.NotNull(response);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(data);
- Assert.Equal(1, data.Operations.Count);
+ Assert.Single(data.Operations);
var attrs = data.Operations.Single().DataObject.Attributes;
Assert.Equal(updates.Name, attrs["name"]);
diff --git a/test/OperationsExampleTests/appsettings.json b/test/OperationsExampleTests/appsettings.json
index 0d77cd40f2..73030b1743 100644
--- a/test/OperationsExampleTests/appsettings.json
+++ b/test/OperationsExampleTests/appsettings.json
@@ -5,9 +5,9 @@
"Logging": {
"IncludeScopes": false,
"LogLevel": {
- "Default": "Trace",
- "System": "Trace",
- "Microsoft": "Trace"
+ "Default": "Warning",
+ "System": "Warning",
+ "Microsoft": "Warning"
}
}
}
diff --git a/test/UnitTests/Builders/DocumentBuilder_Tests.cs b/test/UnitTests/Builders/DocumentBuilder_Tests.cs
index fc816765eb..84c1f3f5c7 100644
--- a/test/UnitTests/Builders/DocumentBuilder_Tests.cs
+++ b/test/UnitTests/Builders/DocumentBuilder_Tests.cs
@@ -190,7 +190,7 @@ public void Build_Can_Build_Arrays()
var documents = documentBuilder.Build(entities);
- Assert.Equal(1, documents.Data.Count);
+ Assert.Single(documents.Data);
}
[Fact]
@@ -201,7 +201,7 @@ public void Build_Can_Build_CustomIEnumerables()
var documents = documentBuilder.Build(entities);
- Assert.Equal(1, documents.Data.Count);
+ Assert.Single(documents.Data);
}
diff --git a/test/UnitTests/Controllers/JsonApiControllerMixin_Tests.cs b/test/UnitTests/Controllers/JsonApiControllerMixin_Tests.cs
index a18aeaf668..c7a4a6cb4d 100644
--- a/test/UnitTests/Controllers/JsonApiControllerMixin_Tests.cs
+++ b/test/UnitTests/Controllers/JsonApiControllerMixin_Tests.cs
@@ -16,26 +16,26 @@ public void Errors_Correctly_Infers_Status_Code()
// arrange
var errors422 = new ErrorCollection {
Errors = new List {
- new Error("422", "bad specific"),
- new Error("422", "bad other specific"),
+ new Error(422, "bad specific"),
+ new Error(422, "bad other specific"),
}
};
var errors400 = new ErrorCollection {
Errors = new List {
- new Error("200", "weird"),
- new Error("400", "bad"),
- new Error("422", "bad specific"),
+ new Error(200, "weird"),
+ new Error(400, "bad"),
+ new Error(422, "bad specific"),
}
};
var errors500 = new ErrorCollection {
Errors = new List {
- new Error("200", "weird"),
- new Error("400", "bad"),
- new Error("422", "bad specific"),
- new Error("500", "really bad"),
- new Error("502", "really bad specific"),
+ new Error(200, "weird"),
+ new Error(400, "bad"),
+ new Error(422, "bad specific"),
+ new Error(500, "really bad"),
+ new Error(502, "really bad specific"),
}
};
diff --git a/test/UnitTests/Internal/ContextGraphBuilder_Tests.cs b/test/UnitTests/Internal/ContextGraphBuilder_Tests.cs
index ce8316b89d..5f56ac0bd8 100644
--- a/test/UnitTests/Internal/ContextGraphBuilder_Tests.cs
+++ b/test/UnitTests/Internal/ContextGraphBuilder_Tests.cs
@@ -33,7 +33,7 @@ public void Adding_DbContext_Members_That_DoNot_Implement_IIdentifiable_Creates_
var contextGraph = contextGraphBuilder.Build() as ContextGraph;
// assert
- Assert.Equal(1, contextGraph.ValidationResults.Count);
+ Assert.Single(contextGraph.ValidationResults);
Assert.Contains(contextGraph.ValidationResults, v => v.LogLevel == LogLevel.Warning);
}
diff --git a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs
index ec34d87d24..be16d1d9d7 100644
--- a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs
+++ b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs
@@ -181,7 +181,7 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate()
// assert
Assert.NotNull(result.ComplexMember);
- Assert.Equal(1, attributesToUpdate.Count);
+ Assert.Single(attributesToUpdate);
foreach (var attr in attributesToUpdate)
Assert.False(attr.Key.IsImmutable);
diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj
index a6ed346e7d..f8dde36f41 100644
--- a/test/UnitTests/UnitTests.csproj
+++ b/test/UnitTests/UnitTests.csproj
@@ -4,12 +4,12 @@
false
-
-
+
+
-
+