// TODO: this method is gross.
        public async Task Invoke(HttpContext context)
        {
            using (MiniProfiler.Current.Step(nameof(KasbahRouterMiddleware)))
            {
                var kasbahWebContext = context.GetKasbahWebContext();

                // Load the model from the cache if this is a subsequent request
                if (context.Request.Query.TryGetValue("ti", out var traceIdentifier))
                {
                    var model = _cache.Get($"model:{traceIdentifier.First()}");

                    context.Items["kasbah:model"] = model;
                }

                if (context.Items["kasbah:model"] == null && kasbahWebContext.Site != null)
                {
                    var node = kasbahWebContext.Node;

                    if (node != null && node.PublishedVersion.HasValue)
                    {
                        var content = await GetContent(node, kasbahWebContext.TypeMapper, kasbahWebContext.ContentService);

                        if (content is IPresentable presentable)
                        {
                            var typeMapperContext = new TypeMapperContext();

                            async Task <ControlRenderModel> ControlToRenderModel(Control control)
                            {
                                using (MiniProfiler.Current.Step($"{nameof(ControlToRenderModel)}('{control.Alias}')"))
                                {
                                    if (control == null || string.IsNullOrEmpty(control.Alias))
                                    {
                                        return(null);
                                    }

                                    var component = _componentRegistry.GetByAlias(control.Alias);

                                    if (component == null)
                                    {
                                        _log.LogInformation($"Referenced component '{control.Alias}' not found");

                                        return(null);
                                    }

                                    async Task <object> ExtractProperties()
                                    {
                                        using (MiniProfiler.Current.Step("Mapping properties"))
                                        {
                                            if (control.Model == null)
                                            {
                                                return(null);
                                            }

                                            var dict = control.Model.ToObject <IDictionary <string, object> >();

                                            return(await kasbahWebContext.TypeMapper.MapTypeAsync(dict, component.Properties.Alias, kasbahWebContext.Node, kasbahWebContext.Node.PublishedVersion, typeMapperContext));
                                        }
                                    }

                                    var properties = await ExtractProperties();

                                    var controlModel = await GetModelAsync(kasbahWebContext, properties, component, presentable);

                                    var placeholderTasks = (control.Placeholders ?? new PlaceholderCollection()).Select(async ent => new KeyValuePair <string, IEnumerable <object> >(ent.Key, await Task.WhenAll(ent.Value.Select(ControlToRenderModel))));

                                    var placeholders = await Task.WhenAll(placeholderTasks);

                                    var controls = placeholders.ToDictionary(ent => ent.Key, ent => ent.Value);

                                    return(new ControlRenderModel
                                    {
                                        Component = control.Alias,
                                        Model = controlModel,
                                        Controls = controls
                                    });
                                }
                            }

                            var layout = await ControlToRenderModel(presentable.Layout);

                            var model = new RenderModel
                            {
                                TraceIdentifier = context.TraceIdentifier,
                                Node            = node,
                                Site            = kasbahWebContext.Site,
                                SiteNode        = kasbahWebContext.SiteNode,
                                Layout          = layout
                            };

                            context.Items["kasbah:model"] = model;

                            _cache.Set($"model:{context.TraceIdentifier}", model, TimeSpan.FromMinutes(5));
                        }
                        else
                        {
                            context.Response.StatusCode = 400;
                            if (context.Request.Headers.TryGetValue("Accept", out var accept) && accept.Contains("application/json"))
                            {
                                context.Response.Headers.Add("Content-Type", "application/json");
                                await context.Response.WriteAsync(JsonConvert.SerializeObject(new { error = "Requested content cannot be rendered" }));
                            }
                            else
                            {
                                await context.Response.WriteAsync("Requested content cannot be rendered");
                            }

                            return;
                        }
                    }
                }
            }

            await _next.Invoke(context);
        }