diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index ea15036201..3900630b5d 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -122,6 +122,7 @@ public static void AddJsonApiInternals( services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IResourceService<,>), typeof(EntityResourceService<,>)); + services.AddSingleton(jsonApiOptions); services.AddSingleton(jsonApiOptions.ContextGraph); services.AddScoped(); diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index a75fd0d23a..6c7dda3460 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@ - 2.3.4 + 2.4.0 $(NetStandardVersion) JsonApiDotNetCore JsonApiDotNetCore diff --git a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs index 0ce54c8589..ab472a8dba 100644 --- a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; @@ -9,16 +10,23 @@ namespace JsonApiDotNetCore.Middleware public class RequestMiddleware { private readonly RequestDelegate _next; - + public RequestMiddleware(RequestDelegate next) { _next = next; } - public async Task Invoke(HttpContext context) + public async Task Invoke(HttpContext context, IJsonApiContext jsonApiContext) { if (IsValid(context)) + { + // HACK: this currently results in allocation of + // objects that may or may not be used and even double allocation + // since the JsonApiContext is using field initializers + // Need to work on finding a better solution. + jsonApiContext.BeginOperation(); await _next(context); + } } private static bool IsValid(HttpContext context) @@ -58,11 +66,11 @@ internal static bool ContainsMediaTypeParameters(string mediaType) var incomingMediaTypeSpan = mediaType.AsSpan(); // if the content type is not application/vnd.api+json then continue on - if(incomingMediaTypeSpan.Length < Constants.ContentType.Length) + if (incomingMediaTypeSpan.Length < Constants.ContentType.Length) return false; var incomingContentType = incomingMediaTypeSpan.Slice(0, Constants.ContentType.Length); - if(incomingContentType.SequenceEqual(Constants.ContentType.AsSpan()) == false) + if (incomingContentType.SequenceEqual(Constants.ContentType.AsSpan()) == false) return false; // anything appended to "application/vnd.api+json;" will be considered a media type param diff --git a/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs b/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs index 721274e3d6..04056e4af8 100644 --- a/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs +++ b/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs @@ -1,6 +1,6 @@ -using System; using System.Collections; using System.Collections.Generic; +using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Request { @@ -32,18 +32,18 @@ namespace JsonApiDotNetCore.Request /// public class HasManyRelationshipPointers { - private Dictionary _hasManyRelationships = new Dictionary(); + private Dictionary _hasManyRelationships = new Dictionary(); /// /// Add the relationship to the list of relationships that should be /// set in the repository layer. /// - public void Add(Type dependentType, IList entities) - => _hasManyRelationships[dependentType] = entities; + public void Add(RelationshipAttribute relationship, IList entities) + => _hasManyRelationships[relationship] = entities; /// /// Get all the models that should be associated /// - public Dictionary Get() => _hasManyRelationships; + public Dictionary Get() => _hasManyRelationships; } } diff --git a/src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs b/src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs index 9e0bdd0e15..753aa35e98 100644 --- a/src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs +++ b/src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs @@ -1,5 +1,4 @@ using JsonApiDotNetCore.Models; -using System; using System.Collections.Generic; namespace JsonApiDotNetCore.Request @@ -29,18 +28,18 @@ namespace JsonApiDotNetCore.Request /// public class HasOneRelationshipPointers { - private Dictionary _hasOneRelationships = new Dictionary(); + private Dictionary _hasOneRelationships = new Dictionary(); /// /// Add the relationship to the list of relationships that should be /// set in the repository layer. /// - public void Add(Type dependentType, IIdentifiable entity) - => _hasOneRelationships[dependentType] = entity; + public void Add(RelationshipAttribute relationship, IIdentifiable entity) + => _hasOneRelationships[relationship] = entity; /// /// Get all the models that should be associated /// - public Dictionary Get() => _hasOneRelationships; + public Dictionary Get() => _hasOneRelationships; } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 8b5a94f201..5ad0a2b63d 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -124,7 +124,7 @@ public object DocumentToObject(DocumentData data, List included = + "If you have manually registered the resource, check that the call to AddResource correctly sets the public name."); ; var entity = Activator.CreateInstance(contextEntity.EntityType); - + entity = SetEntityAttributes(entity, contextEntity, data.Attributes); entity = SetRelationships(entity, contextEntity, data.Relationships, included); @@ -141,7 +141,7 @@ private object SetEntityAttributes( { if (attributeValues == null || attributeValues.Count == 0) return entity; - + foreach (var attr in contextEntity.Attributes) { if (attributeValues.TryGetValue(attr.PublicAttributeName, out object newValue)) @@ -174,7 +174,7 @@ private object DeserializeComplexType(JContainer obj, Type targetType) private object SetRelationships( object entity, ContextEntity contextEntity, - Dictionary relationships, + Dictionary relationships, List included = null) { if (relationships == null || relationships.Count == 0) @@ -203,7 +203,7 @@ private object SetHasOneRelationship(object entity, if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData) == false) return entity; - + var relationshipAttr = _jsonApiContext.RequestEntity.Relationships .SingleOrDefault(r => r.PublicRelationshipName == relationshipName); @@ -234,7 +234,7 @@ private object SetHasOneRelationship(object entity, foreignKeyProperty.SetValue(entity, convertedValue); - if(rio != null + if (rio != null // if the resource identifier is null, there should be no reason to instantiate an instance && rio.Id != null) { @@ -247,7 +247,7 @@ private object SetHasOneRelationship(object entity, // we need to store the fact that this relationship was included in the payload // for EF, the repository will use these pointers to make ensure we don't try to // create resources if they already exist, we just need to create the relationship - _jsonApiContext.HasOneRelationshipPointers.Add(attr.Type, includedRelationshipObject); + _jsonApiContext.HasOneRelationshipPointers.Add(attr, includedRelationshipObject); } return entity; @@ -278,7 +278,7 @@ private object SetHasManyRelationship(object entity, attr.SetValue(entity, convertedCollection); - _jsonApiContext.HasManyRelationshipPointers.Add(attr.Type, convertedCollection); + _jsonApiContext.HasManyRelationshipPointers.Add(attr, convertedCollection); } return entity; @@ -301,7 +301,7 @@ private IIdentifiable GetIncludedRelationship(ResourceIdentifierObject relatedRe var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(relationshipAttr.Type); if (contextEntity == null) throw new JsonApiException(400, $"Included type '{relationshipAttr.Type}' is not a registered json:api resource."); - + SetEntityAttributes(relatedInstance, contextEntity, includedResource.Attributes); return relatedInstance; diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index 9cbe2a53ca..80995596ea 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -152,5 +152,12 @@ public interface IJsonApiContext : IJsonApiRequest [Obsolete("Use the proxied method IControllerContext.GetControllerAttribute instead.")] TAttribute GetControllerAttribute() where TAttribute : Attribute; + + /// + /// **_Experimental_**: do not use. It is likely to change in the future. + /// + /// Resets operational state information. + /// + void BeginOperation(); } } diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index 64fcf8e998..1e9b53eb51 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -47,13 +47,14 @@ public JsonApiContext( public PageManager PageManager { get; set; } public IMetaBuilder MetaBuilder { get; set; } public IGenericProcessorFactory GenericProcessorFactory { get; set; } - public Dictionary AttributesToUpdate { get; set; } = new Dictionary(); - public Dictionary RelationshipsToUpdate { get; set; } = new Dictionary(); public Type ControllerType { get; set; } public Dictionary DocumentMeta { get; set; } public bool IsBulkOperationRequest { get; set; } - public HasManyRelationshipPointers HasManyRelationshipPointers { get; } = new HasManyRelationshipPointers(); - public HasOneRelationshipPointers HasOneRelationshipPointers { get; } = new HasOneRelationshipPointers(); + + public Dictionary AttributesToUpdate { get; set; } = new Dictionary(); + public Dictionary RelationshipsToUpdate { get; set; } = new Dictionary(); + public HasManyRelationshipPointers HasManyRelationshipPointers { get; private set; } = new HasManyRelationshipPointers(); + public HasOneRelationshipPointers HasOneRelationshipPointers { get; private set; } = new HasOneRelationshipPointers(); public IJsonApiContext ApplyContext(object controller) { @@ -132,5 +133,14 @@ private PageManager GetPageManager() [Obsolete("Use the proxied method IControllerContext.GetControllerAttribute instead.")] public TAttribute GetControllerAttribute() where TAttribute : Attribute => _controllerContext.GetControllerAttribute(); + + public void BeginOperation() + { + IncludedRelationships = new List(); + AttributesToUpdate = new Dictionary(); + RelationshipsToUpdate = new Dictionary(); + HasManyRelationshipPointers = new HasManyRelationshipPointers(); + HasOneRelationshipPointers = new HasOneRelationshipPointers(); + } } } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs index 4215507bc2..1004ed30dc 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -1,3 +1,4 @@ +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Services.Operations.Processors; @@ -90,6 +91,9 @@ public IOpProcessor LocateUpdateService(Operation operation) var resource = operation.GetResourceTypeName(); var contextEntity = _context.ContextGraph.GetContextEntity(resource); + if (contextEntity == null) + throw new JsonApiException(400, $"This API does not expose a resource of type '{resource}'."); + var processor = _processorFactory.GetProcessor( typeof(IUpdateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType ); diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index 7cb9765606..275b4b85b0 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -19,13 +19,16 @@ public class OperationsProcessor : IOperationsProcessor { private readonly IOperationProcessorResolver _processorResolver; private readonly DbContext _dbContext; + private readonly IJsonApiContext _jsonApiContext; public OperationsProcessor( IOperationProcessorResolver processorResolver, - IDbContextResolver dbContextResolver) + IDbContextResolver dbContextResolver, + IJsonApiContext jsonApiContext) { _processorResolver = processorResolver; _dbContext = dbContextResolver.GetContext(); + _jsonApiContext = jsonApiContext; } public async Task> ProcessAsync(List inputOps) @@ -40,6 +43,7 @@ public async Task> ProcessAsync(List inputOps) { foreach (var op in inputOps) { + _jsonApiContext.BeginOperation(); lastAttemptedOperation = op.Op; await ProcessOperation(op, outputOps); opIndex++; @@ -75,7 +79,8 @@ private async Task ProcessOperation(Operation op, List outputOps) private void ReplaceLocalIdsInResourceObject(ResourceObject resourceObject, List outputOps) { - if (resourceObject == null) return; + if (resourceObject == null) + return; // it is strange to me that a top level resource object might use a lid. // by not replacing it, we avoid a case where the first operation is an 'add' with an 'lid' diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs index 4f50bbf4da..5ecdf6f38a 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs @@ -7,7 +7,7 @@ namespace JsonApiDotNetCore.Services.Operations.Processors { - public interface ICreateOpProcessor : IOpProcessor + public interface ICreateOpProcessor : ICreateOpProcessor where T : class, IIdentifiable { } @@ -15,7 +15,8 @@ public interface ICreateOpProcessor : IOpProcessor where T : class, IIdentifiable { } - public class CreateOpProcessor : CreateOpProcessor + public class CreateOpProcessor + : CreateOpProcessor, ICreateOpProcessor where T : class, IIdentifiable { public CreateOpProcessor( diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs index a3737dd57d..a3cb6e7da8 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs @@ -13,7 +13,7 @@ namespace JsonApiDotNetCore.Services.Operations.Processors /// Handles all "" operations /// /// The resource type - public interface IGetOpProcessor : IOpProcessor + public interface IGetOpProcessor : IGetOpProcessor where T : class, IIdentifiable { } @@ -27,7 +27,7 @@ public interface IGetOpProcessor : IOpProcessor { } /// - public class GetOpProcessor : GetOpProcessor + public class GetOpProcessor : GetOpProcessor, IGetOpProcessor where T : class, IIdentifiable { /// diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs index 236a76d084..a1aebadc66 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs @@ -7,7 +7,7 @@ namespace JsonApiDotNetCore.Services.Operations.Processors { - public interface IRemoveOpProcessor : IOpProcessor + public interface IRemoveOpProcessor : IRemoveOpProcessor where T : class, IIdentifiable { } @@ -15,7 +15,7 @@ public interface IRemoveOpProcessor : IOpProcessor where T : class, IIdentifiable { } - public class RemoveOpProcessor : RemoveOpProcessor + public class RemoveOpProcessor : RemoveOpProcessor, IRemoveOpProcessor where T : class, IIdentifiable { public RemoveOpProcessor( diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs index b626fbe746..1ea690a52c 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs @@ -7,7 +7,7 @@ namespace JsonApiDotNetCore.Services.Operations.Processors { - public interface IUpdateOpProcessor : IOpProcessor + public interface IUpdateOpProcessor : IUpdateOpProcessor where T : class, IIdentifiable { } @@ -15,7 +15,7 @@ public interface IUpdateOpProcessor : IOpProcessor where T : class, IIdentifiable { } - public class UpdateOpProcessor : UpdateOpProcessor + public class UpdateOpProcessor : UpdateOpProcessor, IUpdateOpProcessor where T : class, IIdentifiable { public UpdateOpProcessor( @@ -27,7 +27,7 @@ IContextGraph contextGraph { } } - public class UpdateOpProcessor : ICreateOpProcessor + public class UpdateOpProcessor : IUpdateOpProcessor where T : class, IIdentifiable { private readonly IUpdateService _service; @@ -53,16 +53,17 @@ public async Task ProcessAsync(Operation operation) throw new JsonApiException(400, "The data.id parameter is required for replace operations"); var model = (T)_deSerializer.DocumentToObject(operation.DataObject); + var result = await _service.UpdateAsync(model.Id, model); + if (result == null) + throw new JsonApiException(404, $"Could not find an instance of '{operation.DataObject.Type}' with id {operation.DataObject.Id}"); var operationResult = new Operation { Op = OperationCode.update }; - operationResult.Data = _documentBuilder.GetData( - _contextGraph.GetContextEntity(operation.GetResourceTypeName()), - result); + operationResult.Data = _documentBuilder.GetData(_contextGraph.GetContextEntity(operation.GetResourceTypeName()), result); return operationResult; } diff --git a/src/JsonApiDotNetCore/Services/ScopedServiceProvider.cs b/src/JsonApiDotNetCore/Services/ScopedServiceProvider.cs index 38e147645f..eecd554e7c 100644 --- a/src/JsonApiDotNetCore/Services/ScopedServiceProvider.cs +++ b/src/JsonApiDotNetCore/Services/ScopedServiceProvider.cs @@ -15,14 +15,14 @@ public interface IScopedServiceProvider : IServiceProvider { } /// public class RequestScopedServiceProvider : IScopedServiceProvider { - private readonly IServiceProvider _serviceProvider; + private readonly IHttpContextAccessor _httpContextAccessor; public RequestScopedServiceProvider(IHttpContextAccessor httpContextAccessor) { - _serviceProvider = httpContextAccessor.HttpContext.RequestServices; + _httpContextAccessor = httpContextAccessor; } /// - public object GetService(Type serviceType) => _serviceProvider.GetService(serviceType); + public object GetService(Type serviceType) => _httpContextAccessor.HttpContext.RequestServices.GetService(serviceType); } } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs index cf1ea6de96..0600fb402b 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs @@ -5,10 +5,12 @@ using System.Net.Http.Headers; using System.Threading.Tasks; using Bogus; +using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using Xunit; using Person = JsonApiDotNetCoreExample.Models.Person; @@ -304,6 +306,74 @@ public async Task Can_Post_TodoItem() Assert.Null(deserializedBody.AchievedDate); } + + [Fact] + public async Task Can_Post_TodoItem_With_Different_Owner_And_Assignee() + { + // Arrange + var person1 = new Person(); + var person2 = new Person(); + _context.People.Add(person1); + _context.People.Add(person2); + _context.SaveChanges(); + + var todoItem = _todoItemFaker.Generate(); + var content = new + { + data = new + { + type = "todo-items", + attributes = new Dictionary() + { + { "description", todoItem.Description }, + { "ordinal", todoItem.Ordinal }, + { "created-date", todoItem.CreatedDate } + }, + relationships = new + { + owner = new + { + data = new + { + type = "people", + id = person1.Id.ToString() + } + }, + assignee = new + { + data = new + { + type = "people", + id = person2.Id.ToString() + } + } + } + } + }; + + var httpMethod = new HttpMethod("POST"); + var route = $"/api/v1/todo-items"; + + var request = new HttpRequestMessage(httpMethod, route); + request.Content = new StringContent(JsonConvert.SerializeObject(content)); + request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); + + // Act + var response = await _fixture.Client.SendAsync(request); + + // Assert -- response + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + var document = JsonConvert.DeserializeObject(body); + var resultId = int.Parse(document.Data.Id); + + // Assert -- database + var todoItemResult = await _context.TodoItems.SingleAsync(t => t.Id == resultId); + + Assert.Equal(person1.Id, todoItemResult.OwnerId); + Assert.Equal(person2.Id, todoItemResult.AssigneeId); + } + [Fact] public async Task Can_Patch_TodoItem() { diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs index 9635c6f6f3..08211c5a67 100644 --- a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Services; using JsonApiDotNetCore.Services.Operations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -18,12 +19,14 @@ public class OperationsProcessorTests private readonly Mock _resolverMock; public readonly Mock _dbContextMock; public readonly Mock _dbContextResolverMock; + public readonly Mock _jsonApiContextMock; public OperationsProcessorTests() { _resolverMock = new Mock(); _dbContextMock = new Mock(); _dbContextResolverMock = new Mock(); + _jsonApiContextMock = new Mock(); } [Fact] @@ -90,7 +93,7 @@ public async Task ProcessAsync_Performs_LocalId_ReplacementAsync_In_Relationship .Returns(opProcessorMock.Object); _dbContextResolverMock.Setup(m => m.GetContext()).Returns(_dbContextMock.Object); - var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextResolverMock.Object); + var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextResolverMock.Object, _jsonApiContextMock.Object); // act var results = await operationsProcessor.ProcessAsync(operations); @@ -173,7 +176,7 @@ public async Task ProcessAsync_Performs_LocalId_ReplacementAsync_In_References() .Returns(updateOpProcessorMock.Object); _dbContextResolverMock.Setup(m => m.GetContext()).Returns(_dbContextMock.Object); - var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextResolverMock.Object); + var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextResolverMock.Object, _jsonApiContextMock.Object); // act var results = await operationsProcessor.ProcessAsync(operations);