Пример #1
0
        protected override async Task <IQueryable <TRelated> > GetRelatedQuery(string primaryResourceId,
                                                                               CancellationToken cancellationToken)
        {
            var param        = Expression.Parameter(typeof(TPrimaryResource));
            var accessorExpr = Expression.Property(param, _relationship.Property);
            var lambda       = Expression.Lambda <Func <TPrimaryResource, IEnumerable <TRelated> > >(accessorExpr, param);

            var primaryEntityQuery = FilterById <TPrimaryResource>(primaryResourceId, _primaryTypeRegistration);

            // We have to see if the resource even exists, so we can throw a 404 if it doesn't
            var relatedResource = await primaryEntityQuery.FirstOrDefaultAsync(cancellationToken);

            if (relatedResource == null)
            {
                throw JsonApiException.CreateForNotFound(string.Format(
                                                             "No resource of type `{0}` exists with id `{1}`.",
                                                             _primaryTypeRegistration.ResourceTypeName, primaryResourceId));
            }
            var includes = GetNavigationPropertiesIncludes(Includes);
            var query    = primaryEntityQuery.SelectMany(lambda);

            if (includes != null && includes.Any())
            {
                query = includes.Aggregate(query, (current, include) => current.Include(include));
            }
            return(query);
        }
Пример #2
0
        public virtual async Task <ISingleResourceDocument> GetRecordById(string id, HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var apiBaseUrl     = GetBaseUrlFromRequest(request);
            var singleResource = await FilterById <T>(id, _resourceTypeRegistration).FirstOrDefaultAsync(cancellationToken);

            if (singleResource == null)
            {
                throw JsonApiException.CreateForNotFound(string.Format("No resource of type `{0}` exists with id `{1}`.",
                                                                       _resourceTypeRegistration.ResourceTypeName, id));
            }
            return(_singleResourceDocumentBuilder.BuildDocument(singleResource, apiBaseUrl, null, null));
        }
        protected override async Task <TRelated> GetRelatedRecord(string primaryResourceId, CancellationToken cancellationToken)
        {
            var param        = Expression.Parameter(typeof(TPrimaryResource));
            var accessorExpr = Expression.Property(param, _relationship.Property);
            var lambda       = Expression.Lambda <Func <TPrimaryResource, TRelated> >(accessorExpr, param);

            var primaryEntityQuery  = FilterById <TPrimaryResource>(primaryResourceId, _primaryTypeRegistration);
            var primaryEntityExists = await primaryEntityQuery.AnyAsync(cancellationToken);

            if (!primaryEntityExists)
            {
                throw JsonApiException.CreateForNotFound(string.Format("No resource of type `{0}` exists with id `{1}`.",
                                                                       _primaryTypeRegistration.ResourceTypeName, primaryResourceId));
            }
            return(await primaryEntityQuery.Select(lambda).FirstOrDefaultAsync(cancellationToken));
        }
Пример #4
0
        /// <summary>
        /// Generic method for getting the related resources for a to-one relationship
        /// </summary>
        protected async Task <ISingleResourceDocument> GetRelatedToOne <TRelated>(string id,
                                                                                  ResourceTypeRelationship relationship, HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var param        = Expression.Parameter(typeof(T));
            var accessorExpr = Expression.Property(param, relationship.Property);
            var lambda       = Expression.Lambda <Func <T, TRelated> >(accessorExpr, param);

            var primaryEntityQuery  = FilterById <T>(id, _resourceTypeRegistration);
            var primaryEntityExists = await primaryEntityQuery.AnyAsync(cancellationToken);

            if (!primaryEntityExists)
            {
                throw JsonApiException.CreateForNotFound(string.Format("No resource of type `{0}` exists with id `{1}`.",
                                                                       _resourceTypeRegistration.ResourceTypeName, id));
            }
            var relatedResource = await primaryEntityQuery.Select(lambda).FirstOrDefaultAsync(cancellationToken);

            return(_singleResourceDocumentBuilder.BuildDocument(relatedResource, GetBaseUrlFromRequest(request), null, null));
        }
        public virtual async Task <ISingleResourceDocument> GetRecordById(string id, HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var entityQuery     = GetByIdQuery(id);
            var includePaths    = GetIncludePathsForSingleResource() ?? new Expression <Func <TDto, object> >[] { };
            var jsonApiPaths    = includePaths.Select(ConvertToJsonKeyPath).ToArray();
            var mappedQuery     = GetMappedQuery(entityQuery, includePaths);
            var primaryResource = await _queryableEnumerationTransformer.FirstOrDefault(mappedQuery, cancellationToken);

            if (primaryResource == null)
            {
                throw JsonApiException.CreateForNotFound(
                          string.Format("No record exists with type `{0}` and ID `{1}`.", ResourceTypeName, id));
            }

            await OnResourceFetched(primaryResource, cancellationToken);

            var baseUrl = _baseUrlService.GetBaseUrl(request);

            return(_singleResourceDocumentBuilder.BuildDocument(primaryResource, baseUrl, jsonApiPaths, null));
        }
Пример #6
0
        /// <summary>
        /// Generic method for getting the related resources for a to-many relationship
        /// </summary>
        protected async Task <IResourceCollectionDocument> GetRelatedToMany <TRelated>(string id,
                                                                                       ResourceTypeRelationship relationship, HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var param        = Expression.Parameter(typeof(T));
            var accessorExpr = Expression.Property(param, relationship.Property);
            var lambda       = Expression.Lambda <Func <T, IEnumerable <TRelated> > >(accessorExpr, param);

            var primaryEntityQuery = FilterById <T>(id, _resourceTypeRegistration);

            // We have to see if the resource even exists, so we can throw a 404 if it doesn't
            var relatedResource = await primaryEntityQuery.FirstOrDefaultAsync(cancellationToken);

            if (relatedResource == null)
            {
                throw JsonApiException.CreateForNotFound(string.Format("No resource of type `{0}` exists with id `{1}`.",
                                                                       _resourceTypeRegistration.ResourceTypeName, id));
            }

            var relatedResourceQuery = primaryEntityQuery.SelectMany(lambda);
            var sortExpressions      = _sortExpressionExtractor.ExtractSortExpressions(request);

            return(await _queryableResourceCollectionDocumentBuilder.BuildDocument(relatedResourceQuery, request, sortExpressions, cancellationToken));
        }
Пример #7
0
        protected override void Load(ContainerBuilder builder)
        {
            // Register resource types
            var registry = new ResourceTypeRegistry();

            foreach (var resourceTypeConfiguration in _jsonApiConfiguration.ResourceTypeConfigurations)
            {
                var resourceTypeRegistration = resourceTypeConfiguration.BuildResourceTypeRegistration();
                registry.AddRegistration(resourceTypeRegistration);

                var configuration = resourceTypeConfiguration;
                builder.Register(c => configuration)
                .Keyed <IResourceTypeConfiguration>(resourceTypeRegistration.Type)
                .Keyed <IResourceTypeConfiguration>(resourceTypeRegistration.ResourceTypeName)
                .SingleInstance();

                if (resourceTypeConfiguration.DocumentMaterializerType != null)
                {
                    builder.RegisterType(resourceTypeConfiguration.DocumentMaterializerType);
                }
                if (resourceTypeConfiguration.ResourceCollectionResolverType != null)
                {
                    builder.RegisterType(resourceTypeConfiguration.ResourceCollectionResolverType);
                }

                foreach (var relationship in resourceTypeRegistration.Relationships)
                {
                    IResourceTypeRelationshipConfiguration relationshipConfiguration;
                    if (resourceTypeConfiguration.RelationshipConfigurations
                        .TryGetValue(relationship.Property.Name, out relationshipConfiguration))
                    {
                        if (relationshipConfiguration.MaterializerType != null)
                        {
                            builder.RegisterType(relationshipConfiguration.MaterializerType);
                            continue;
                        }
                    }

                    // They didn't set an explicit materializer. See if they specified a factory for this resource type.
                    if (configuration.RelatedResourceMaterializerTypeFactory == null)
                    {
                        continue;
                    }

                    var materializerType = configuration.RelatedResourceMaterializerTypeFactory(relationship);
                    builder.RegisterType(materializerType);
                }
            }

            builder.Register(c => registry).As <IResourceTypeRegistry>().SingleInstance();
            builder.Register(c =>
            {
                var context = c.Resolve <IComponentContext>();
                Func <string, IDocumentMaterializer> factory = resourceTypeName =>
                {
                    var configuration = context.ResolveKeyed <IResourceTypeConfiguration>(resourceTypeName);
                    var registration  = registry.GetRegistrationForResourceTypeName(resourceTypeName);
                    var parameters    = new Parameter[] { new TypedParameter(typeof(IResourceTypeRegistration), registration) };
                    if (configuration.ResourceCollectionResolverType != null)
                    {
                        var collectionResolver = context.Resolve(configuration.ResourceCollectionResolverType, parameters);
                        parameters             = new Parameter[] { new TypedParameter(typeof(IResourceTypeRegistration), registration), new NamedParameter("collectionResolver", collectionResolver), };
                    }
                    if (configuration.DocumentMaterializerType != null)
                    {
                        return((IDocumentMaterializer)context.Resolve(configuration.DocumentMaterializerType, parameters));
                    }
                    return(context.Resolve <IDocumentMaterializer>(parameters));
                };
                return(factory);
            });
            builder.Register(c =>
            {
                var context = c.Resolve <IComponentContext>();
                Func <Type, IDocumentMaterializer> factory = clrType =>
                {
                    var configuration = context.ResolveKeyed <IResourceTypeConfiguration>(clrType);
                    var registration  = registry.GetRegistrationForType(clrType);
                    var parameters    = new List <Parameter> {
                        new TypedParameter(typeof(IResourceTypeRegistration), registration)
                    };

                    // add parameter for collectionResolver
                    if (configuration.ResourceCollectionResolverType != null)
                    {
                        var collectionResolver = context.Resolve(configuration.ResourceCollectionResolverType, parameters);
                        parameters.Add(new NamedParameter("collectionResolver", collectionResolver));
                    }

                    if (configuration.DocumentMaterializerType != null)
                    {
                        return((IDocumentMaterializer)context.Resolve(configuration.DocumentMaterializerType, parameters));
                    }
                    return(context.Resolve <IDocumentMaterializer>(parameters));
                };
                return(factory);
            });
            builder.Register(c =>
            {
                var context = c.Resolve <IComponentContext>();
                Func <string, string, IRelatedResourceDocumentMaterializer> factory = (resourceTypeName, relationshipName) =>
                {
                    var configuration = context.ResolveKeyed <IResourceTypeConfiguration>(resourceTypeName);
                    var registration  = registry.GetRegistrationForResourceTypeName(resourceTypeName);
                    var relationship  = registration.GetFieldByName(relationshipName) as ResourceTypeRelationship;
                    if (relationship == null)
                    {
                        throw JsonApiException.CreateForNotFound(
                            string.Format("No relationship `{0}` exists for the resource type `{1}`.", relationshipName, resourceTypeName));
                    }

                    var parameters = new List <Parameter>
                    {
                        new TypedParameter(typeof(IResourceTypeRegistration), registration),
                        new TypedParameter(typeof(ResourceTypeRelationship), relationship)
                    };

                    // add parameter for collectionResolver
                    if (context.IsRegisteredWithKey <IResourceTypeConfiguration>(relationship.RelatedType))
                    {
                        var relConfiguration = context.ResolveKeyed <IResourceTypeConfiguration>(relationship.RelatedType);
                        if (relConfiguration.ResourceCollectionResolverType != null)
                        {
                            var collectionResolver = context.Resolve(relConfiguration.ResourceCollectionResolverType, parameters);
                            parameters.Add(new NamedParameter("collectionResolver", collectionResolver));
                        }
                    }

                    // First, see if they have set an explicit materializer for this relationship
                    IResourceTypeRelationshipConfiguration relationshipConfiguration;
                    if (configuration.RelationshipConfigurations.TryGetValue(relationship.Property.Name,
                                                                             out relationshipConfiguration) && relationshipConfiguration.MaterializerType != null)
                    {
                        return((IRelatedResourceDocumentMaterializer)context.Resolve(relationshipConfiguration.MaterializerType, parameters));
                    }

                    // They didn't set an explicit materializer. See if they specified a factory for this resource type.
                    if (configuration.RelatedResourceMaterializerTypeFactory != null)
                    {
                        var materializerType = configuration.RelatedResourceMaterializerTypeFactory(relationship);
                        return((IRelatedResourceDocumentMaterializer)context.Resolve(materializerType, parameters));
                    }

                    return(context.Resolve <IRelatedResourceDocumentMaterializer>(parameters));
                };
                return(factory);
            });

            builder.RegisterType <JsonApiHttpConfiguration>().SingleInstance();
            if (_jsonApiConfiguration.CustomBaseUrlService != null)
            {
                builder.Register(c => _jsonApiConfiguration.CustomBaseUrlService).As <IBaseUrlService>().SingleInstance();
            }
            else
            {
                builder.RegisterType <BaseUrlService>().As <IBaseUrlService>().SingleInstance();
            }
            builder.RegisterType <DocumentMaterializerLocator>().As <IDocumentMaterializerLocator>().InstancePerRequest();

            // Serialization
            builder.RegisterType <MetadataFormatter>().As <IMetadataFormatter>().SingleInstance();
            builder.RegisterType <LinkFormatter>().As <ILinkFormatter>().SingleInstance();
            builder.RegisterType <ResourceLinkageFormatter>().As <IResourceLinkageFormatter>().SingleInstance();
            builder.RegisterType <RelationshipObjectFormatter>().As <IRelationshipObjectFormatter>().SingleInstance();
            builder.RegisterType <ResourceObjectFormatter>().As <IResourceObjectFormatter>().SingleInstance();
            builder.RegisterType <SingleResourceDocumentFormatter>().As <ISingleResourceDocumentFormatter>().SingleInstance();
            builder.RegisterType <ResourceCollectionDocumentFormatter>().As <IResourceCollectionDocumentFormatter>().SingleInstance();
            builder.RegisterType <ErrorFormatter>().As <IErrorFormatter>().SingleInstance();
            builder.RegisterType <ErrorDocumentFormatter>().As <IErrorDocumentFormatter>().SingleInstance();

            // Queryable transforms
            builder.RegisterType <SynchronousEnumerationTransformer>().As <IQueryableEnumerationTransformer>().SingleInstance();
            builder.RegisterType <DefaultFilteringTransformer>().As <IQueryableFilteringTransformer>().SingleInstance();
            builder.RegisterType <DefaultSortingTransformer>().As <IQueryableSortingTransformer>().SingleInstance();
            builder.RegisterType <DefaultPaginationTransformer>().As <IQueryablePaginationTransformer>().SingleInstance();

            // Document building
            builder.Register(c => _jsonApiConfiguration.LinkConventions).As <ILinkConventions>().SingleInstance();
            builder.RegisterType <JsonApiFormatter>().SingleInstance();
            builder.RegisterType <RegistryDrivenResourceCollectionDocumentBuilder>().As <IResourceCollectionDocumentBuilder>().SingleInstance();
            builder.RegisterType <RegistryDrivenSingleResourceDocumentBuilder>().As <ISingleResourceDocumentBuilder>().SingleInstance();
            builder.RegisterType <FallbackDocumentBuilder>().As <IFallbackDocumentBuilder>().SingleInstance();
            builder.RegisterType <ErrorDocumentBuilder>().As <IErrorDocumentBuilder>().SingleInstance();
            builder.RegisterType <FallbackDocumentBuilderAttribute>().SingleInstance();
            builder.RegisterType <JsonApiExceptionFilterAttribute>().SingleInstance();
            builder.RegisterType <DefaultQueryableResourceCollectionDocumentBuilder>().As <IQueryableResourceCollectionDocumentBuilder>();

            // Misc
            builder.RegisterType <DefaultSortExpressionExtractor>().As <ISortExpressionExtractor>().SingleInstance();
            builder.RegisterType <DefaultIncludeExpressionExtractor>().As <IIncludeExpressionExtractor>().SingleInstance();
        }