Ejemplo n.º 1
0
        public static async Task HandleAsync(
            IResourceEventRepository resourceEventRepository,
            IApiLinkGenerator apiLinkGenerator,
            ApiOperationContext context,
            OperationResult result)
        {
            if (result is OkResult okResult)
            {
                var innerResult = okResult.Content;

                if (innerResult is ResourceEvent resourceEvent)
                {
                    var logger = context.ServiceProvider.GetRequiredService <ILogger <ResourceEventHandlerMiddlewareBuilder> >();

                    void AddMetadata(string k, object v) => resourceEvent.Metadata[k] = v;

                    context.UserAuthorisationContext?.PopulateMetadata(AddMetadata);

                    resourceEvent.CorrelationId = context.Activity?.Id;
                    resourceEvent.Operation     = context.Operation;

                    var metadataProviders = context.ServiceProvider.GetServices <IContextMetadataProvider>();

                    foreach (var p in metadataProviders)
                    {
                        await p.PopulateMetadataAsync(context, AddMetadata);
                    }

                    // If we do not already have Data use the "SelfQuery" to populate using a nested query if possible
                    if (resourceEvent.Data == null && resourceEvent.SelfQuery != null)
                    {
                        await TryPopulateResourceEventDataAsync(context, resourceEvent);
                    }

                    var selfLink = context.DataModel.GetLinkFor(resourceEvent.ResourceType, "self");

                    if (selfLink == null)
                    {
                        logger.LogWarning(
                            "No self link exists. Href property of the resource event of type {ResourceType} will not be populated",
                            resourceEvent.ResourceType);
                    }
                    else
                    {
                        resourceEvent.Href = apiLinkGenerator.CreateUrl(selfLink, resourceEvent.Data ?? resourceEvent.SelfQuery);
                    }

                    if (resourceEvent.Data != null)
                    {
                        await TryPopulateChangedValuesAsync(resourceEventRepository, resourceEvent);
                    }

                    await resourceEventRepository.AddAsync(resourceEvent);
                }
            }
        }
        private static async ValueTask <object> AddResourceLinksAsync(
            ILogger <LinkGeneratorMiddlewareBuilder> logger,
            IApiLinkGenerator apiLinkGenerator,
            IEnumerable <IResourceLinkGenerator> generators,
            ApiOperationContext context,
            object resource)
        {
            if (resource is ILinkableResource linkableResource)
            {
                await AddLinksAsync(logger, apiLinkGenerator, generators, context, linkableResource);
            }

            var enumerableResult = resource as IEnumerable <object>;

            if (resource is IPagedApiResource pagedResult)
            {
                enumerableResult = pagedResult.GetEnumerable();
            }

            if (enumerableResult != null)
            {
                if (enumerableResult is IQueryable <object> )
                {
                    // We need to ensure we are now dealing with a non-deferred result, else the
                    // links will be added, but the deferred result is still returned and so
                    // changes are lost.
                    //
                    // This needs to be what we then actually return from the middleware after the
                    // links have been added
                    enumerableResult = enumerableResult.ToList();
                    resource         = enumerableResult;
                }

                foreach (var obj in enumerableResult)
                {
                    if (obj is ILinkableResource apiResourceItem)
                    {
                        await AddLinksAsync(logger, apiLinkGenerator, generators, context, apiResourceItem);
                    }
                    else
                    {
                        // If we cannot add any links because not a `LinkableResource` then break early
                        // as we assume all entries are the same type
                        if (logger.IsEnabled(LogLevel.Trace))
                        {
                            logger.LogTrace("Resource type is not a LinkableResource. resource_type={0}", obj.GetType().Name);
                        }

                        break;
                    }
                }
            }

            return(resource);
        }
        public static async Task AddLinksAsync(
            IApiLinkGenerator apiLinkGenerator,
            IEnumerable <IResourceLinkGenerator> registeredGenerators,
            ApiOperationContext context,
            OperationResult result)
        {
            if (result is OkResult okResult)
            {
                var logger = context.ServiceProvider.GetRequiredService <ILogger <LinkGeneratorMiddlewareBuilder> >();

                okResult.Content = await AddResourceLinksAsync(logger, apiLinkGenerator, registeredGenerators, context, okResult.Content);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="EntityOperationResourceLinkGenerator"/> class.
        /// </summary>
        /// <param name="apiAuthoriserAggregator">An authorisor aggregrator to check if links are allowed to be shown to a user.</param>
        /// <param name="linkGenerator">A link generator to create the URLs of generated links.</param>
        /// <param name="logger">The logger.</param>
        public EntityOperationResourceLinkGenerator(
            IApiAuthoriserAggregator apiAuthoriserAggregator,
            IApiLinkGenerator linkGenerator,
            ILogger <EntityOperationResourceLinkGenerator> logger)
        {
            Guard.NotNull(nameof(apiAuthoriserAggregator), apiAuthoriserAggregator);
            Guard.NotNull(nameof(linkGenerator), linkGenerator);
            Guard.NotNull(nameof(logger), logger);

            this._apiAuthoriserAggregator = apiAuthoriserAggregator;
            this._linkGenerator           = linkGenerator;
            this._logger = logger;
        }
        public static async Task HandleAsync(
            IResourceEventRepository resourceEventRepository,
            IApiLinkGenerator apiLinkGenerator,
            ApiOperationContext context,
            OperationResult result)
        {
            if (result is OkResult okResult)
            {
                var innerResult = okResult.Content;

                if (innerResult is ResourceEvent resourceEvent)
                {
                    var logger = context.ServiceProvider.GetRequiredService <ILogger <ResourceEventHandlerMiddlewareBuilder> >();

                    logger.LogDebug("ResourceEvent found. Loading resource. resource_type={0}", resourceEvent.ResourceType);

                    void AddMetadata(string k, object v) => resourceEvent.Metadata[k] = v;

                    context.UserAuthorisationContext?.PopulateMetadata(AddMetadata);

                    resourceEvent.CorrelationId = Activity.Current?.Id;
                    resourceEvent.Operation     = context.Operation;

                    var metadataProviders = context.ServiceProvider.GetServices <IContextMetadataProvider>();

                    foreach (var p in metadataProviders)
                    {
                        await p.PopulateMetadataAsync(context, AddMetadata);
                    }

                    var selfLink = context.DataModel.GetLinkFor(resourceEvent.ResourceType, "self");

                    if (selfLink == null)
                    {
                        logger.LogWarning(
                            "No self link exists. Link and payload will not be populated. resource_type={0}",
                            resourceEvent.ResourceType.Name);

                        return;
                    }

                    resourceEvent.Href = apiLinkGenerator.CreateUrl(selfLink, resourceEvent.SelfQuery);

                    await PopulateResourceEventData(resourceEventRepository, context, resourceEvent);

                    await resourceEventRepository.AddAsync(resourceEvent);
                }
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Invokes this query, returning a simple model of available routes within this API.
        /// </summary>
        /// <param name="linkGenerator">The API link generator.</param>
        /// <param name="dataModel">The API data model.</param>
        /// <returns>A <see cref="RootResource" />.</returns>
        public RootResource Invoke(IApiLinkGenerator linkGenerator, ApiDataModel dataModel)
        {
            var systemResource = new RootResource();

            foreach (var link in dataModel.GetRootLinks())
            {
                if (link.OperationDescriptor.IsExposed)
                {
                    systemResource.AddLink(link.Rel, new Link
                    {
                        Href = linkGenerator.CreateUrl(link),
                    });
                }
            }

            return(systemResource);
        }
        private static async ValueTask AddLinksAsync(
            ILogger logger,
            IApiLinkGenerator apiLinkGenerator,
            IEnumerable <IResourceLinkGenerator> generators,
            ApiOperationContext context,
            ILinkableResource result)
        {
            foreach (var resourceLinkGenerator in generators)
            {
                if (logger.IsEnabled(LogLevel.Trace))
                {
                    logger.LogTrace("Generating links. generator={0} result_type={1}", resourceLinkGenerator.GetType().Name, result.GetType().Name);
                }

                await resourceLinkGenerator.AddLinksAsync(apiLinkGenerator, context, result);
            }
        }
Ejemplo n.º 8
0
 /// <inheritdoc />
 public ValueTask AddLinksAsync(IApiLinkGenerator apiLinkGenerator, ApiOperationContext context, ILinkableResource linkableResource)
 {
     if (!(linkableResource is T asTypedResource))
     {
         return(default);
Ejemplo n.º 9
0
        /// <inheritdoc/>
        public async ValueTask AddLinksAsync(IApiLinkGenerator apiLinkGenerator, ApiOperationContext context, ILinkableResource linkableResource)
        {
            Guard.NotNull(nameof(context), context);
            Guard.NotNull(nameof(linkableResource), linkableResource);

            var traceLogEnabled = this._logger.IsEnabled(LogLevel.Trace);
            var links           = context.DataModel.GetLinksForResource(linkableResource.GetType());

            if (links.Count == 0)
            {
                if (traceLogEnabled)
                {
                    this._logger.LogTrace(
                        "No links have been registered for linkable resource {0}",
                        linkableResource.GetType());
                }

                return;
            }

            // When trace is enabled, log all links we would be checking, else if debug just the count, otherwise nothing logged here
            if (traceLogEnabled)
            {
                this._logger.LogTrace("Attempting to add {0} links for the linkable resource {1}.", links.Count, linkableResource.GetType());
            }

            foreach (var link in links)
            {
                var entityOperation     = link.OperationDescriptor;
                var entityOperationName = entityOperation.OperationType.Name;

                if (!entityOperation.IsExposed)
                {
                    if (traceLogEnabled)
                    {
                        this._logger.LogTrace("Operation not exposed, excluding. operation_type={0}", entityOperationName);
                    }

                    continue;
                }

                var result = await this._apiAuthoriserAggregator.CanShowLinkAsync(context, entityOperation, linkableResource);

                if (result.IsAllowed == false)
                {
                    if (traceLogEnabled)
                    {
                        this._logger.LogTrace("Operation is not allowed to be executed, excluding. operation_type={0}", entityOperationName);
                    }

                    continue;
                }

                var url = this._linkGenerator.CreateUrl(link, linkableResource);

                // We could not generate this URL, a placeholder value could not be injected. We therefore skip it
                if (url == null)
                {
                    if (traceLogEnabled)
                    {
                        this._logger.LogTrace("Cannot add link, URL was not generated. operation_type={0}", entityOperationName);
                    }

                    continue;
                }

                if (traceLogEnabled)
                {
                    this._logger.LogTrace("All checks passed. Adding link. operation_type={0}", entityOperationName);
                }

                linkableResource.AddLink(link.Rel, new Link
                {
                    Href = url,
                });
            }
        }