Change record status: 
Project: 
Introduced in branch: 
8.x
Description: 

Creating a page to render an entity type in a view mode can use the EntityViewController to route the request to that entity type's render controller (as nominated in the entity type's annotation).

Drupal 7

To render an entity on a page of its own in Drupal 7, you needed lots of boilerplate like so.

function mymodule_menu() {
  $items['my-entity-type/%my_entity_type'] = array(
    'page callback' => 'mymodule_entity_type_page_view',
    'access arguments' => array('access my entity type'),
  );
  return $items;
}

function mymodule_entity_type_page_view($entity) {
  drupal_set_title($entity->title);
  return my_entity_view_multiple(array($entity->id => $entity), 'full');
}

function my_entity_type_load($id) {
  return entity_load('my_entity_type', $id);
}

function my_entity_view_multiple($entities, $view_mode, $langcode = LANGUAGE_NONE) {
 field_attach_prepare_view('my_entity_type', $entities, $view_mode, $langcode);
  entity_prepare_view('entity_type', $entities, $langcode);
  $build = array();
  foreach ($entitiess as $entity) {
    $build['my_entity_type'][$entity->id] = my_entity_type_view($entity, $view_mode, $langcode);
    $build['my_entity_type'][$entity->id]['#weight'] = $weight;
    $weight++;
  }
  $build['my_entity_type']['#sorted'] = TRUE;
  return $build;
}

function my_entity_type_view($entity, $view_mode, $langcode = LANGUAGE_NONE) {
  // Populate $entity->content with a render() array.
  my_entity_build_content($entity, $view_mode, $langcode);

  $build = $entity->content;
  // We don't need duplicate rendering info in entity->content.
  unset($entity->content);

  $build += array(
    '#theme' => 'entity',
    '#my_entity_type' => $entity,
    '#view_mode' => $view_mode,
    '#language' => $langcode,
  );
}

function my_entity_type_build_content($entity, $view_mode, $langcode = LANGUAGE_NONE) {
  // Remove previously built content, if exists.
  $entity->content = array();

  // Allow modules to change the view mode.
  $context = array(
    'entity_type' => 'my_entity_type',
    'entity' => $entity,
    'langcode' => $langcode,
  );
  drupal_alter('entity_view_mode', $view_mode, $context);

  // Build fields content.
  // In case of a multiple view, my_entity_view_multiple() already ran the
  // 'prepare_view' step. An internal flag prevents the operation from running
  // twice.
  field_attach_prepare_view('my_entity_type', array($entity->id => $entity), $view_mode, $langcode);
  entity_prepare_view('my_entity_type', array($entity->nid => $entity), $langcode);
  $entity->content += field_attach_view('my_entity_type', $entity, $view_mode, $langcode);
}

Drupal 8

You can create a routing entry like so

module.my_entity_type_page:
  path: '/my_entity_type/{my_entity_id}'
  defaults:
    _entity_view: 'my_entity_type.full'
  requirements:
    _permission: 'view my_entity_type'

And the EntityViewBuilder handles the rest.

Browsing to /my_entity_type/1 will automatically load my entity type with id 1 and render it using the full view mode.
Extra logic that may have been in an existing page callback can be added in the render controller.

Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done