diff --git a/.gitignore b/.gitignore index 9f911ba396..f432f5ba3f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ \.vs/ + +*.user diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index 7a4f950746..71cba7f264 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -15,6 +15,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C5B4D998-CECB-454D-9F32-085A897577BE}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore + README.md = README.md EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoEntityFrameworkExample", "src\NoEntityFrameworkExample\NoEntityFrameworkExample.csproj", "{570165EC-62B5-4684-A139-8D2A30DD4475}" diff --git a/README.md b/README.md index 4d38f0a0c1..ec0d7610de 100644 --- a/README.md +++ b/README.md @@ -248,9 +248,10 @@ services.AddJsonApi( #### Disable Convention You can disable the dasherized convention and specify your own template -by using the `DisableRoutingConvention` Attribute: +by using the `DisableRoutingConvention` Attribute. ```csharp +[Route("[controller]")] [DisableRoutingConvention] public class CamelCasedModelsController : JsonApiController { @@ -263,6 +264,22 @@ public class CamelCasedModelsController : JsonApiController } ``` +It is important to note that your routes *must* still end with the model name in the same format +as the resource name. This is so that we can build accurrate resource links in the json:api document. +For example, if you define a resource as `MyModels` the controller route must match: + +```csharp +// resource definition +builder.AddResource("myModels"); + +// controller definition +[Route("api/myModels")] +[DisableRoutingConvention] +public class TodoItemsController : JsonApiController +{ //... +} +``` + ### Defining Custom Data Access Methods By default, data retrieval is distributed across 3 layers: @@ -287,7 +304,7 @@ public void ConfigureServices(IServiceCollection services) services.AddJsonApi(options => { options.Namespace = "api/v1"; options.BuildContextGraph((builder) => { - builder.AddResource("my-models"); + builder.AddResource("my-models");1 }); }, mvcBuilder); // ... diff --git a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs index e90f1ca7ff..fec71f97d6 100644 --- a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs @@ -10,18 +10,18 @@ namespace JsonApiDotNetCore.Builders { public class ContextGraphBuilder : IContextGraphBuilder { - private List Entities; + private List _entities; private bool _usesDbContext; public ContextGraphBuilder() { - Entities = new List(); + _entities = new List(); } public IContextGraph Build() { var graph = new ContextGraph() { - Entities = Entities, + Entities = _entities, UsesDbContext = _usesDbContext }; return graph; @@ -30,7 +30,7 @@ public IContextGraph Build() public void AddResource(string pluralizedTypeName) where TResource : class { var entityType = typeof(TResource); - Entities.Add(new ContextEntity + _entities.Add(new ContextEntity { EntityName = pluralizedTypeName, EntityType = entityType, @@ -108,7 +108,7 @@ public void AddDbContext() where T : DbContext } } - Entities = entities; + _entities = entities; } private string GetResourceName(PropertyInfo property) diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index fd9b29a0d5..4662a37668 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -9,8 +9,8 @@ namespace JsonApiDotNetCore.Builders { public class DocumentBuilder : IDocumentBuilder { - private IJsonApiContext _jsonApiContext; - private IContextGraph _contextGraph; + private readonly IJsonApiContext _jsonApiContext; + private readonly IContextGraph _contextGraph; private readonly IRequestMeta _requestMeta; public DocumentBuilder(IJsonApiContext jsonApiContext) @@ -50,14 +50,15 @@ public Documents Build(IEnumerable entities) var contextEntity = _contextGraph.GetContextEntity(entityType); + var enumeratedEntities = entities as IList ?? entities.ToList(); var documents = new Documents { Data = new List(), - Meta = GetMeta(entities.FirstOrDefault()), + Meta = GetMeta(enumeratedEntities.FirstOrDefault()), Links = _jsonApiContext.PageManager.GetPageLinks(new LinkBuilder(_jsonApiContext)) }; - foreach (var entity in entities) + foreach (var entity in enumeratedEntities) { documents.Data.Add(GetData(contextEntity, entity)); documents.Included = AppendIncludedObject(documents.Included, contextEntity, entity); @@ -155,9 +156,9 @@ private void AddRelationships(DocumentData data, ContextEntity contextEntity, II if(navigationEntity == null) relationshipData.SingleData = null; else if (navigationEntity is IEnumerable) - relationshipData.ManyData = GetRelationships((IEnumerable)navigationEntity, r.InternalRelationshipName); + relationshipData.ManyData = GetRelationships((IEnumerable)navigationEntity); else - relationshipData.SingleData = GetRelationship(navigationEntity, r.InternalRelationshipName); + relationshipData.SingleData = GetRelationship(navigationEntity); } data.Relationships.Add(r.PublicRelationshipName, relationshipData); @@ -174,9 +175,9 @@ private List GetIncludedEntities(ContextEntity contextEntity, IIde var navigationEntity = _jsonApiContext.ContextGraph.GetRelationship(entity, r.InternalRelationshipName); - if (navigationEntity is IEnumerable) - foreach (var includedEntity in (IEnumerable)navigationEntity) - AddIncludedEntity(included, (IIdentifiable)includedEntity); + if (navigationEntity is IEnumerable hasManyNavigationEntity) + foreach (IIdentifiable includedEntity in hasManyNavigationEntity) + AddIncludedEntity(included, includedEntity); else AddIncludedEntity(included, (IIdentifiable)navigationEntity); }); @@ -216,7 +217,7 @@ private bool RelationshipIsIncluded(string relationshipName) _jsonApiContext.IncludedRelationships.Contains(relationshipName); } - private List> GetRelationships(IEnumerable entities, string relationshipName) + private List> GetRelationships(IEnumerable entities) { var objType = entities.GetType().GenericTypeArguments[0]; @@ -232,7 +233,7 @@ private List> GetRelationships(IEnumerable en } return relationships; } - private Dictionary GetRelationship(object entity, string relationshipName) + private Dictionary GetRelationship(object entity) { var objType = entity.GetType(); diff --git a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs index 241646a850..83b77c169c 100644 --- a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs @@ -1,4 +1,3 @@ -using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; @@ -6,7 +5,7 @@ namespace JsonApiDotNetCore.Builders { public class LinkBuilder { - IJsonApiContext _context; + private readonly IJsonApiContext _context; public LinkBuilder(IJsonApiContext context) { diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index cacb08ea40..e3e5dd21da 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -20,8 +20,7 @@ public void BuildContextGraph(Action builder) contextGraphBuilder.AddDbContext(); - if(builder != null) - builder(contextGraphBuilder); + builder?.Invoke(contextGraphBuilder); ContextGraph = contextGraphBuilder.Build(); } diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs b/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs index 3200ff36ef..85e7425b75 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs @@ -4,9 +4,6 @@ namespace JsonApiDotNetCore.Controllers { public abstract class JsonApiControllerMixin : Controller { - protected JsonApiControllerMixin() - { } - protected IActionResult UnprocessableEntity() { return new StatusCodeResult(422); diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 5b5125ef91..a9ccac907b 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; @@ -58,8 +59,8 @@ public virtual IQueryable Filter(IQueryable entities, FilterQ if(filterQuery.IsAttributeOfRelationship) return entities.Filter(new RelatedAttrFilterQuery(_jsonApiContext, filterQuery)); - else - return entities.Filter(new AttrFilterQuery(_jsonApiContext, filterQuery)); + + return entities.Filter(new AttrFilterQuery(_jsonApiContext, filterQuery)); } public virtual IQueryable Sort(IQueryable entities, List sortQueries) @@ -69,9 +70,10 @@ public virtual IQueryable Sort(IQueryable entities, List 1) - for(var i=1; i < sortQueries.Count(); i++) - orderedEntities = orderedEntities.Sort(sortQueries[i]); + if (sortQueries.Count <= 1) return orderedEntities; + + for(var i=1; i < sortQueries.Count; i++) + orderedEntities = orderedEntities.Sort(sortQueries[i]); return orderedEntities; } diff --git a/src/JsonApiDotNetCore/Data/IEntityRepository.cs b/src/JsonApiDotNetCore/Data/IEntityRepository.cs index 8df7019f13..547c930b8d 100644 --- a/src/JsonApiDotNetCore/Data/IEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/IEntityRepository.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs b/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs index cf0ded5eb5..c3d7ba2ee7 100644 --- a/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs @@ -1,8 +1,9 @@ using JsonApiDotNetCore.Middleware; using Microsoft.AspNetCore.Builder; -namespace JsonApiDotNetCore.Routing +namespace JsonApiDotNetCore.Extensions { + // ReSharper disable once InconsistentNaming public static class IApplicationBuilderExtensions { public static IApplicationBuilder UseJsonApi(this IApplicationBuilder app, bool useMvc = true) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 62313e3ad9..f5a1db4010 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -8,22 +8,21 @@ namespace JsonApiDotNetCore.Extensions { + // ReSharper disable once InconsistentNaming public static class IQueryableExtensions { public static IOrderedQueryable Sort(this IQueryable source, SortQuery sortQuery) { - if (sortQuery.Direction == SortDirection.Descending) - return source.OrderByDescending(sortQuery.SortedAttribute.InternalAttributeName); - - return source.OrderBy(sortQuery.SortedAttribute.InternalAttributeName); + return sortQuery.Direction == SortDirection.Descending + ? source.OrderByDescending(sortQuery.SortedAttribute.InternalAttributeName) + : source.OrderBy(sortQuery.SortedAttribute.InternalAttributeName); } public static IOrderedQueryable Sort(this IOrderedQueryable source, SortQuery sortQuery) { - if (sortQuery.Direction == SortDirection.Descending) - return source.ThenByDescending(sortQuery.SortedAttribute.InternalAttributeName); - - return source.ThenBy(sortQuery.SortedAttribute.InternalAttributeName); + return sortQuery.Direction == SortDirection.Descending + ? source.ThenByDescending(sortQuery.SortedAttribute.InternalAttributeName) + : source.ThenBy(sortQuery.SortedAttribute.InternalAttributeName); } public static IOrderedQueryable OrderBy(this IQueryable source, string propertyName) @@ -178,10 +177,9 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression return body; } - - public static IQueryable Select(this IQueryable source, IEnumerable columns) + public static IQueryable Select(this IQueryable source, List columns) { - if (columns == null || columns.Count() == 0) + if (columns == null || columns.Any() == false) return source; var sourceType = source.ElementType; @@ -201,7 +199,7 @@ public static IQueryable Select(this IQueryable sourc var selector = Expression.Lambda(body, parameter); return source.Provider.CreateQuery( - Expression.Call(typeof(Queryable), "Select", new Type[] { sourceType, resultType }, + Expression.Call(typeof(Queryable), "Select", new[] { sourceType, resultType }, source.Expression, Expression.Quote(selector))); } } diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 93590cf30b..43bc63da4a 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -4,6 +4,8 @@ using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Formatters; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Internal.Generics; +using JsonApiDotNetCore.Middleware; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; @@ -13,6 +15,7 @@ namespace JsonApiDotNetCore.Extensions { + // ReSharper disable once InconsistentNaming public static class IServiceCollectionExtensions { public static void AddJsonApi(this IServiceCollection services) diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs index 65a2382a73..f9d38c2cfb 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs @@ -4,7 +4,6 @@ using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Newtonsoft.Json; diff --git a/src/JsonApiDotNetCore/Internal/DasherizedRoutingConvention.cs b/src/JsonApiDotNetCore/Internal/DasherizedRoutingConvention.cs index a1385581db..edb7e2444a 100644 --- a/src/JsonApiDotNetCore/Internal/DasherizedRoutingConvention.cs +++ b/src/JsonApiDotNetCore/Internal/DasherizedRoutingConvention.cs @@ -3,14 +3,13 @@ using System.Reflection; using JsonApiDotNetCore.Controllers; using JsonApiDotNetCore.Extensions; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; namespace JsonApiDotNetCore.Internal { public class DasherizedRoutingConvention : IApplicationModelConvention { - private string _namespace; + private readonly string _namespace; public DasherizedRoutingConvention(string nspace) { _namespace = nspace; @@ -20,14 +19,11 @@ public void Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { - var template = string.Empty; - - if (IsDasherizedJsonApiController(controller)) - template = $"{_namespace}/{controller.ControllerName.Dasherize()}"; - else - template = GetTemplate(controller); + if (IsDasherizedJsonApiController(controller) == false) + continue; - controller.Selectors[0].AttributeRouteModel = new AttributeRouteModel() + var template = $"{_namespace}/{controller.ControllerName.Dasherize()}"; + controller.Selectors[0].AttributeRouteModel = new AttributeRouteModel { Template = template }; @@ -40,15 +36,5 @@ private bool IsDasherizedJsonApiController(ControllerModel controller) var notDisabled = type.GetCustomAttribute() == null; return notDisabled && type.IsSubclassOf(typeof(JsonApiControllerMixin)); } - - private string GetTemplate(ControllerModel controller) - { - var type = controller.ControllerType; - var routeAttr = type.GetCustomAttribute(); - if(routeAttr != null) - return ((RouteAttribute)routeAttr).Template; - - return controller.ControllerName; - } } } diff --git a/src/JsonApiDotNetCore/Internal/Error.cs b/src/JsonApiDotNetCore/Internal/Error.cs index b9261324a5..c47f7276b2 100644 --- a/src/JsonApiDotNetCore/Internal/Error.cs +++ b/src/JsonApiDotNetCore/Internal/Error.cs @@ -30,6 +30,6 @@ public Error(string status, string title, string detail) public string Status { get; set; } [JsonIgnore] - public int StatusCode { get { return int.Parse(Status); } } + public int StatusCode => int.Parse(Status); } } diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs index 6958ada265..ce76b47dae 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs @@ -5,7 +5,7 @@ using JsonApiDotNetCore.Models; using Microsoft.EntityFrameworkCore; -namespace JsonApiDotNetCore.Internal +namespace JsonApiDotNetCore.Internal.Generics { public class GenericProcessor : IGenericProcessor where T : class, IIdentifiable { @@ -24,8 +24,6 @@ public async Task UpdateRelationshipsAsync(object parent, RelationshipAttribute public void SetRelationships(object parent, RelationshipAttribute relationship, IEnumerable relationshipIds) { - var relationshipType = relationship.Type; - if (relationship.IsHasMany) { var entities = _context.GetDbSet().Where(x => relationshipIds.Contains(x.StringId)).ToList(); diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs index 7a647bf60f..a238e4ef9f 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs @@ -1,7 +1,7 @@ using System; using Microsoft.EntityFrameworkCore; -namespace JsonApiDotNetCore.Internal +namespace JsonApiDotNetCore.Internal.Generics { public class GenericProcessorFactory : IGenericProcessorFactory { diff --git a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessor.cs b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessor.cs index 27678acf82..d05e47cb6c 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessor.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessor.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using JsonApiDotNetCore.Models; -namespace JsonApiDotNetCore.Internal +namespace JsonApiDotNetCore.Internal.Generics { public interface IGenericProcessor { diff --git a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs index ce959658c4..83e794a12b 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs @@ -1,6 +1,6 @@ using System; -namespace JsonApiDotNetCore.Internal +namespace JsonApiDotNetCore.Internal.Generics { /// /// Used to generate a generic operations processor when the types diff --git a/src/JsonApiDotNetCore/Internal/JsonApiException.cs b/src/JsonApiDotNetCore/Internal/JsonApiException.cs index 907b1db7fd..e62503c379 100644 --- a/src/JsonApiDotNetCore/Internal/JsonApiException.cs +++ b/src/JsonApiDotNetCore/Internal/JsonApiException.cs @@ -5,7 +5,7 @@ namespace JsonApiDotNetCore.Internal { public class JsonApiException : Exception { - private ErrorCollection _errors = new ErrorCollection(); + private readonly ErrorCollection _errors = new ErrorCollection(); public JsonApiException(ErrorCollection errorCollection) { diff --git a/src/JsonApiDotNetCore/Internal/JsonApiRouteHandler.cs b/src/JsonApiDotNetCore/Internal/JsonApiRouteHandler.cs index 393cdb9cbe..3099959ef6 100644 --- a/src/JsonApiDotNetCore/Internal/JsonApiRouteHandler.cs +++ b/src/JsonApiDotNetCore/Internal/JsonApiRouteHandler.cs @@ -11,10 +11,12 @@ namespace JsonApiDotNetCore.Internal { public class JsonApiRouteHandler : IRouter { - private IActionContextAccessor _actionContextAccessor; - private IActionInvokerFactory _actionInvokerFactory; - private IActionSelector _actionSelector; - public JsonApiRouteHandler(IActionInvokerFactory actionInvokerFactory, + private readonly IActionContextAccessor _actionContextAccessor; + private readonly IActionInvokerFactory _actionInvokerFactory; + private readonly IActionSelector _actionSelector; + + public JsonApiRouteHandler( + IActionInvokerFactory actionInvokerFactory, IActionSelector actionSelector) : this(actionInvokerFactory, actionSelector, actionContextAccessor: null) { @@ -28,7 +30,6 @@ public JsonApiRouteHandler( // The IActionContextAccessor is optional. We want to avoid the overhead of using CallContext // if possible. _actionContextAccessor = actionContextAccessor; - _actionInvokerFactory = actionInvokerFactory; _actionSelector = actionSelector; } diff --git a/src/JsonApiDotNetCore/Internal/PageManager.cs b/src/JsonApiDotNetCore/Internal/PageManager.cs index c85d81b1e9..124aaad6dd 100644 --- a/src/JsonApiDotNetCore/Internal/PageManager.cs +++ b/src/JsonApiDotNetCore/Internal/PageManager.cs @@ -10,10 +10,8 @@ public class PageManager public int PageSize { get; set; } public int DefaultPageSize { get; set; } public int CurrentPage { get; set; } - public bool IsPaginated { get { return PageSize > 0; } } - public int TotalPages { - get { return (TotalRecords == 0) ? -1: (int)Math.Ceiling(decimal.Divide(TotalRecords, PageSize)); } - } + public bool IsPaginated => PageSize > 0; + public int TotalPages => (TotalRecords == 0) ? -1: (int)Math.Ceiling(decimal.Divide(TotalRecords, PageSize)); public RootLinks GetPageLinks(LinkBuilder linkBuilder) { @@ -22,9 +20,7 @@ public RootLinks GetPageLinks(LinkBuilder linkBuilder) var rootLinks = new RootLinks(); - var includePageSize = DefaultPageSize != PageSize; - - if(CurrentPage > 1) + if(CurrentPage > 1) rootLinks.First = linkBuilder.GetPageLink(1, PageSize); if(CurrentPage > 1) diff --git a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs index f45d384d72..5a17b59d2a 100644 --- a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs @@ -16,10 +16,7 @@ public AttrFilterQuery( var attribute = GetAttribute(filterQuery.Key); - if (attribute == null) - throw new JsonApiException("400", $"{filterQuery.Key} is not a valid property."); - - FilteredAttribute = attribute; + FilteredAttribute = attribute ?? throw new JsonApiException("400", $"{filterQuery.Key} is not a valid property."); PropertyValue = filterQuery.Value; FilterOperation = GetFilterOperation(filterQuery.Operation); } diff --git a/src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs index fdb2abd4ae..3a677bb247 100644 --- a/src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs @@ -8,8 +8,7 @@ protected FilterOperations GetFilterOperation(string prefix) { if (prefix.Length == 0) return FilterOperations.eq; - FilterOperations opertion; - if (!Enum.TryParse(prefix, out opertion)) + if (!Enum.TryParse(prefix, out FilterOperations opertion)) throw new JsonApiException("400", $"Invalid filter prefix '{prefix}'"); return opertion; diff --git a/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs b/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs index cc6166e422..260dc32655 100644 --- a/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs +++ b/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs @@ -1,3 +1,4 @@ +// ReSharper disable InconsistentNaming namespace JsonApiDotNetCore.Internal.Query { public enum FilterOperations diff --git a/src/JsonApiDotNetCore/Internal/Query/QuerySet.cs b/src/JsonApiDotNetCore/Internal/Query/QuerySet.cs index 6ebc7179a8..9bcdbe0179 100644 --- a/src/JsonApiDotNetCore/Internal/Query/QuerySet.cs +++ b/src/JsonApiDotNetCore/Internal/Query/QuerySet.cs @@ -10,7 +10,7 @@ namespace JsonApiDotNetCore.Internal.Query { public class QuerySet { - IJsonApiContext _jsonApiContext; + private readonly IJsonApiContext _jsonApiContext; public QuerySet( IJsonApiContext jsonApiContext, @@ -99,7 +99,7 @@ private List ParseFilterQuery(string key, string value) var prefix = operation[0]; value = operation[1]; - return (prefix, value);; + return (prefix, value); } private PageQuery ParsePageQuery(string key, string value) diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index 7fb93b8d46..e4168ad08b 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -21,11 +21,9 @@ public RelatedAttrFilterQuery( throw new JsonApiException("400", $"{relationshipArray[0]} is not a valid relationship."); var attribute = GetAttribute(relationship, relationshipArray[1]); - if (attribute == null) - throw new JsonApiException("400", $"{relationshipArray[1]} is not a valid attribute on {relationshipArray[0]}."); FilteredRelationship = relationship; - FilteredAttribute = attribute; + FilteredAttribute = attribute ?? throw new JsonApiException("400", $"{relationshipArray[1]} is not a valid attribute on {relationshipArray[0]}."); PropertyValue = filterQuery.Value; FilterOperation = GetFilterOperation(filterQuery.Operation); } @@ -33,7 +31,7 @@ public RelatedAttrFilterQuery( public AttrAttribute FilteredAttribute { get; set; } public string PropertyValue { get; set; } public FilterOperations FilterOperation { get; set; } - public RelationshipAttribute FilteredRelationship { get; private set; } + public RelationshipAttribute FilteredRelationship { get; } private RelationshipAttribute GetRelationship(string propertyName) { diff --git a/src/JsonApiDotNetCore/Middleware/JsonApiExceptionFilter.cs b/src/JsonApiDotNetCore/Middleware/JsonApiExceptionFilter.cs index ee038e7902..dda1fd3b89 100644 --- a/src/JsonApiDotNetCore/Middleware/JsonApiExceptionFilter.cs +++ b/src/JsonApiDotNetCore/Middleware/JsonApiExceptionFilter.cs @@ -1,15 +1,14 @@ -using System; using JsonApiDotNetCore.Internal; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; -namespace JsonApiDotNetCore.Formatters +namespace JsonApiDotNetCore.Middleware { public class JsonApiExceptionFilter : ActionFilterAttribute, IExceptionFilter { private readonly ILogger _logger; - + public JsonApiExceptionFilter(ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger(); @@ -20,11 +19,13 @@ public void OnException(ExceptionContext context) _logger?.LogError(new EventId(), context.Exception, "An unhandled exception occurred during the request"); var jsonApiException = JsonApiExceptionFactory.GetException(context.Exception); - + var error = jsonApiException.GetError(); - var result = new ObjectResult(error); - result.StatusCode = jsonApiException.GetStatusCode(); - context.Result = result; + var result = new ObjectResult(error) + { + StatusCode = jsonApiException.GetStatusCode() + }; + context.Result = result; } } } diff --git a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs index 036497333f..670def21d6 100644 --- a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs @@ -37,17 +37,16 @@ private static bool IsValidContentTypeHeader(HttpContext context) private static bool IsValidAcceptHeader(HttpContext context) { - var acceptHeaders = new StringValues(); - if (context.Request.Headers.TryGetValue("Accept", out acceptHeaders)) + if (context.Request.Headers.TryGetValue("Accept", out StringValues acceptHeaders) == false) + return true; + + foreach (var acceptHeader in acceptHeaders) { - foreach (var acceptHeader in acceptHeaders) - { - if (ContainsMediaTypeParameters(acceptHeader)) - { - FlushResponse(context, 406); - return false; - } - } + if (ContainsMediaTypeParameters(acceptHeader) == false) + continue; + + FlushResponse(context, 406); + return false; } return true; } diff --git a/src/JsonApiDotNetCore/Models/Identifiable.cs b/src/JsonApiDotNetCore/Models/Identifiable.cs index c470656e63..0adb073f2f 100644 --- a/src/JsonApiDotNetCore/Models/Identifiable.cs +++ b/src/JsonApiDotNetCore/Models/Identifiable.cs @@ -7,15 +7,15 @@ namespace JsonApiDotNetCore.Models public class Identifiable : Identifiable {} - public class Identifiable : IIdentifiable, IIdentifiable + public class Identifiable : IIdentifiable { public virtual T Id { get; set; } [NotMapped] public string StringId { - get { return GetStringId(Id); } - set { Id = (T)GetConcreteId(value); } + get => GetStringId(Id); + set => Id = (T)GetConcreteId(value); } protected virtual string GetStringId(object value) @@ -26,12 +26,12 @@ protected virtual string GetStringId(object value) if(type == typeof(Guid)) { var guid = Guid.Parse(stringValue); - return (guid == Guid.Empty ? string.Empty : stringValue); + return guid == Guid.Empty ? string.Empty : stringValue; } - if(stringValue == "0") return string.Empty; - - return stringValue; + return stringValue == "0" + ? string.Empty + : stringValue; } protected virtual object GetConcreteId(string value) diff --git a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs index 208e002504..aaf065d6be 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs @@ -12,8 +12,8 @@ protected RelationshipAttribute(string publicName) public string PublicRelationshipName { get; set; } public string InternalRelationshipName { get; set; } public Type Type { get; set; } - public bool IsHasMany { get { return this.GetType() == typeof(HasManyAttribute); } } - public bool IsHasOne { get { return this.GetType() == typeof(HasOneAttribute); } } + public bool IsHasMany => GetType() == typeof(HasManyAttribute); + public bool IsHasOne => GetType() == typeof(HasOneAttribute); public abstract void SetValue(object entity, object newValue); @@ -24,7 +24,7 @@ public override string ToString() public override bool Equals(object obj) { - RelationshipAttribute attr = obj as RelationshipAttribute; + var attr = obj as RelationshipAttribute; if (attr == null) { return false; diff --git a/src/JsonApiDotNetCore/Models/RelationshipData.cs b/src/JsonApiDotNetCore/Models/RelationshipData.cs index aa2effd9bb..21efa7409c 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipData.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipData.cs @@ -19,10 +19,10 @@ public object ExposedData { } set { if(value is IEnumerable) - if(value is JObject) - SingleData = ((JObject)value).ToObject>(); - else if(value is JArray) - ManyData = ((JArray)value).ToObject>>(); + if(value is JObject jObject) + SingleData = jObject.ToObject>(); + else if(value is JArray jArray) + ManyData = jArray.ToObject>>(); else ManyData = (List>)value; else diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index b6ad9273c3..19ec28ee6a 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -2,27 +2,24 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Serialization { public class JsonApiDeSerializer : IJsonApiDeSerializer { - private readonly DbContext _dbContext; private readonly IJsonApiContext _jsonApiContext; private readonly IGenericProcessorFactory _genericProcessorFactor; - public JsonApiDeSerializer(DbContext dbContext, + public JsonApiDeSerializer( IJsonApiContext jsonApiContext, IGenericProcessorFactory genericProcessorFactory) { - _dbContext = dbContext; _jsonApiContext = jsonApiContext; _genericProcessorFactor = genericProcessorFactory; } @@ -115,10 +112,9 @@ private object _setRelationships( foreach (var attr in contextEntity.Relationships) { - if (attr.IsHasOne) - entity = _setHasOneRelationship(entity, entityProperties, attr, contextEntity, relationships); - else - entity = _setHasManyRelationship(entity, entityProperties, attr, contextEntity, relationships); + entity = attr.IsHasOne + ? _setHasOneRelationship(entity, entityProperties, attr, contextEntity, relationships) + : _setHasManyRelationship(entity, entityProperties, attr, contextEntity, relationships); } return entity; diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index ca49b7bf70..f2c1ef777c 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -11,174 +11,174 @@ namespace JsonApiDotNetCore.Services { - public class EntityResourceService - : EntityResourceService, - IResourceService - where T : class, IIdentifiable - { - public EntityResourceService( - IJsonApiContext jsonApiContext, - IEntityRepository entityRepository, - ILoggerFactory loggerFactory) - : base(jsonApiContext, entityRepository, loggerFactory) - { } - } - - public class EntityResourceService : IResourceService - where T : class, IIdentifiable - { - private readonly IJsonApiContext _jsonApiContext; - private readonly IEntityRepository _entities; - private readonly ILogger _logger; - - public EntityResourceService( - IJsonApiContext jsonApiContext, - IEntityRepository entityRepository, - ILoggerFactory loggerFactory) + public class EntityResourceService + : EntityResourceService, + IResourceService + where T : class, IIdentifiable { - _jsonApiContext = jsonApiContext; - _entities = entityRepository; - _logger = loggerFactory.CreateLogger>(); + public EntityResourceService( + IJsonApiContext jsonApiContext, + IEntityRepository entityRepository, + ILoggerFactory loggerFactory) + : base(jsonApiContext, entityRepository, loggerFactory) + { } } - public async Task> GetAsync() + public class EntityResourceService : IResourceService + where T : class, IIdentifiable { - var entities = _entities.Get(); + private readonly IJsonApiContext _jsonApiContext; + private readonly IEntityRepository _entities; + private readonly ILogger _logger; + + public EntityResourceService( + IJsonApiContext jsonApiContext, + IEntityRepository entityRepository, + ILoggerFactory loggerFactory) + { + _jsonApiContext = jsonApiContext; + _entities = entityRepository; + _logger = loggerFactory.CreateLogger>(); + } + + public async Task> GetAsync() + { + var entities = _entities.Get(); + + entities = ApplySortAndFilterQuery(entities); + + if (_jsonApiContext.QuerySet?.IncludedRelationships != null && _jsonApiContext.QuerySet.IncludedRelationships.Count > 0) + entities = IncludeRelationships(entities, _jsonApiContext.QuerySet.IncludedRelationships); + + if (_jsonApiContext.Options.IncludeTotalRecordCount) + _jsonApiContext.PageManager.TotalRecords = await entities.CountAsync(); + + // pagination should be done last since it will execute the query + var pagedEntities = await ApplyPageQueryAsync(entities); + return pagedEntities; + } + + public async Task GetAsync(TId id) + { + T entity; + if (_jsonApiContext.QuerySet?.IncludedRelationships != null) + entity = await GetWithRelationshipsAsync(id); + else + entity = await _entities.GetAsync(id); + return entity; + } + + private async Task GetWithRelationshipsAsync(TId id) + { + var query = _entities.Get(); + _jsonApiContext.QuerySet.IncludedRelationships.ForEach(r => + { + query = _entities.Include(query, r); + }); + return await query.FirstOrDefaultAsync(e => e.Id.Equals(id)); + } + + public async Task GetRelationshipsAsync(TId id, string relationshipName) + { + _jsonApiContext.IsRelationshipData = true; + return await GetRelationshipAsync(id, relationshipName); + } + + public async Task GetRelationshipAsync(TId id, string relationshipName) + { + relationshipName = _jsonApiContext.ContextGraph + .GetRelationshipName(relationshipName.ToProperCase()); + + if (relationshipName == null) + throw new JsonApiException("422", "Relationship name not specified."); + + var entity = await _entities.GetAndIncludeAsync(id, relationshipName); + if (entity == null) + throw new JsonApiException("404", $"Relationship {relationshipName} not found."); + + var relationship = _jsonApiContext.ContextGraph + .GetRelationship(entity, relationshipName); + + return relationship; + } + + public async Task CreateAsync(T entity) + { + return await _entities.CreateAsync(entity); + } + + public async Task UpdateAsync(TId id, T entity) + { + var updatedEntity = await _entities.UpdateAsync(id, entity); + return updatedEntity; + } + + public async Task UpdateRelationshipsAsync(TId id, string relationshipName, List relationships) + { + relationshipName = _jsonApiContext.ContextGraph + .GetRelationshipName(relationshipName.ToProperCase()); + + if (relationshipName == null) + throw new JsonApiException("422", "Relationship name not specified."); + + var entity = await _entities.GetAndIncludeAsync(id, relationshipName); + + if (entity == null) + throw new JsonApiException("404", $"Entity with id {id} could not be found."); + + var relationship = _jsonApiContext.ContextGraph + .GetContextEntity(typeof(T)) + .Relationships + .FirstOrDefault(r => r.InternalRelationshipName == relationshipName); + + var relationshipIds = relationships.Select(r => r.Id); + + await _entities.UpdateRelationshipsAsync(entity, relationship, relationshipIds); + } + + public async Task DeleteAsync(TId id) + { + return await _entities.DeleteAsync(id); + } - entities = ApplySortAndFilterQuery(entities); + private IQueryable ApplySortAndFilterQuery(IQueryable entities) + { + var query = _jsonApiContext.QuerySet; - if (_jsonApiContext.QuerySet != null && _jsonApiContext.QuerySet.IncludedRelationships != null && _jsonApiContext.QuerySet.IncludedRelationships.Count > 0) - entities = IncludeRelationships(entities, _jsonApiContext.QuerySet.IncludedRelationships); + if (_jsonApiContext.QuerySet == null) + return entities; + + if (query.Filters.Count > 0) + foreach (var filter in query.Filters) + entities = _entities.Filter(entities, filter); + + if (query.SortParameters != null && query.SortParameters.Count > 0) + entities = _entities.Sort(entities, query.SortParameters); + + return entities; + } - if (_jsonApiContext.Options.IncludeTotalRecordCount) - _jsonApiContext.PageManager.TotalRecords = await entities.CountAsync(); + private async Task> ApplyPageQueryAsync(IQueryable entities) + { + var pageManager = _jsonApiContext.PageManager; + if (!pageManager.IsPaginated) + return entities; - // pagination should be done last since it will execute the query - var pagedEntities = await ApplyPageQueryAsync(entities); - return pagedEntities; - } - - public async Task GetAsync(TId id) - { - T entity; - if (_jsonApiContext.QuerySet?.IncludedRelationships != null) - entity = await GetWithRelationshipsAsync(id); - else - entity = await _entities.GetAsync(id); - return entity; - } - - private async Task GetWithRelationshipsAsync(TId id) - { - var query = _entities.Get(); - _jsonApiContext.QuerySet.IncludedRelationships.ForEach(r => - { - query = _entities.Include(query, r); - }); - return await query.FirstOrDefaultAsync(e => e.Id.Equals(id)); - } - - public async Task GetRelationshipsAsync(TId id, string relationshipName) - { - _jsonApiContext.IsRelationshipData = true; - return await GetRelationshipAsync(id, relationshipName); - } - - public async Task GetRelationshipAsync(TId id, string relationshipName) - { - relationshipName = _jsonApiContext.ContextGraph - .GetRelationshipName(relationshipName.ToProperCase()); - - if (relationshipName == null) - throw new JsonApiException("422", "Relationship name not specified."); - - var entity = await _entities.GetAndIncludeAsync(id, relationshipName); - if (entity == null) - throw new JsonApiException("404", $"Relationship {relationshipName} not found."); - - var relationship = _jsonApiContext.ContextGraph - .GetRelationship(entity, relationshipName); - - return relationship; - } - - public async Task CreateAsync(T entity) - { - return await _entities.CreateAsync(entity); - } - - public async Task UpdateAsync(TId id, T entity) - { - var updatedEntity = await _entities.UpdateAsync(id, entity); - return updatedEntity; - } + var query = _jsonApiContext.QuerySet?.PageQuery ?? new PageQuery(); - public async Task UpdateRelationshipsAsync(TId id, string relationshipName, List relationships) - { - relationshipName = _jsonApiContext.ContextGraph - .GetRelationshipName(relationshipName.ToProperCase()); - - if (relationshipName == null) - throw new JsonApiException("422", "Relationship name not specified."); - - var entity = await _entities.GetAndIncludeAsync(id, relationshipName); - - if (entity == null) - throw new JsonApiException("404", $"Entity with id {id} could not be found."); - - var relationship = _jsonApiContext.ContextGraph - .GetContextEntity(typeof(T)) - .Relationships - .FirstOrDefault(r => r.InternalRelationshipName == relationshipName); - - var relationshipIds = relationships.Select(r => r.Id); + _logger?.LogInformation($"Applying paging query. Fetching page {pageManager.CurrentPage} with {pageManager.PageSize} entities"); - await _entities.UpdateRelationshipsAsync(entity, relationship, relationshipIds); - } - - public async Task DeleteAsync(TId id) - { - return await _entities.DeleteAsync(id); - } - - private IQueryable ApplySortAndFilterQuery(IQueryable entities) - { - var query = _jsonApiContext.QuerySet; + return await _entities.PageAsync(entities, pageManager.PageSize, pageManager.CurrentPage); + } - if (_jsonApiContext.QuerySet == null) - return entities; + private IQueryable IncludeRelationships(IQueryable entities, List relationships) + { + _jsonApiContext.IncludedRelationships = relationships; - if (query.Filters.Count > 0) - foreach (var filter in query.Filters) - entities = _entities.Filter(entities, filter); - - if (query.SortParameters != null && query.SortParameters.Count > 0) - entities = _entities.Sort(entities, query.SortParameters); - - return entities; - } - - private async Task> ApplyPageQueryAsync(IQueryable entities) - { - var pageManager = _jsonApiContext.PageManager; - if (!pageManager.IsPaginated) - return entities; - - var query = _jsonApiContext.QuerySet?.PageQuery ?? new PageQuery(); - - _logger?.LogInformation($"Applying paging query. Fetching page {pageManager.CurrentPage} with {pageManager.PageSize} entities"); - - return await _entities.PageAsync(entities, pageManager.PageSize, pageManager.CurrentPage); - } - - private IQueryable IncludeRelationships(IQueryable entities, List relationships) - { - _jsonApiContext.IncludedRelationships = relationships; - - foreach (var r in relationships) - entities = _entities.Include(entities, r); + foreach (var r in relationships) + entities = _entities.Include(entities, r); - return entities; + return entities; + } } - } } diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index 2860c3eb74..cfc58cec61 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -2,6 +2,7 @@ using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Services/IResourceService.cs b/src/JsonApiDotNetCore/Services/IResourceService.cs index c2cc0ceab3..ba9a5784ec 100644 --- a/src/JsonApiDotNetCore/Services/IResourceService.cs +++ b/src/JsonApiDotNetCore/Services/IResourceService.cs @@ -8,7 +8,7 @@ public interface IResourceService : IResourceService where T : class, IIdentifiable { } - public interface IResourceService + public interface IResourceService where T : class, IIdentifiable { Task> GetAsync(); diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index 9cc244677d..908a5c9cf9 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -3,6 +3,7 @@ using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; using Microsoft.AspNetCore.Http; @@ -11,7 +12,7 @@ namespace JsonApiDotNetCore.Services { public class JsonApiContext : IJsonApiContext { - private IHttpContextAccessor _httpContextAccessor; + private readonly IHttpContextAccessor _httpContextAccessor; public JsonApiContext( IContextGraph contextGraph, IHttpContextAccessor httpContextAccessor, diff --git a/src/JsonApiDotNetCoreExample/Controllers/CamelCasedModelsController.cs b/src/JsonApiDotNetCoreExample/Controllers/CamelCasedModelsController.cs index 1a1c3bcf70..e46b3f8efd 100644 --- a/src/JsonApiDotNetCoreExample/Controllers/CamelCasedModelsController.cs +++ b/src/JsonApiDotNetCoreExample/Controllers/CamelCasedModelsController.cs @@ -1,10 +1,12 @@ using JsonApiDotNetCore.Controllers; using JsonApiDotNetCore.Services; using JsonApiDotNetCoreExample.Models; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace JsonApiDotNetCoreExample.Controllers { + [Route("[controller]")] [DisableRoutingConvention] public class CamelCasedModelsController : JsonApiController { diff --git a/src/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.cs b/src/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.cs index ce40d8016e..e0b4e3b40b 100644 --- a/src/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.cs +++ b/src/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.cs b/src/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.cs index 9d41bb041e..8a1810a9d8 100755 --- a/src/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.cs +++ b/src/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; namespace JsonApiDotNetCoreExample.Migrations { diff --git a/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs b/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs index 43ea19b242..27815ce504 100755 --- a/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs +++ b/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Migrations; namespace JsonApiDotNetCoreExample.Migrations diff --git a/src/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.cs b/src/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.cs index e1c04cf961..1c36034fe3 100755 --- a/src/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.cs +++ b/src/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Migrations; namespace JsonApiDotNetCoreExample.Migrations diff --git a/src/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.cs b/src/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.cs index fb6afef816..fbec5e0a79 100755 --- a/src/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.cs +++ b/src/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Metadata; namespace JsonApiDotNetCoreExample.Migrations diff --git a/src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs b/src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs index 57d636f9ea..5de99f5078 100755 --- a/src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs +++ b/src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs @@ -2,7 +2,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; using JsonApiDotNetCoreExample.Data; namespace JsonApiDotNetCoreExample.Migrations diff --git a/src/JsonApiDotNetCoreExample/Program.cs b/src/JsonApiDotNetCoreExample/Program.cs index 79be99a718..669e932b68 100644 --- a/src/JsonApiDotNetCoreExample/Program.cs +++ b/src/JsonApiDotNetCoreExample/Program.cs @@ -1,6 +1,5 @@ using System.IO; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; namespace JsonApiDotNetCoreExample diff --git a/src/JsonApiDotNetCoreExample/README.md b/src/JsonApiDotNetCoreExample/README.md deleted file mode 100644 index da40473b98..0000000000 --- a/src/JsonApiDotNetCoreExample/README.md +++ /dev/null @@ -1,15 +0,0 @@ -## Running the Example - -``` -> dotnet run -``` - -## Generate Documentation - -``` -> cd ./test/JsonApiDotNetCoreExampleTests -> dotnet test -> cd ./src/JsonApiDotNetCoreExample -> dotnet run -> open http://localhost:5000/docs -``` \ No newline at end of file diff --git a/src/JsonApiDotNetCoreExample/Startup.cs b/src/JsonApiDotNetCoreExample/Startup.cs index 0f8c5403c6..4a4f591967 100644 --- a/src/JsonApiDotNetCoreExample/Startup.cs +++ b/src/JsonApiDotNetCoreExample/Startup.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using JsonApiDotNetCore.Routing; using JsonApiDotNetCoreExample.Data; using Microsoft.EntityFrameworkCore; using JsonApiDotNetCore.Extensions; diff --git a/src/NoEntityFrameworkExample/Program.cs b/src/NoEntityFrameworkExample/Program.cs index 33c8f78dcb..5606e8e9f4 100755 --- a/src/NoEntityFrameworkExample/Program.cs +++ b/src/NoEntityFrameworkExample/Program.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; +using System.IO; using Microsoft.AspNetCore.Hosting; namespace NoEntityFrameworkExample diff --git a/src/NoEntityFrameworkExample/Properties/launchSettings.json b/src/NoEntityFrameworkExample/Properties/launchSettings.json new file mode 100644 index 0000000000..b78d7494b8 --- /dev/null +++ b/src/NoEntityFrameworkExample/Properties/launchSettings.json @@ -0,0 +1,22 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:57181/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "NoEntityFrameworkExample": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs index eacf716ae9..f41c5941b8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Bogus; using DotNetCoreDocs; -using DotNetCoreDocs.Models; using DotNetCoreDocs.Writers; using JsonApiDotNetCoreExample; using JsonApiDotNetCoreExample.Data; @@ -14,10 +13,8 @@ using Xunit; using JsonApiDotNetCore.Services; using JsonApiDotNetCore.Serialization; -using System.Linq; using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.Hosting; -using System; namespace JsonApiDotNetCoreExampleTests.Acceptance { diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs index a1b597f7d5..bc017fa3dc 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs @@ -11,8 +11,6 @@ using Newtonsoft.Json; using JsonApiDotNetCore.Models; using System.Collections; -using System.Diagnostics; -using System.Threading; using JsonApiDotNetCoreExampleTests.Startups; namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs index 6f57a17e2b..d23eda4cc8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using DotNetCoreDocs; using DotNetCoreDocs.Writers; using JsonApiDotNetCoreExample; @@ -14,6 +16,7 @@ using Newtonsoft.Json; using JsonApiDotNetCore.Models; using JsonApiDotNetCoreExampleTests.Helpers.Extensions; +using StringExtensions = JsonApiDotNetCoreExampleTests.Helpers.Extensions.StringExtensions; namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec { @@ -33,18 +36,18 @@ public SparseFieldSetTests(DocsFixture fixture) public async Task Can_Select_Sparse_Fieldsets() { // arrange - var fields = new string[] { "Id", "Description", "CreatedDate", "AchievedDate" }; + var fields = new List { "Id", "Description", "CreatedDate", "AchievedDate" }; var todoItem = new TodoItem { Description = "description", Ordinal = 1, - CreatedDate = System.DateTime.Now, - AchievedDate = System.DateTime.Now.AddDays(2) + CreatedDate = DateTime.Now, + AchievedDate = DateTime.Now.AddDays(2) }; _dbContext.TodoItems.Add(todoItem); await _dbContext.SaveChangesAsync(); - var expectedSql = $@"SELECT 't'.'Id', 't'.'Description', 't'.'CreatedDate', 't'.'AchievedDate' + var expectedSql = StringExtensions.Normalize($@"SELECT 't'.'Id', 't'.'Description', 't'.'CreatedDate', 't'.'AchievedDate' FROM 'TodoItems' AS 't' - WHERE 't'.'Id' = {todoItem.Id}".Normalize(); + WHERE 't'.'Id' = {todoItem.Id}"); // act var query = _dbContext @@ -52,7 +55,7 @@ public async Task Can_Select_Sparse_Fieldsets() .Where(t=>t.Id == todoItem.Id) .Select(fields); - var resultSql = query.ToSql().Normalize(); + var resultSql = StringExtensions.Normalize(query.ToSql()); var result = await query.FirstAsync(); // assert @@ -70,7 +73,7 @@ public async Task Fields_Query_Selects_Sparse_Field_Sets() var todoItem = new TodoItem { Description = "description", Ordinal = 1, - CreatedDate = System.DateTime.Now + CreatedDate = DateTime.Now }; _dbContext.TodoItems.Add(todoItem); await _dbContext.SaveChangesAsync(); @@ -93,7 +96,7 @@ public async Task Fields_Query_Selects_Sparse_Field_Sets() Assert.Equal(todoItem.StringId, deserializeBody.Data.Id); Assert.Equal(2, deserializeBody.Data.Attributes.Count); Assert.Equal(todoItem.Description, deserializeBody.Data.Attributes["description"]); - Assert.Equal(todoItem.CreatedDate, deserializeBody.Data.Attributes["created-date"]); + Assert.Equal(todoItem.CreatedDate.ToString("G"), ((DateTime)deserializeBody.Data.Attributes["created-date"]).ToString("G")); } } } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs index c8896e0ff5..39cb4dbdd0 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs @@ -1,10 +1,8 @@ using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using System.Threading; using System.Threading.Tasks; using Bogus; using DotNetCoreDocs; diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs b/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs index 71a952994a..95b05df096 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs @@ -13,6 +13,7 @@ using JsonApiDotNetCoreExample.Models; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Formatters; +using JsonApiDotNetCore.Internal.Generics; namespace JsonApiDotNetCoreExampleTests.Unit.Extensions { diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs b/test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs index ac9efd35e3..107dd1d593 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs @@ -1,7 +1,4 @@ using JsonApiDotNetCore.Models; -using System; -using System.Collections.Generic; -using System.Text; using Xunit; namespace JsonApiDotNetCoreExampleTests.Unit.Models