public async Task Invoke(HttpContext context)
    {
        // Invoke the 'normal' pipeline first.
        // Note that the mvc middleware would serialize the response...
        // Prevent that by injecting a custom IActionResultExecutor<ObjectResult>,
        // that sets the ActionResult to the context instead of serializing.
        await this.next(context);

        // Our objectresultexecutor added some information on the HttpContext.
        if (!context.Items.TryGetValue("HalFormattingContext", out object formatObject) ||
            !(formatObject is HalFormattingContext halFormattingContext))
        {
            logger.LogDebug("Hal formatting context not found, other formatters are handling this response.");
            return;
        }
        // some code to create a resource object from the result.
        var rootResource = ConstructRootResource(halFormattingContext.ObjectResult);

        halFormattingContext.ObjectResult.Value = rootResource;
        // some code to figure out which actions/routes to embed.
        var toEmbeds       = GetRoutesToEmbed(halFormattingContext.ActionContext);
        var requestFeature = context.Features.Get <IHttpRequestFeature>();

        foreach (var toEmbed in toEmbeds)
        {
            var halRequestFeature = new HalHttpRequestFeature(requestFeature)
            {
                Method = "GET",
                Path   = toEmbed.Path
            };
            // The HalHttpContext creates a custom request and response in the constructor
            // and creates a new feature collection with custom request and response features.
            var halContext = new HalHttpContext(context, halRequestFeature);
            await this.next(halContext);

            // Now the custom ObjectResultExecutor set the ActionResult to a property of the custom HttpResponse.
            var embedActionResult = ((HalHttpResponse)halContext.Response).ObjectResult;

            // some code to embed the new actionresult.
            Embed(rootResource, embedActionResult, toEmbed);
        }
        // Then invoke the default ObjectResultExecutor to serialize the new result.
        await halFormattingContext.DefaultExecutor.ExecuteAsync(
            halFormattingContext.ActionContext,
            halFormattingContext.ObjectResult);
    }
Beispiel #2
0
        public async Task <HalResourceInspectedContext> OnResourceInspectionAsync(
            HalResourceInspectingContext context,
            HalResourceInspectionDelegate next)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (next == null)
            {
                throw new ArgumentNullException(nameof(next));
            }

            if (!context.IsRootResource)
            {
                throw new NotSupportedException("This inspector does not support embedded resources.");
            }

            if (context.Resource == null)
            {
                return(await next());
            }

            if (context.ActionContext == null)
            {
                throw new ArgumentException("ActionContext cannot be null.", nameof(context));
            }

            if (!(context.ActionContext.ActionDescriptor is ControllerActionDescriptor descriptor))
            {
                throw new HalException("Could not establish ControllerActionDescriptor reference.");
            }

            if (context.ActionContext.HttpContext == null || context.ActionContext.HttpContext.Features == null)
            {
                throw new ArgumentException("HttpContext features cannot be null.", nameof(context));
            }

            if (context.MvcPipeline == null)
            {
                throw new ArgumentException("Context does not contain the mvc pipeline.", nameof(context));
            }

            var requestFeature = context.ActionContext.HttpContext.Features.Get <IHttpRequestFeature>();
            var links          = linkService.GetLinks <HalEmbedAttribute>(descriptor, context.ActionContext, context.OriginalObject);

            foreach (var link in links)
            {
                var halRequestFeature = new HalHttpRequestFeature(requestFeature)
                {
                    Method = "GET",
                    Path   = link.Uri
                };

                var halContext = new HalHttpContext(context.ActionContext.HttpContext, halRequestFeature);

                logger.LogDebug("About to invoke MVC pipeline with a GET request on path '{0}'.", link.Uri);
                await context.MvcPipeline.Pipeline(halContext);

                var response = halContext.Response as HalHttpResponse;
                if (response.StatusCode >= 200 && response.StatusCode <= 299)
                {
                    logger.LogDebug("MVC pipeline returned success status code {0}. Invoking HAL resource factory.", response.StatusCode);
                    IResource embedded = await context.EmbeddedResourcePipeline(response.ActionContext, response.Resource);

                    embedded.Rel = link.Rel;

                    if (embedded is IResourceCollection collection)
                    {
                        if (collection.Collection != null)
                        {
                            logger.LogDebug("Embedding collection of {0} resources to rel '{0}'", collection.Collection.Count, link.Rel);
                            foreach (var item in collection.Collection)
                            {
                                item.Rel = link.Rel;
                                context.Resource.Embedded.Add(item);
                            }
                        }
                    }
                    else
                    {
                        logger.LogDebug("Embedding resource to rel '{0}'", link.Rel);
                        context.Resource.Embedded.Add(embedded);
                    }
                }
                else
                {
                    logger.LogWarning("MVC pipeline returned non-success status code {0}. Ignoring result.", response.StatusCode);
                }
            }

            var result = await next();

            logger.LogTrace("After invoke next.");

            return(result);
        }