diff --git a/core/core.services.yml b/core/core.services.yml
index 5399bc7..9b691a3 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -182,6 +182,7 @@ services:
     factory_class: Symfony\Component\HttpFoundation\Request
     factory_method: createFromGlobals
     #synthetic: true
+    synchronized: true
   event_dispatcher:
     class: Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher
     arguments: ['@service_container']
@@ -328,17 +329,17 @@ services:
     arguments: ['@content_negotiation']
     tags:
       - { name: route_enhancer, priority: 30 }
-  route_enhancer.ajax:
-    class: Drupal\Core\Routing\Enhancer\AjaxEnhancer
+  route_enhancer.entity:
+    class: Drupal\Core\Entity\Enhancer\EntityRouteEnhancer
     arguments: ['@content_negotiation']
     tags:
       - { name: route_enhancer, priority: 20 }
-      - { name: legacy_route_enhancer, priority: 20 }
-  route_enhancer.entity:
-    class: Drupal\Core\Entity\Enhancer\EntityRouteEnhancer
+  route_enhancer.ajax:
+    class: Drupal\Core\Routing\Enhancer\AjaxEnhancer
     arguments: ['@content_negotiation']
     tags:
       - { name: route_enhancer, priority: 15 }
+      - { name: legacy_route_enhancer, priority: 20 }
   route_enhancer.form:
     class: Drupal\Core\Routing\Enhancer\FormEnhancer
     arguments: ['@content_negotiation']
@@ -350,10 +351,13 @@ services:
       - { name: event_subscriber }
   controller.page:
     class: Drupal\Core\Controller\HtmlPageController
-    arguments: ['@http_kernel', '@controller_resolver']
+    arguments: ['@controller_resolver']
   controller.dialog:
     class: Drupal\Core\Controller\DialogController
-    arguments: ['@http_kernel']
+    arguments: ['@controller_resolver']
+  controller.ajax:
+    class: Drupal\Core\Controller\AjaxController
+    arguments: ['@controller_resolver']
   router_listener:
     class: Symfony\Component\HttpKernel\EventListener\RouterListener
     tags:
@@ -424,13 +428,11 @@ services:
     tags:
       - { name: event_subscriber }
     arguments: ['@language_manager']
-    scope: request
   redirect_response_subscriber:
     class: Drupal\Core\EventSubscriber\RedirectResponseSubscriber
     arguments: ['@url_generator']
     tags:
       - { name: event_subscriber }
-    scope: request
   request_close_subscriber:
     class: Drupal\Core\EventSubscriber\RequestCloseSubscriber
     tags:
diff --git a/core/lib/Drupal/Core/Controller/AjaxController.php b/core/lib/Drupal/Core/Controller/AjaxController.php
index 7b2cece..fd40496 100644
--- a/core/lib/Drupal/Core/Controller/AjaxController.php
+++ b/core/lib/Drupal/Core/Controller/AjaxController.php
@@ -10,13 +10,30 @@
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\InsertCommand;
 use Drupal\Core\Ajax\PrependCommand;
-use Symfony\Component\DependencyInjection\ContainerAware;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 
 /**
  * Default controller for ajax requests.
  */
-class AjaxController extends ContainerAware {
+class AjaxController {
+
+  /**
+   * The controller resolver.
+   *
+   * @var \Drupal\Core\Controller\ControllerResolverInterface
+   */
+  protected $controllerResolver;
+
+  /**
+   * Constructs a HtmlPageController instance.
+   *
+   * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
+   *   The controller resolver.
+   */
+  public function __construct(ControllerResolverInterface $controller_resolver) {
+    $this->controllerResolver = $controller_resolver;
+  }
 
   /**
    * Controller method for AJAX content.
@@ -30,50 +47,34 @@ class AjaxController extends ContainerAware {
    *   A response object.
    */
   public function content(Request $request, $_content) {
-
-    // @todo When we have a Generator, we can replace the forward() call with
-    // a render() call, which would handle ESI and hInclude as well.  That will
-    // require an _internal route.  For examples, see:
-    // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/internal.xml
-    // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/InternalController.php
-    $attributes = clone $request->attributes;
-    $controller = $_content;
-
-    // We need to clean up the derived information and such so that the
-    // subrequest can be processed properly without leaking data through.
-    $attributes->remove('_system_path');
-    $attributes->remove('_content');
-    $attributes->remove('_legacy');
-
-    // Remove the accept header so the subrequest does not end up back in this
-    // controller.
-    $request->headers->remove('accept');
-    // Remove the header in order to let the subrequest not think that it's an
-    // ajax request, see \Drupal\Core\ContentNegotiation.
-    $request->headers->remove('x-requested-with');
-
-    $response = $this->container->get('http_kernel')->forward($controller, $attributes->all(), $request->query->all());
-    // For successful (HTTP status 200) responses.
-    if ($response->isOk()) {
-      // If there is already an AjaxResponse, then return it without
-      // manipulation.
-      if (!($response instanceof AjaxResponse)) {
+    $callable = $this->controllerResolver->createController($_content);
+    $arguments = $this->controllerResolver->getArguments($request, $callable);
+    $response = call_user_func_array($callable, $arguments);
+    if ($response instanceof Response) {
+      if ($response instanceof AjaxResponse || !$response->isOk()) {
+        return $response;
+      }
+      else {
         // Pull the content out of the response.
         $content = $response->getContent();
-        // A page callback could return a render array or a string.
-        $html = is_string($content) ? $content : drupal_render($content);
-        $response = new AjaxResponse();
-        // The selector for the insert command is NULL as the new content will
-        // replace the element making the ajax call. The default 'replaceWith'
-        // behavior can be changed with #ajax['method'].
-        $response->addCommand(new InsertCommand(NULL, $html));
-        $status_messages = array('#theme' => 'status_messages');
-        $output = drupal_render($status_messages);
-        if (!empty($output)) {
-          $response->addCommand(new PrependCommand(NULL, $output));
-        }
       }
     }
+    else {
+      $content = $response;
+    }
+
+    // A page callback could return a render array or a string.
+    $html = is_string($content) ? $content : drupal_render($content);
+    $response = new AjaxResponse();
+    // The selector for the insert command is NULL as the new content will
+    // replace the element making the ajax call. The default 'replaceWith'
+    // behavior can be changed with #ajax['method'].
+    $response->addCommand(new InsertCommand(NULL, $html));
+    $status_messages = array('#theme' => 'status_messages');
+    $output = drupal_render($status_messages);
+    if (!empty($output)) {
+      $response->addCommand(new PrependCommand(NULL, $output));
+    }
     return $response;
   }
 }
diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php
index f363d65..dd9300b 100644
--- a/core/lib/Drupal/Core/Controller/ControllerResolver.php
+++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
@@ -100,21 +100,9 @@ public function getController(Request $request) {
   }
 
   /**
-   * Returns a callable for the given controller.
-   *
-   * @param string $controller
-   *   A Controller string.
-   *
-   * @return mixed
-   *   A PHP callable.
-   *
-   * @throws \LogicException
-   *   If the controller cannot be parsed
-   *
-   * @throws \InvalidArgumentException
-   *   If the controller class does not exist
+   * {@inheritdoc}
    */
-  protected function createController($controller) {
+  public function createController($controller) {
     // Controller in the service:method notation.
     $count = substr_count($controller, ':');
     if ($count == 1) {
diff --git a/core/lib/Drupal/Core/Controller/ControllerResolverInterface.php b/core/lib/Drupal/Core/Controller/ControllerResolverInterface.php
index b0179fe..0eec574 100644
--- a/core/lib/Drupal/Core/Controller/ControllerResolverInterface.php
+++ b/core/lib/Drupal/Core/Controller/ControllerResolverInterface.php
@@ -34,4 +34,21 @@
    */
   public function getControllerFromDefinition($controller);
 
+  /**
+   * Returns a callable for the given controller.
+   *
+   * @param string $controller
+   *   A Controller string.
+   *
+   * @return mixed
+   *   A PHP callable.
+   *
+   * @throws \LogicException
+   *   If the controller cannot be parsed
+   *
+   * @throws \InvalidArgumentException
+   *   If the controller class does not exist
+   */
+  public function createController($controller);
+
 }
diff --git a/core/lib/Drupal/Core/Controller/DialogController.php b/core/lib/Drupal/Core/Controller/DialogController.php
index cde2876..3340328 100644
--- a/core/lib/Drupal/Core/Controller/DialogController.php
+++ b/core/lib/Drupal/Core/Controller/DialogController.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Ajax\OpenDialogCommand;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 
 /**
@@ -19,51 +20,20 @@
 class DialogController {
 
   /**
-   * The HttpKernel object to use for subrequests.
+   * The controller resolver.
    *
-   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+   * @var \Drupal\Core\Controller\ControllerResolverInterface
    */
-  protected $httpKernel;
+  protected $controllerResolver;
 
   /**
    * Constructs a new DialogController.
    *
-   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel
-   *   The kernel.
+   * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
+   *   The controller resolver.
    */
-  public function __construct(HttpKernelInterface $kernel) {
-    $this->httpKernel = $kernel;
-  }
-
-  /**
-   * Forwards request to a subrequest.
-   *
-   * @param \Symfony\Component\HttpFoundation\RequestRequest $request
-   *   The request object.
-   *
-   * @return \Symfony\Component\HttpFoundation\Response
-   *   A response object.
-   */
-  protected function forward(Request $request) {
-    // @todo When we have a Generator, we can replace the forward() call with
-    // a render() call, which would handle ESI and hInclude as well.  That will
-    // require an _internal route.  For examples, see:
-    // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/internal.xml
-    // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/InternalController.php
-    $attributes = clone $request->attributes;
-    // We need to clean up the derived information and such so that the
-    // subrequest can be processed properly without leaking data through.
-    $attributes->remove('_system_path');
-    $attributes->set('dialog', TRUE);
-
-    // Remove the accept header so the subrequest does not end up back in this
-    // controller.
-    $request->headers->remove('accept');
-    // Remove the X-Requested-With header so the subrequest is not mistaken for
-    // an ajax request.
-    $request->headers->remove('x-requested-with');
-
-    return $this->httpKernel->forward(NULL, $attributes->all(), $request->query->all());
+  public function __construct(ControllerResolverInterface $controller_resolver) {
+    $this->controllerResolver = $controller_resolver;
   }
 
   /**
@@ -75,8 +45,8 @@ protected function forward(Request $request) {
    * @return \Drupal\Core\Ajax\AjaxResponse
    *   AjaxResponse to return the content wrapper in a modal dialog.
    */
-  public function modal(Request $request) {
-    return $this->dialog($request, TRUE);
+  public function modal(Request $request, $_content) {
+    return $this->dialog($request, $_content, TRUE);
   }
 
   /**
@@ -90,13 +60,29 @@ public function modal(Request $request) {
    * @return \Drupal\Core\Ajax\AjaxResponse
    *   AjaxResponse to return the content wrapper in a dialog.
    */
-  public function dialog(Request $request, $modal = FALSE) {
-    $subrequest = $this->forward($request);
-    if ($subrequest->isOk()) {
-      $content = $subrequest->getContent();
-      // @todo Remove use of drupal_get_title() when
-      //  http://drupal.org/node/1871596 is in.
-      $title = drupal_get_title();
+  public function dialog(Request $request, $_content, $modal = FALSE) {
+    $callable = $this->controllerResolver->createController($_content);
+    $arguments = $this->controllerResolver->getArguments($request, $callable);
+    $controller_response = call_user_func_array($callable, $arguments);
+
+    if ($controller_response instanceof Response) {
+      return $controller_response;
+    }
+    else {
+      if (!is_array($controller_response)) {
+        $content = array(
+          '#markup' => $controller_response,
+        );
+      }
+      else {
+        $content = $controller_response;
+      }
+
+      // If no title was returned fall back to one defined in the route.
+      if (!isset($content['#title']) && $request->attributes->has('_title')) {
+        $content['#title'] = $request->attributes->get('_title');
+      }
+
       $response = new AjaxResponse();
       // Fetch any modal options passed in from data-dialog-options.
       if (!($options = $request->request->get('dialogOptions'))) {
@@ -125,10 +111,11 @@ public function dialog(Request $request, $modal = FALSE) {
           $target = '#' . drupal_html_id("drupal-dialog-$route_name");
         }
       }
-      $response->addCommand(new OpenDialogCommand($target, $title, $content, $options));
+      $response->addCommand(new OpenDialogCommand($target, isset($content['#title']) ? $content['#title'] : '', drupal_render($content), $options));
       return $response;
     }
     // An error occurred in the subrequest, return that.
-    return $subrequest;
+    return $controller_response;
   }
+
 }
diff --git a/core/lib/Drupal/Core/Controller/HtmlPageController.php b/core/lib/Drupal/Core/Controller/HtmlPageController.php
index d87b3ed..cdb0174 100644
--- a/core/lib/Drupal/Core/Controller/HtmlPageController.php
+++ b/core/lib/Drupal/Core/Controller/HtmlPageController.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Controller;
 
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
@@ -17,13 +18,6 @@
 class HtmlPageController {
 
   /**
-   * The HttpKernel object to use for subrequests.
-   *
-   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
-   */
-  protected $httpKernel;
-
-  /**
    * The controller resolver.
    *
    * @var \Drupal\Core\Controller\ControllerResolverInterface
@@ -33,12 +27,10 @@ class HtmlPageController {
   /**
    * Constructs a new HtmlPageController.
    *
-   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel
    * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
    *   The controller resolver.
    */
-  public function __construct(HttpKernelInterface $kernel, ControllerResolverInterface $controller_resolver) {
-    $this->httpKernel = $kernel;
+  public function __construct(ControllerResolverInterface $controller_resolver) {
     $this->controllerResolver = $controller_resolver;
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php b/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php
index 2cf8d47..bf9023d 100644
--- a/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php
+++ b/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php
@@ -38,7 +38,7 @@ public function __construct(ContentNegotiation $negotiation) {
    * {@inheritdoc}
    */
   public function enhance(array $defaults, Request $request) {
-    if (empty($defaults['_controller']) && $this->negotiation->getContentType($request) === 'html') {
+    if (empty($defaults['_controller']) && in_array($this->negotiation->getContentType($request), array('html', 'drupal_ajax'))) {
       if (!empty($defaults['_entity_form'])) {
         $defaults['_controller'] = '\Drupal\Core\Entity\HtmlEntityFormController::content';
       }
diff --git a/core/lib/Drupal/Core/HttpKernel.php b/core/lib/Drupal/Core/HttpKernel.php
index 07c79c7..ec426c7 100644
--- a/core/lib/Drupal/Core/HttpKernel.php
+++ b/core/lib/Drupal/Core/HttpKernel.php
@@ -2,12 +2,7 @@
 
 /**
  * @file
- * Definition of Drupal\Core\HttpKernel.
- *
- * @todo This file is copied verbatim, with the exception of the namespace
- * change and this commment block, from Symfony full stack's FrameworkBundle.
- * Once the FrameworkBundle is available as a Composer package we should switch
- * to pulling it via Composer.
+ * Contains \Drupal\Core\HttpKernel.
  */
 
 namespace Drupal\Core;
@@ -23,249 +18,42 @@
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
- * This HttpKernel is used to manage scope changes of the DI container.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * HttpKernel extension to allow easy in-process subrequests.
  */
-class HttpKernel extends BaseHttpKernel
-{
-    protected $container;
+class HttpKernel extends BaseHttpKernel {
 
-    private $esiSupport;
-
-    public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver)
-    {
-        parent::__construct($dispatcher, $controllerResolver);
-
-        $this->container = $container;
-    }
-
-    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
-    {
-        $request->headers->set('X-Php-Ob-Level', ob_get_level());
-
-        $this->container->enterScope('request');
-        $this->container->set('request', $request, 'request');
-
-        try {
-            $response = parent::handle($request, $type, $catch);
-        } catch (\Exception $e) {
-            $this->container->leaveScope('request');
-
-            throw $e;
-        }
-
-        $this->container->leaveScope('request');
-
-        return $response;
-    }
-
-    /**
-     * Forwards the request to another controller.
-     *
-     * @param string|NULL $controller
-     *   The controller name (a string like BlogBundle:Post:index).
-     * @param array $attributes
-     *   An array of request attributes.
-     * @param array $query
-     *   An array of request query parameters.
-     *
-     * @return Response
-     *   A Response instance
-     */
-    public function forward($controller, array $attributes = array(), array $query = array())
-    {
-      $subrequest = $this->setupSubrequest($controller, $attributes, $query);
-
-      return $this->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
-    }
-
-    /**
-     * Renders a Controller and returns the Response content.
-     *
-     * Note that this method generates an esi:include tag only when both the standalone
-     * option is set to true and the request has ESI capability (@see Symfony\Component\HttpKernel\HttpCache\ESI).
-     *
-     * Available options:
-     *
-     *  * attributes: An array of request attributes (only when the first argument is a controller)
-     *  * query: An array of request query parameters (only when the first argument is a controller)
-     *  * ignore_errors: true to return an empty string in case of an error
-     *  * alt: an alternative controller to execute in case of an error (can be a controller, a URI, or an array with the controller, the attributes, and the query arguments)
-     *  * standalone: whether to generate an esi:include tag or not when ESI is supported
-     *  * comment: a comment to add when returning an esi:include tag
-     *
-     * @param string $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
-     * @param array  $options    An array of options
-     *
-     * @return string The Response content
-     */
-    public function render($controller, array $options = array())
-    {
-        $options = array_merge(array(
-            'attributes'    => array(),
-            'query'         => array(),
-            'ignore_errors' => !$this->container->getParameter('kernel.debug'),
-            'alt'           => array(),
-            'standalone'    => false,
-            'comment'       => '',
-        ), $options);
-
-        if (!is_array($options['alt'])) {
-            $options['alt'] = array($options['alt']);
-        }
-
-        if (null === $this->esiSupport) {
-            $this->esiSupport = $this->container->has('esi') && $this->container->get('esi')->hasSurrogateEsiCapability($this->container->get('request'));
-        }
-
-        if ($this->esiSupport && (true === $options['standalone'] || 'esi' === $options['standalone'])) {
-            $uri = $this->generateInternalUri($controller, $options['attributes'], $options['query']);
-
-            $alt = '';
-            if ($options['alt']) {
-                $alt = $this->generateInternalUri($options['alt'][0], isset($options['alt'][1]) ? $options['alt'][1] : array(), isset($options['alt'][2]) ? $options['alt'][2] : array());
-            }
-
-            return $this->container->get('esi')->renderIncludeTag($uri, $alt, $options['ignore_errors'], $options['comment']);
-        }
-
-        if ('js' === $options['standalone']) {
-            $uri = $this->generateInternalUri($controller, $options['attributes'], $options['query'], false);
-            $defaultContent = null;
-
-            if ($template = $this->container->getParameter('templating.hinclude.default_template')) {
-                $defaultContent = $this->container->get('templating')->render($template);
-            }
-
-            return $this->renderHIncludeTag($uri, $defaultContent);
-        }
-
-        $request = $this->container->get('request');
-
-        // controller or URI?
-        if (0 === strpos($controller, '/')) {
-            $subRequest = Request::create($request->getUriForPath($controller), 'get', array(), $request->cookies->all(), array(), $request->server->all());
-            if ($session = $request->getSession()) {
-                $subRequest->setSession($session);
-            }
-        } else {
-            $options['attributes']['_controller'] = $controller;
-
-            if (!isset($options['attributes']['_format'])) {
-                $options['attributes']['_format'] = $request->getRequestFormat();
-            }
-
-            $options['attributes'][RouteObjectInterface::ROUTE_OBJECT] = '_internal';
-            $subRequest = $request->duplicate($options['query'], null, $options['attributes']);
-            $subRequest->setMethod('GET');
-        }
-
-        $level = ob_get_level();
-        try {
-            $response = $this->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
-
-            if (!$response->isSuccessful()) {
-                throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode()));
-            }
-
-            if (!$response instanceof StreamedResponse) {
-                return $response->getContent();
-            }
-
-            $response->sendContent();
-        } catch (\Exception $e) {
-            if ($options['alt']) {
-                $alt = $options['alt'];
-                unset($options['alt']);
-                $options['attributes'] = isset($alt[1]) ? $alt[1] : array();
-                $options['query'] = isset($alt[2]) ? $alt[2] : array();
-
-                return $this->render($alt[0], $options);
-            }
-
-            if (!$options['ignore_errors']) {
-                throw $e;
-            }
-
-            // let's clean up the output buffers that were created by the sub-request
-            while (ob_get_level() > $level) {
-                ob_get_clean();
-            }
-        }
-    }
-
-    /**
-     * Generates an internal URI for a given controller.
-     *
-     * This method uses the "_internal" route, which should be available.
-     *
-     * @param string  $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
-     * @param array   $attributes An array of request attributes
-     * @param array   $query      An array of request query parameters
-     * @param boolean $secure
-     *
-     * @return string An internal URI
-     */
-    public function generateInternalUri($controller, array $attributes = array(), array $query = array(), $secure = true)
-    {
-        if (0 === strpos($controller, '/')) {
-            return $controller;
-        }
+  /**
+   * Constructs a \Drupal\Core\HttpKernel object.
+   *
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
+   *   The event dispatcher.
+   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+   *   The service container.
+   * @param \Symfony\Component\HttpKernel\Controller\ControllerResolverInterface $resolver
+   *   The controller resolver.
+   */
+  public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $resolver) {
+    parent::__construct($dispatcher, $resolver);
+    $this->container = $container;
+  }
 
-        $path = http_build_query($attributes, '', '&');
-        $uri = $this->container->get('router')->generate($secure ? '_internal' : '_internal_public', array(
-            'controller' => $controller,
-            'path'       => $path ?: 'none',
-            '_format'    => $this->container->get('request')->getRequestFormat(),
-        ));
+  public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) {
+    $request->headers->set('X-Php-Ob-Level', ob_get_level());
 
-        if ($queryString = http_build_query($query, '', '&')) {
-            $uri .= '?'.$queryString;
-        }
+    $this->container->enterScope('request');
+    $this->container->set('request', $request, 'request');
 
-        return $uri;
+    try {
+      $response = parent::handle($request, $type, $catch);
     }
-
-    /**
-     * Renders an HInclude tag.
-     *
-     * @param string $uri A URI
-     * @param string $defaultContent Default content
-     */
-    public function renderHIncludeTag($uri, $defaultContent = null)
-    {
-        return sprintf('<hx:include src="%s">%s</hx:include>', $uri, $defaultContent);
+    catch (\Exception $e) {
+      $this->container->leaveScope('request');
+      throw $e;
     }
 
-    public function hasEsiSupport()
-    {
-        return $this->esiSupport;
-    }
+    $this->container->leaveScope('request');
 
-  /**
-   * Creates a request object for a subrequest.
-   *
-   * @param string $controller
-   *   The controller name (a string like BlogBundle:Post:index)
-   * @param array $attributes
-   *   An array of request attributes.
-   * @param array $query
-   *   An array of request query parameters.
-   *
-   * @return \Symfony\Component\HttpFoundation\Request
-   *   Returns the new request.
-   */
-  public function setupSubrequest($controller, array $attributes, array $query) {
-    // Don't override the controller if it's NULL.
-    if (isset($controller)) {
-      $attributes['_controller'] = $controller;
-    }
-    else {
-      unset($attributes['_controller']);
-    }
-    return $this->container->get('request')->duplicate($query, NULL, $attributes);
+    return $response;
   }
 
 }
diff --git a/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php
index 47c5179..7c4a1df 100644
--- a/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php
+++ b/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php
@@ -39,7 +39,7 @@ public function __construct(ContentNegotiation $negotiation) {
   public function enhance(array $defaults, Request $request) {
     if (empty($defaults['_content']) && $this->negotiation->getContentType($request) == 'drupal_ajax') {
       $defaults['_content'] = isset($defaults['_controller']) ? $defaults['_controller'] : NULL;
-      $defaults['_controller'] = '\Drupal\Core\Controller\AjaxController::content';
+      $defaults['_controller'] = 'controller.ajax:content';
     }
     return $defaults;
   }
diff --git a/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php
index e088d44..de2d41f 100644
--- a/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php
+++ b/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php
@@ -58,11 +58,6 @@ public function enhance(array $defaults, Request $request) {
         $defaults['_controller'] = $this->types[$type];
       }
     }
-    // When the dialog attribute is TRUE this is a DialogController sub-request.
-    // Route the sub-request to the _content callable.
-    if ($request->attributes->get('dialog') && !empty($defaults['_content'])) {
-      $defaults['_controller'] = $defaults['_content'];
-    }
     return $defaults;
   }
 }
diff --git a/core/modules/system/tests/modules/ajax_test/ajax_test.module b/core/modules/system/tests/modules/ajax_test/ajax_test.module
index e358018..3217c41 100644
--- a/core/modules/system/tests/modules/ajax_test/ajax_test.module
+++ b/core/modules/system/tests/modules/ajax_test/ajax_test.module
@@ -269,8 +269,14 @@ function _ajax_test_dialog($is_modal = FALSE) {
 
 /**
  * Returns example content for dialog tests.
+ *
+ * @param string $title
+ *   (optional) The title of the dialog result.
+ *
+ * @return array
+ *   A render array as expected by drupal_render().
  */
-function ajax_test_dialog_contents() {
+function ajax_test_dialog_contents($title = '') {
   // This is a regular render array; the keys do not have special meaning.
   $content = array(
     'content' => array(
@@ -288,6 +294,10 @@ function ajax_test_dialog_contents() {
     ),
   );
 
+  if ($title) {
+    $content['#title'] = $title;
+  }
+
   return $content;
 }
 
diff --git a/core/modules/system/tests/modules/ajax_test/lib/Drupal/ajax_test/AjaxTestController.php b/core/modules/system/tests/modules/ajax_test/lib/Drupal/ajax_test/AjaxTestController.php
index 53044c5..91d44a1 100644
--- a/core/modules/system/tests/modules/ajax_test/lib/Drupal/ajax_test/AjaxTestController.php
+++ b/core/modules/system/tests/modules/ajax_test/lib/Drupal/ajax_test/AjaxTestController.php
@@ -17,8 +17,7 @@ class AjaxTestController {
    */
   public function dialogContents() {
     // Re-use the utility method that returns the example content.
-    drupal_set_title(t('AJAX Dialog contents'));
-    return ajax_test_dialog_contents();
+    return ajax_test_dialog_contents(t('AJAX Dialog contents'));
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/HttpKernelTest.php b/core/tests/Drupal/Tests/Core/HttpKernelTest.php
deleted file mode 100644
index b51e108..0000000
--- a/core/tests/Drupal/Tests/Core/HttpKernelTest.php
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Tests\Core\HttpKernelTest.
- */
-
-namespace Drupal\Tests\Core;
-
-use Drupal\Core\Controller\ControllerResolver;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\HttpKernel;
-use Drupal\Tests\UnitTestCase;
-use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
-use Symfony\Component\DependencyInjection\Scope;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\KernelEvents;
-
-/**
- * Tests the custom http kernel of drupal.
- *
- * @see \Drupal\Core\HttpKernel
- */
-class HttpKernelTest extends UnitTestCase {
-
-  public static function getInfo() {
-    return array(
-      'name' => 'HttpKernel (Unit)',
-      'description' => 'Tests the HttpKernel.',
-      'group' => 'Routing',
-    );
-  }
-
-  /**
-   * Tests the forward method.
-   *
-   * @see \Drupal\Core\HttpKernel::setupSubrequest()
-   */
-  public function testSetupSubrequest() {
-    $container = new ContainerBuilder();
-
-    $request = new Request();
-    $container->addScope(new Scope('request'));
-    $container->enterScope('request');
-    $container->set('request', $request, 'request');
-
-    $dispatcher = new EventDispatcher();
-    $controller_resolver = new ControllerResolver($container);
-
-    $http_kernel = new HttpKernel($dispatcher, $container, $controller_resolver);
-
-    $test_controller = '\Drupal\Tests\Core\Controller\TestController';
-    $random_attribute = $this->randomName();
-    $subrequest = $http_kernel->setupSubrequest($test_controller, array('custom_attribute' => $random_attribute), array('custom_query' => $random_attribute));
-    $this->assertNotSame($subrequest, $request, 'The subrequest is not the same as the main request.');
-    $this->assertEquals($subrequest->attributes->get('custom_attribute'), $random_attribute, 'Attributes are set from the subrequest.');
-    $this->assertEquals($subrequest->query->get('custom_query'), $random_attribute, 'Query attributes are set from the subrequest.');
-    $this->assertEquals($subrequest->attributes->get('_controller'), $test_controller, 'Controller attribute got set.');
-
-    $subrequest = $http_kernel->setupSubrequest(NULL, array(), array());
-    $this->assertFalse($subrequest->attributes->has('_controller'), 'Ensure that _controller is not copied when no controller was set before.');
-  }
-
-}
