diff --git a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php
new file mode 100644
index 0000000..f33b9b0
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\EventSubscriber\RouteSubscriber.
+ */
+
+namespace Drupal\views\EventSubscriber;
+
+use Drupal\Core\Routing\RouteBuildEvent;
+use Drupal\Core\Routing\RoutingEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Defines the routes for a view.
+ */
+class RouteSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Implements \EventSubscriberInterface::getSubscribedEvents().
+   */
+  public static function getSubscribedEvents() {
+    $events[RoutingEvents::DYNAMIC] = 'dynamicRoutes';
+    return $events;
+  }
+
+  /**
+   * Adds routes defined by all views.
+   *
+   * @param \Drupal\Core\Routing\RouteBuildEvent $event
+   *   The route building event.
+   */
+  public function dynamicRoutes(RouteBuildEvent $event) {
+    $collection = $event->getRouteCollection();
+
+    $views = views_get_applicable_views('uses_hook_menu');
+    foreach ($views as $data) {
+      list($view, $display_id) = $data;
+      $view->collectRoutes($display_id, $collection);
+    }
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
index b0c6511..4ff8160 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\views\ViewExecutable;
 use \Drupal\views\Plugin\views\PluginBase;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * @defgroup views_display_plugins Views display plugins
@@ -2433,6 +2434,17 @@ public function renderEmpty() {
   }
 
   /**
+   * Adds the route entry of a view to the collection.#
+   *
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   A collection of routes that should be registered for this resource.
+   */
+  public function collectRoutes(RouteCollection $collection) {
+
+  }
+
+
+  /**
    * If this display creates a page with a menu item, implement it here.
    */
   public function hookMenu() { return array(); }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
index 8a0a85e..52ce835 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
@@ -9,6 +9,8 @@
 
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * The base display plugin for path/callbacks. This is used for pages and feeds.
@@ -33,6 +35,50 @@ protected function defineOptions() {
   }
 
   /**
+   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::collectRoutes().
+   */
+  public function collectRoutes(RouteCollection $collection) {
+    $view_id = $this->view->storage->id();
+    $display_id = $this->display['id'];
+
+    // @todo How do we apply argument validation?
+    $bits = explode('/', $this->getOption('path'));
+    // @todo Figure out validation/argument loading.
+    // Replace % with %views_arg for menu autoloading and add to the
+    // page arguments so the argument actually comes through.
+    $arg_counter = 0;
+    foreach ($bits as $pos => &$bit) {
+      if ($bit == '%') {
+        $bit = '{}';
+      }
+    }
+    $route_path = '/' . implode('/', $bits);
+
+    $route = new Route($route_path, array(
+      '_content' => 'Drupal\views\ViewRequestHandler::handle',
+      'view_id' => $view_id,
+      'display_id' => $display_id,
+    ));
+
+    // Add access check parameters to the route.
+    $access_plugin = $this->getPlugin('access');
+    if (!isset($access_plugin)) {
+      // @todo Do we want to support a default plugin in getPlugin itself?
+      $access_plugin = drupal_container()->get('plugin.manager.views.access')->createInstance('none');
+    }
+    $callback = $access_plugin->get_access_callback();
+    if (is_array($callback)) {
+      list($access_callback, $args) = $callback;
+      $route->addOptions(array(
+        '_access_callback' => $access_callback,
+        '_access_arguments' => $args,
+      ));
+    }
+
+    $collection->add("$view_id.$display_id", $route);
+  }
+
+  /**
    * Add this display's path information to Drupal's menu system.
    */
   public function executeHookMenu($callbacks) {
diff --git a/core/modules/views/lib/Drupal/views/ViewExecutable.php b/core/modules/views/lib/Drupal/views/ViewExecutable.php
index 7447488..6d64676 100644
--- a/core/modules/views/lib/Drupal/views/ViewExecutable.php
+++ b/core/modules/views/lib/Drupal/views/ViewExecutable.php
@@ -9,6 +9,7 @@
 
 use Symfony\Component\HttpFoundation\Response;
 use Drupal\views\Plugin\Core\Entity\View;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * @defgroup views_objects Objects that represent a View or part of a view
@@ -1458,6 +1459,30 @@ public function attachDisplays() {
   }
 
   /**
+   * Called to collect router entries from the view and the display_handler.
+   *
+   * @param string $display_id
+   *   A display id.
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   A menu callback array passed from views_menu_alter().
+   *
+   * @return bool
+   *   Returns FALSE if the display has not been found, TRUE otherwise.
+   */
+  public function collectRoutes($display_id = NULL, RouteCollection $collection = NULL) {
+
+    // This was probably already called, but it's good to be safe.
+    if (!$this->setDisplay($display_id)) {
+      return FALSE;
+    }
+
+    if (isset($this->display_handler)) {
+      $this->display_handler->collectRoutes($collection);
+      return TRUE;
+    }
+  }
+
+  /**
    * Called to get hook_menu() information from the view and the named display handler.
    *
    * @param $display_id
diff --git a/core/modules/views/lib/Drupal/views/ViewRequestHandler.php b/core/modules/views/lib/Drupal/views/ViewRequestHandler.php
new file mode 100644
index 0000000..a5874e4
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/ViewRequestHandler.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\ViewRequestHandler.
+ */
+
+namespace Drupal\views;
+
+use Drupal\Core\Ajax\AjaxResponse;
+use Symfony\Component\HttpFoundation\Request;
+
+class ViewRequestHandler {
+
+  /**
+   * Handles a response for a view.
+   *
+   * @param string $view_id
+   *   The ID of the view to execute.
+   * @param string $display_id
+   *   The ID of the display to execute.
+   */
+  public function handle($view_id, $display_id, Request $request) {
+    // @todo: Handle args!!
+    if ($view = views_get_view($view_id)) {
+      $func_args = func_get_args();
+      // Drop view and display ID.
+      array_shift($func_args);
+      array_shift($func_args);
+      $args = array_filter($func_args, function($item) {
+        return $item !== NULL;
+      });
+
+      return $view->executeDisplay($display_id, $args);
+    }
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php b/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php
new file mode 100644
index 0000000..15e5f43
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\ViewsAccessCheck.
+ */
+
+namespace Drupal\views;
+
+use Drupal\Core\Access\AccessCheckInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Defines a route access checker.
+ */
+class ViewsAccessCheck implements AccessCheckInterface {
+
+  /**
+   * Implements \Drupal\Core\Access\AccessCheckInterface::applies().
+   */
+  public function applies(Route $route) {
+    return $route->getDefault('view_id') && $route->getDefault('display_id');
+  }
+
+  /**
+   * Implements \Drupal\Core\Access\AccessCheckInterface::applies().
+   */
+  public function access(Route $route, Request $request) {
+    $access_callback = $route->getOption('access_callback');
+    $access_arguments = $route->getOption('access_arguments');
+
+    if (is_callable($access_callback)) {
+      return call_user_func($access_callback, $access_arguments);
+    }
+    // If there is no access check for the view, allow it.
+    return TRUE;
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/ViewsBundle.php b/core/modules/views/lib/Drupal/views/ViewsBundle.php
index 544b8c3..7f745eb 100644
--- a/core/modules/views/lib/Drupal/views/ViewsBundle.php
+++ b/core/modules/views/lib/Drupal/views/ViewsBundle.php
@@ -35,6 +35,13 @@ public function build(ContainerBuilder $container) {
     $container->register('views.views_data', 'Drupal\views\ViewsDataCache')
       ->addArgument(new Reference('cache.views_info'))
       ->addArgument(new Reference('config.factory'));
+
+    $container->register('views.route_subscriber', 'Drupal\views\EventSubscriber\RouteSubscriber')
+      ->addArgument(new Reference('config.factory'))
+      ->addTag('event_subscriber');
+
+    $container->register('views.route_access_check', 'Drupal\views\ViewsAccessCheck')
+      ->addTag('access_check');
   }
 
 }
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 8a85c97..fb45d42 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -331,6 +331,7 @@ function views_menu() {
  * Implement hook_menu_alter().
  */
 function views_menu_alter(&$callbacks) {
+  return;
   $our_paths = array();
   $views = views_get_applicable_views('uses_hook_menu');
   foreach ($views as $data) {
@@ -736,6 +737,8 @@ function views_invalidate_cache() {
 
   // Set the menu as needed to be rebuilt.
   state()->set('menu_rebuild_needed', TRUE);
+  // Set the router to be rebuild.
+  drupal_container()->get('router.builder')->rebuild();
 
   // Invalidate the block cache to update views block derivatives.
   if (module_exists('block')) {
