public void OnActionExecuting(ActionExecutingContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (!context.HttpContext.IsJsonApiRequest()) { return; } var request = context.HttpContext.Request; if (request.Method == "PATCH" || request.Method == "POST") { var deserializedType = context.ActionArguments.FirstOrDefault().Value?.GetType(); var targetType = context.ActionDescriptor.Parameters.FirstOrDefault()?.ParameterType; if (deserializedType != null && targetType != null && deserializedType != targetType) { ResourceContext resourceFromEndpoint = _provider.GetResourceContext(targetType); ResourceContext resourceFromBody = _provider.GetResourceContext(deserializedType); throw new ResourceTypeMismatchException(new HttpMethod(request.Method), request.Path, resourceFromEndpoint, resourceFromBody); } } }
/// <inheritdoc /> public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } if (context.HttpContext.IsJsonApiRequest() && IsPatchOrPostRequest(context.HttpContext.Request)) { var deserializedType = context.ActionArguments.FirstOrDefault().Value?.GetType(); var targetType = context.ActionDescriptor.Parameters.FirstOrDefault()?.ParameterType; if (deserializedType != null && targetType != null && deserializedType != targetType) { var resourceFromEndpoint = _provider.GetResourceContext(targetType); var resourceFromBody = _provider.GetResourceContext(deserializedType); throw new ResourceTypeMismatchException(new HttpMethod(context.HttpContext.Request.Method), context.HttpContext.Request.Path, resourceFromEndpoint, resourceFromBody); } } await next(); }
private void ValidateIncomingResourceType(InputFormatterContext context, object model) { if (context.HttpContext.IsJsonApiRequest() && IsPatchOrPostRequest(context.HttpContext.Request)) { var endpointResourceType = GetEndpointResourceType(); if (endpointResourceType == null) { return; } var bodyResourceTypes = GetBodyResourceTypes(model); foreach (var bodyResourceType in bodyResourceTypes) { if (!endpointResourceType.IsAssignableFrom(bodyResourceType)) { var resourceFromEndpoint = _resourceContextProvider.GetResourceContext(endpointResourceType); var resourceFromBody = _resourceContextProvider.GetResourceContext(bodyResourceType); throw new ResourceTypeMismatchException(new HttpMethod(context.HttpContext.Request.Method), context.HttpContext.Request.Path, resourceFromEndpoint, resourceFromBody); } } } }
private IReadOnlyCollection <IncludeElementExpression> ProcessIncludeSet(IReadOnlyCollection <IncludeElementExpression> includeElements, QueryLayer parentLayer, ICollection <RelationshipAttribute> parentRelationshipChain, ICollection <ExpressionInScope> constraints) { var includeElementsEvaluated = GetIncludeElements(includeElements, parentLayer.ResourceContext) ?? Array.Empty <IncludeElementExpression>(); var updatesInChildren = new Dictionary <IncludeElementExpression, IReadOnlyCollection <IncludeElementExpression> >(); foreach (var includeElement in includeElementsEvaluated) { parentLayer.Projection ??= new Dictionary <ResourceFieldAttribute, QueryLayer>(); if (!parentLayer.Projection.ContainsKey(includeElement.Relationship)) { var relationshipChain = new List <RelationshipAttribute>(parentRelationshipChain) { includeElement.Relationship }; // @formatter:wrap_chained_method_calls chop_always // @formatter:keep_existing_linebreaks true var expressionsInCurrentScope = constraints .Where(constraint => constraint.Scope != null && constraint.Scope.Fields.SequenceEqual(relationshipChain)) .Select(constraint => constraint.Expression) .ToArray(); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore var resourceContext = _resourceContextProvider.GetResourceContext(includeElement.Relationship.RightType); var child = new QueryLayer(resourceContext) { Filter = GetFilter(expressionsInCurrentScope, resourceContext), Sort = GetSort(expressionsInCurrentScope, resourceContext), Pagination = ((JsonApiOptions)_options).DisableChildrenPagination ? null : GetPagination(expressionsInCurrentScope, resourceContext), Projection = GetProjectionForSparseAttributeSet(resourceContext) }; parentLayer.Projection.Add(includeElement.Relationship, child); if (includeElement.Children.Any()) { var updatedChildren = ProcessIncludeSet(includeElement.Children, child, relationshipChain, constraints); if (!ReferenceEquals(includeElement.Children, updatedChildren)) { updatesInChildren.Add(includeElement, updatedChildren); } } } } return(!updatesInChildren.Any() ? includeElementsEvaluated : ApplyIncludeElementUpdates(includeElementsEvaluated, updatesInChildren)); }
/// <inheritdoc /> public void SetInitiallyStoredAttributeValues(TResource resource) { ArgumentGuard.NotNull(resource, nameof(resource)); ResourceContext resourceContext = _resourceContextProvider.GetResourceContext <TResource>(); _initiallyStoredAttributeValues = CreateAttributeDictionary(resource, resourceContext.Attributes); }
private void DeclareLocalId(IIdentifiable resource) { if (resource.LocalId != null) { var resourceContext = _resourceContextProvider.GetResourceContext(resource.GetType()); _localIdTracker.Declare(resource.LocalId, resourceContext.PublicName); } }
/// <inheritdoc /> public void SetInitiallyStoredAttributeValues(TResource resource) { if (resource == null) { throw new ArgumentNullException(nameof(resource)); } var resourceContext = _resourceContextProvider.GetResourceContext <TResource>(); _initiallyStoredAttributeValues = CreateAttributeDictionary(resource, resourceContext.Attributes); }
/// <inheritdoc /> public virtual Task <int> CountAsync(FilterExpression topFilter, CancellationToken cancellationToken) { var resourceContext = _resourceContextProvider.GetResourceContext <TResource>(); var layer = new QueryLayer(resourceContext) { Filter = topFilter }; var query = ApplyQueryLayer(layer); return(query.CountAsync(cancellationToken)); }
/// <inheritdoc/> public ResourceLinks GetResourceLinks(string resourceName, string id) { var resourceContext = _provider.GetResourceContext(resourceName); if (ShouldAddResourceLink(resourceContext, Link.Self)) { return(new ResourceLinks { Self = GetSelfResourceLink(resourceName, id) }); } return(null); }
/// <inheritdoc /> public IReadOnlyCollection <AttrAttribute> GetAttributes(Type resourceType) { ArgumentGuard.NotNull(resourceType, nameof(resourceType)); if (_request.Kind == EndpointKind.Relationship) { return(Array.Empty <AttrAttribute>()); } var resourceContext = _resourceContextProvider.GetResourceContext(resourceType); var fieldSet = _sparseFieldSetCache.GetSparseFieldSetForSerializer(resourceContext); return(fieldSet.OfType <AttrAttribute>().ToArray()); }
/// <inheritdoc /> public string GetControllerNameForResourceType(Type resourceType) { ArgumentGuard.NotNull(resourceType, nameof(resourceType)); ResourceContext resourceContext = _resourceContextProvider.GetResourceContext(resourceType); if (_controllerPerResourceContextMap.TryGetValue(resourceContext, out ControllerModel controllerModel)) { return(controllerModel.ControllerName); } return(null); }
/// <inheritdoc /> public IReadOnlyCollection <AttrAttribute> GetAttributes(Type resourceType) { ArgumentGuard.NotNull(resourceType, nameof(resourceType)); if (!ShouldSerialize) { return(Array.Empty <AttrAttribute>()); } ResourceContext resourceContext = _resourceContextProvider.GetResourceContext(resourceType); IReadOnlyCollection <ResourceFieldAttribute> fieldSet = _sparseFieldSetCache.GetSparseFieldSetForSerializer(resourceContext); return(fieldSet.OfType <AttrAttribute>().ToArray()); }
private IEnumerable <TResource> GetWhereWithInclude <TResource, TId>(IReadOnlyCollection <TId> ids, RelationshipAttribute[] relationshipsToNextLayer) where TResource : class, IIdentifiable <TId> { if (!ids.Any()) { return(Array.Empty <TResource>()); } ResourceContext resourceContext = _resourceContextProvider.GetResourceContext <TResource>(); FilterExpression filterExpression = CreateFilterByIds(ids, resourceContext); var queryLayer = new QueryLayer(resourceContext) { Filter = filterExpression }; List <ResourceFieldChainExpression> chains = relationshipsToNextLayer.Select(relationship => new ResourceFieldChainExpression(relationship)) .ToList(); if (chains.Any()) { queryLayer.Include = IncludeChainConverter.FromRelationshipChains(chains); } IResourceReadRepository <TResource, TId> repository = GetRepository <TResource, TId>(); return(repository.GetAsync(queryLayer, CancellationToken.None).Result); }
private static void SetupCurrentRequest(CurrentRequest currentRequest, ResourceContext primaryResourceContext, RouteValueDictionary routeValues, IJsonApiOptions options, IResourceContextProvider resourceContextProvider, HttpRequest httpRequest) { currentRequest.IsReadOnly = httpRequest.Method == HttpMethod.Get.Method; currentRequest.Kind = EndpointKind.Primary; currentRequest.PrimaryResource = primaryResourceContext; currentRequest.PrimaryId = GetPrimaryRequestId(routeValues); currentRequest.BasePath = GetBasePath(primaryResourceContext.ResourceName, options, httpRequest); var relationshipName = GetRelationshipNameForSecondaryRequest(routeValues); if (relationshipName != null) { currentRequest.Kind = IsRouteForRelationship(routeValues) ? EndpointKind.Relationship : EndpointKind.Secondary; var requestRelationship = primaryResourceContext.Relationships.SingleOrDefault(relationship => relationship.PublicName == relationshipName); if (requestRelationship != null) { currentRequest.Relationship = requestRelationship; currentRequest.SecondaryResource = resourceContextProvider.GetResourceContext(requestRelationship.RightType); } } currentRequest.IsCollection = currentRequest.PrimaryId == null || currentRequest.Relationship is HasManyAttribute; }
/// <inheritdoc /> public ResourceLinks GetResourceLinks(string resourceName, string id) { ArgumentGuard.NotNull(resourceName, nameof(resourceName)); ArgumentGuard.NotNull(id, nameof(id)); var resourceContext = _provider.GetResourceContext(resourceName); if (ShouldAddResourceLink(resourceContext, LinkTypes.Self)) { return(new ResourceLinks { Self = GetSelfResourceLink(resourceName, id) }); } return(null); }
/// <summary> /// Creates an instance of the referenced type in <paramref name="data"/> /// and sets its attributes and relationships /// </summary> /// <param name="data"></param> /// <returns>The parsed entity</returns> private IIdentifiable ParseResourceObject(ResourceObject data) { var resourceContext = _provider.GetResourceContext(data.Type); if (resourceContext == null) { throw new JsonApiException(400, message: $"This API does not contain a json:api resource named '{data.Type}'.", detail: "This resource is not registered on the ResourceGraph. " + "If you are using Entity Framework, make sure the DbSet matches the expected resource name. " + "If you have manually registered the resource, check that the call to AddResource correctly sets the public name."); } var entity = (IIdentifiable)Activator.CreateInstance(resourceContext.ResourceType); entity = SetAttributes(entity, data.Attributes, resourceContext.Attributes); entity = SetRelationships(entity, data.Relationships, resourceContext.Relationships); if (data.Id != null) { entity.StringId = data.Id?.ToString(); } return(entity); }
private static void SetupResourceRequest(JsonApiRequest request, ResourceContext primaryResourceContext, RouteValueDictionary routeValues, IJsonApiOptions options, IResourceContextProvider resourceContextProvider, HttpRequest httpRequest) { request.IsReadOnly = httpRequest.Method == HttpMethod.Get.Method || httpRequest.Method == HttpMethod.Head.Method; request.Kind = EndpointKind.Primary; request.PrimaryResource = primaryResourceContext; request.PrimaryId = GetPrimaryRequestId(routeValues); request.BasePath = GetBasePath(primaryResourceContext.PublicName, options, httpRequest); string relationshipName = GetRelationshipNameForSecondaryRequest(routeValues); if (relationshipName != null) { request.Kind = IsRouteForRelationship(routeValues) ? EndpointKind.Relationship : EndpointKind.Secondary; RelationshipAttribute requestRelationship = primaryResourceContext.Relationships.SingleOrDefault(relationship => relationship.PublicName == relationshipName); if (requestRelationship != null) { request.Relationship = requestRelationship; request.SecondaryResource = resourceContextProvider.GetResourceContext(requestRelationship.RightType); } } bool isGetAll = request.PrimaryId == null && request.IsReadOnly; request.IsCollection = isGetAll || request.Relationship is HasManyAttribute; }
public DefaultResourceService( IFieldsToSerialize fieldsToSerialize, IEnumerable <IQueryParameterService> queryParameters, IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceRepository <TResource, TId> repository, IResourceContextProvider provider, IResourceChangeTracker <TResource> resourceChangeTracker, IResourceFactory resourceFactory, IResourceHookExecutor hookExecutor = null) { _fieldsToSerialize = fieldsToSerialize; _includeService = queryParameters.FirstOrDefault <IIncludeService>(); _sparseFieldsService = queryParameters.FirstOrDefault <ISparseFieldsService>(); _pageService = queryParameters.FirstOrDefault <IPageService>(); _sortService = queryParameters.FirstOrDefault <ISortService>(); _filterService = queryParameters.FirstOrDefault <IFilterService>(); _options = options; _logger = loggerFactory.CreateLogger <DefaultResourceService <TResource, TId> >(); _repository = repository; _resourceChangeTracker = resourceChangeTracker; _resourceFactory = resourceFactory; _hookExecutor = hookExecutor; _currentRequestResource = provider.GetResourceContext <TResource>(); }
public CarExpressionRewriter(IResourceContextProvider resourceContextProvider) { ResourceContext carResourceContext = resourceContextProvider.GetResourceContext <Car>(); _regionIdAttribute = carResourceContext.Attributes.Single(attribute => attribute.Property.Name == nameof(Car.RegionId)); _licensePlateAttribute = carResourceContext.Attributes.Single(attribute => attribute.Property.Name == nameof(Car.LicensePlate)); }
protected virtual IOperationProcessor ResolveProcessor(OperationContainer operation) { Type processorInterface = GetProcessorInterface(operation.Kind); ResourceContext resourceContext = _resourceContextProvider.GetResourceContext(operation.Resource.GetType()); Type processorType = processorInterface.MakeGenericType(resourceContext.ResourceType, resourceContext.IdentityType); return((IOperationProcessor)_serviceProvider.GetRequiredService(processorType)); }
protected virtual object ResolveReadRepository(Type resourceType) { var resourceContext = _resourceContextProvider.GetResourceContext(resourceType); if (resourceContext.IdentityType == typeof(int)) { var intRepositoryType = typeof(IResourceReadRepository <>).MakeGenericType(resourceContext.ResourceType); var intRepository = _serviceProvider.GetService(intRepositoryType); if (intRepository != null) { return(intRepository); } } var resourceDefinitionType = typeof(IResourceReadRepository <,>).MakeGenericType(resourceContext.ResourceType, resourceContext.IdentityType); return(_serviceProvider.GetRequiredService(resourceDefinitionType)); }
private ResourceContext GetResourceContext(string resourceName) { var resourceContext = _resourceContextProvider.GetResourceContext(resourceName); if (resourceContext == null) { throw new QueryParseException($"Resource type '{resourceName}' does not exist."); } return(resourceContext); }
protected ResourceContext GetResourceContextForScope(ResourceFieldChainExpression scope) { if (scope == null) { return(RequestResource); } var lastField = scope.Fields.Last(); var type = lastField is RelationshipAttribute relationship ? relationship.RightType : lastField.Property.PropertyType; return(_resourceContextProvider.GetResourceContext(type)); }
private IReadOnlyCollection <IncludeElementExpression> ProcessIncludeSet(IReadOnlyCollection <IncludeElementExpression> includeElements, QueryLayer parentLayer, ICollection <RelationshipAttribute> parentRelationshipChain, ExpressionInScope[] constraints) { includeElements = GetIncludeElements(includeElements, parentLayer.ResourceContext) ?? Array.Empty <IncludeElementExpression>(); var updatesInChildren = new Dictionary <IncludeElementExpression, IReadOnlyCollection <IncludeElementExpression> >(); foreach (var includeElement in includeElements) { parentLayer.Projection ??= new Dictionary <ResourceFieldAttribute, QueryLayer>(); if (!parentLayer.Projection.ContainsKey(includeElement.Relationship)) { var relationshipChain = new List <RelationshipAttribute>(parentRelationshipChain) { includeElement.Relationship }; var expressionsInCurrentScope = constraints .Where(c => c.Scope != null && c.Scope.Fields.SequenceEqual(relationshipChain)) .Select(expressionInScope => expressionInScope.Expression) .ToArray(); var resourceContext = _resourceContextProvider.GetResourceContext(includeElement.Relationship.RightType); var child = new QueryLayer(resourceContext) { Filter = GetFilter(expressionsInCurrentScope, resourceContext), Sort = GetSort(expressionsInCurrentScope, resourceContext), Pagination = ((JsonApiOptions)_options).DisableChildrenPagination ? null : GetPagination(expressionsInCurrentScope, resourceContext), Projection = GetSparseFieldSetProjection(expressionsInCurrentScope, resourceContext) }; parentLayer.Projection.Add(includeElement.Relationship, child); if (includeElement.Children.Any()) { var updatedChildren = ProcessIncludeSet(includeElement.Children, child, relationshipChain, constraints); if (!ReferenceEquals(includeElement.Children, updatedChildren)) { updatesInChildren.Add(includeElement, updatedChildren); } } } } return(!updatesInChildren.Any() ? includeElements : ApplyIncludeElementUpdates(includeElements, updatesInChildren)); }
/// <inheritdoc /> public ResourceLinks GetResourceLinks(string resourceName, string id) { if (resourceName == null) { throw new ArgumentNullException(nameof(resourceName)); } if (id == null) { throw new ArgumentNullException(nameof(id)); } var resourceContext = _provider.GetResourceContext(resourceName); if (ShouldAddResourceLink(resourceContext, LinkTypes.Self)) { return(new ResourceLinks { Self = GetSelfResourceLink(resourceName, id) }); } return(null); }
private void ValidateIncomingResourceType(object model, HttpRequest httpRequest) { Type endpointResourceType = GetResourceTypeFromEndpoint(); if (endpointResourceType == null) { return; } IEnumerable <Type> bodyResourceTypes = GetResourceTypesFromRequestBody(model); foreach (Type bodyResourceType in bodyResourceTypes) { if (!endpointResourceType.IsAssignableFrom(bodyResourceType)) { ResourceContext resourceFromEndpoint = _resourceContextProvider.GetResourceContext(endpointResourceType); ResourceContext resourceFromBody = _resourceContextProvider.GetResourceContext(bodyResourceType); throw new ResourceTypeMismatchException(new HttpMethod(httpRequest.Method), httpRequest.Path, resourceFromEndpoint, resourceFromBody); } } }
private FilterExpression ParseFilterInHas(HasManyAttribute hasManyRelationship) { ResourceContext outerScopeBackup = _resourceContextInScope; Type innerResourceType = hasManyRelationship.RightType; _resourceContextInScope = _resourceContextProvider.GetResourceContext(innerResourceType); FilterExpression filter = ParseFilter(); _resourceContextInScope = outerScopeBackup; return(filter); }
/// <inheritdoc/> public ResourceObject Build(IIdentifiable entity, IEnumerable <AttrAttribute> attributes = null, IEnumerable <RelationshipAttribute> relationships = null) { var resourceContext = _provider.GetResourceContext(entity.GetType()); // populating the top-level "type" and "id" members. var ro = new ResourceObject { Type = resourceContext.ResourceName, Id = entity.StringId.NullIfEmpty() }; // populating the top-level "attribute" member of a resource object. never include "id" as an attribute if (attributes != null && (attributes = attributes.Where(attr => attr.PropertyInfo.Name != _identifiablePropertyName)).Any()) { ProcessAttributes(entity, attributes, ro); } // populating the top-level "relationship" member of a resource object. if (relationships != null) { ProcessRelationships(entity, relationships, ro); } return(ro); }
private static ResourceContext CreateResourceContext(RouteValueDictionary routeValues, IControllerResourceMapping controllerResourceMapping, IResourceContextProvider resourceGraph) { var controllerName = (string)routeValues["controller"]; if (controllerName == null) { return(null); } var resourceType = controllerResourceMapping.GetAssociatedResource(controllerName); return(resourceGraph.GetResourceContext(resourceType)); }
private Expression ProcessRelationshipChain(ResourceFieldChainExpression chain, Expression source) { string path = null; Expression result = source; foreach (RelationshipAttribute relationship in chain.Fields.Cast <RelationshipAttribute>()) { path = path == null ? relationship.RelationshipPath : path + "." + relationship.RelationshipPath; ResourceContext resourceContext = _resourceContextProvider.GetResourceContext(relationship.RightType); result = ApplyEagerLoads(result, resourceContext.EagerLoads, path); } return(IncludeExtensionMethodCall(result, path)); }