diff --git a/composer.json b/composer.json
index 779027662297c4ad00af653a9a8bb33331db812a..bcb67589840dfc99e96954f3b1e954597baefe4e 100644
--- a/composer.json
+++ b/composer.json
@@ -75,7 +75,7 @@
 		"friendsofphp/php-cs-fixer": "^2.12.2",
 		"phpspec/prophecy": "^1.7.5",
 		"typo3/cms-styleguide": "~10.0.2",
-		"typo3/testing-framework": "~5.0.10"
+		"typo3/testing-framework": "~5.0.11"
 	},
 	"suggest": {
 		"ext-gd": "GDlib/Freetype is required for building images with text (GIFBUILDER) and can also be used to scale images",
diff --git a/composer.lock b/composer.lock
index 151f8925669a058512ea851f45cedf3fb312686d..cec5b8a2733e22c95c3e0b75f0b15b7ba24f9015 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "a46e7f1e82efeff6223502b47a7cf998",
+    "content-hash": "112098a7382ac5f79a2b4dfe5fa616a9",
     "packages": [
         {
             "name": "cogpowered/finediff",
@@ -6316,16 +6316,16 @@
         },
         {
             "name": "typo3/testing-framework",
-            "version": "5.0.10",
+            "version": "5.0.11",
             "source": {
                 "type": "git",
                 "url": "https://github.com/TYPO3/testing-framework.git",
-                "reference": "63a0f97ee27607b93301dc6b322927fbe98185c5"
+                "reference": "ac55b0e2d6e2d4369ece187cc31b58457d5b7122"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/TYPO3/testing-framework/zipball/63a0f97ee27607b93301dc6b322927fbe98185c5",
-                "reference": "63a0f97ee27607b93301dc6b322927fbe98185c5",
+                "url": "https://api.github.com/repos/TYPO3/testing-framework/zipball/ac55b0e2d6e2d4369ece187cc31b58457d5b7122",
+                "reference": "ac55b0e2d6e2d4369ece187cc31b58457d5b7122",
                 "shasum": ""
             },
             "require": {
@@ -6372,7 +6372,7 @@
                 "tests",
                 "typo3"
             ],
-            "time": "2019-06-18T07:52:50+00:00"
+            "time": "2019-07-13T12:16:05+00:00"
         }
     ],
     "aliases": [],
diff --git a/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php b/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php
index 0b08aa5ad172c740399f03521c79f0c56bc8f05a..4ca5dcd3cc25802a02d3e62b8dcbd761c11aeb50 100644
--- a/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php
+++ b/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php
@@ -14,10 +14,10 @@ return [
             'target' => \TYPO3\CMS\Adminpanel\Middleware\AdminPanelInitiator::class,
             'before' => [
                 'typo3/cms-frontend/prepare-tsfe-rendering',
-                'typo3/cms-frontend/page-resolver'
+                'typo3/cms-frontend/tsfe',
+                'typo3/cms-frontend/page-resolver',
             ],
             'after' => [
-                'typo3/cms-frontend/tsfe',
                 'typo3/cms-frontend/authentication',
                 'typo3/cms-frontend/backend-user-authentication',
             ]
@@ -29,7 +29,7 @@ return [
                 'typo3/cms-frontend/backend-user-authentication',
             ],
             'before' => [
-                'typo3/cms-frontend/site'
+                'typo3/cms-frontend/tsfe'
             ]
         ],
         'typo3/cms-adminpanel/data-persister' => [
diff --git a/typo3/sysext/core/Classes/Http/Uri.php b/typo3/sysext/core/Classes/Http/Uri.php
index 7f624e2c1f8cfbcf0682a5a6f735b929105f29b5..d7c31b213b0cf56db97c79aaad53f95121872c59 100644
--- a/typo3/sysext/core/Classes/Http/Uri.php
+++ b/typo3/sysext/core/Classes/Http/Uri.php
@@ -120,7 +120,7 @@ class Uri implements UriInterface
         $uriParts = parse_url($uri);
 
         if ($uriParts === false) {
-            throw new \InvalidArgumentException('The parsedUri string appears to be malformed', 1436717322);
+            throw new \InvalidArgumentException('The parsedUri "' . $uri . '" appears to be malformed', 1436717322);
         }
 
         if (isset($uriParts['scheme'])) {
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-88540-ChangedRequestWorkflowForFrontendRequests.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-88540-ChangedRequestWorkflowForFrontendRequests.rst
index d655d45811408efc5163d5a07d0785e75e325f40..94abba36d190a2b86e2847c70df84bd94919155a 100644
--- a/typo3/sysext/core/Documentation/Changelog/master/Breaking-88540-ChangedRequestWorkflowForFrontendRequests.rst
+++ b/typo3/sysext/core/Documentation/Changelog/master/Breaking-88540-ChangedRequestWorkflowForFrontendRequests.rst
@@ -10,10 +10,11 @@ Description
 ===========
 
 The "Frontend Request Workflow" is the PHP code responsible for
-setting up various functionality. This includes Login/Permission Check, resolving
+setting up various functionality when the TYPO3 Frontend (= rendering of the website)
+is booted and the content is built. This includes Login/Permission Check, resolving
 the current site + language, and checking the page + rootline, then
 parsing TypoScript, which will then lead to building content (or taken from
-cache), until the actual output.
+cache), until the actual output is returned.
 
 Since TYPO3 v9, this is all built via PSR-15 middlewares, the PSR-15 Request Handler,
 and the global TypoScriptFrontendController (TSFE).
@@ -24,11 +25,51 @@ other / extended functionality.
 
 The following changes have been made:
 
-- Storing session data from a Frontend User Session / Anonymous session is now
-triggered within the Frontend User ("frontend-user-authenticator") Middleware,
-at a later point. Before this was part of the RequestHandler logic after content
-was put together. This was due to legacy reasons of the previous hook execution order.
-
+- Storing session data from a Frontend User Session / Anonymous session is now triggered within the Frontend User
+("frontend-user-authenticator") Middleware, at a later point - once the page was generated. Up until TYPO3 v9, this
+was part of the RequestHandler logic right after content was put together. This was due to legacy reasons of the
+previous hook execution order.
+
+- Resolving the actual site - that is the site configuration plus the language - now happens before Frontend
+and Backend User Authentication. This is important to understand to be able to define further settings within
+Site Handling configuration in the future. Site and Site Language Resolving is now 100% independent of any permission
+settings. Evaluating if a language is active is evaluated separately.
+
+- Backend User Authentication ("$BE_USER") is now started before Frontend User Authentication ("fe_user"), previously
+this was the other way around. Frontend Users are now stored in the request object via the "frontend.user" attribute,
+instead of `$TSFE->fe_user`, until `$TSFE` is instantiated.
+
+- Once all site + permission/authentication functionality has been set up, Routing now tries to detect
+the target page ID and the URL parameters ("PageResolver" middleware) and evaluates the result, so-called
+"Page Arguments" directly afterwards ("PageArgumentValidator" middleware). This effectively validates the cHash
+logic.
+
+- All of the mentioned parts above do not depend on TSFE anymore. In fact, they are 100% independent of
+any TSFE-related code. TSFE is instantiated after all site resolving, authentication, page resolving and argument
+validation is done.
+
+The new request workflow looks like this (simplified):
+
+1. Evaluation of Normalized Parameters (a.k.a. getIndpEnv) & Evaluation of "Maintenance Mode" functionality
+2. Handling registered eID scripts depending on GET parameter `eID`
+3. Resolving Site configuration and Language from URL if possible
+4. Resolving logged-in Backend User Authentication for previewing hidden pages or languages
+5. Authentication of Website Users ("Frontend Users")
+6. Executing various static routes and redirct functionality
+7. Resolving Target Page ID and URL parameters based on Routing, Validation of Page Arguments based on "cHash"
+8. Setting up global $TSFE object, injecting previously resolved settings into TSFE.
+9. Resolving the Rootline for the page
+10. Parsing and Evaluation of TypoScript Instructions to render the page content
+11. Build the content (cached / uncached)
+12. Return the Response (PSR-7) to the base application and output headers + content.
+
+In addition, TypoScriptFrontendController now expects the following constructor arguments:
+
+1. Context API object (previously a copy of $TYPO3_CONF_VARS, until TYPO3 v8, then, unused)
+2. SiteInterface object (previously the Page ID)
+3. SiteLanguage object (previously the Page Type)
+4. PageArguments object (previously the no_cache GET parameter)
+5. FrontendUserAuthentication object (previously the cHash parameter)
 
 Impact
 ======
@@ -50,11 +91,18 @@ Any hooks from third party extensions that run
 
 and depend on the frontend session data being written.
 
+Any TYPO3 extensions using middlewares in the frontend.
 
 Migration
 =========
 
-Consider using a PSR-15 middleware instead of using a hook, or explicitly
-call "storeSessionData" within the PHP hook if necessary.
+Consider using a PSR-15 middleware instead of using a hook, or explicitly call "storeSessionData" within
+the PHP hook if necessary.
+
+If an existing middleware was used, ensure that it's loaded in TYPO3 v10 at the proper location, as the
+`typo3-cms/frontend/tsfe` middleware is loaded at a very late point.
+
+Ensure to use proper objects for the constructor arguments on `TypoScriptFrontendController` when instantiating
+the object on your own.
 
 .. index:: Frontend, PHP-API, NotScanned
diff --git a/typo3/sysext/core/composer.json b/typo3/sysext/core/composer.json
index b38736a5a5ca6ef76312567138d54120c4860d59..e34079e3af7a3d3faca1d7b728ec65b4fcb70e4f 100644
--- a/typo3/sysext/core/composer.json
+++ b/typo3/sysext/core/composer.json
@@ -54,7 +54,7 @@
 		"friendsofphp/php-cs-fixer": "^2.12.2",
 		"phpspec/prophecy": "^1.7.5",
 		"typo3/cms-styleguide": "~10.0.2",
-		"typo3/testing-framework": "~5.0.10"
+		"typo3/testing-framework": "~5.0.11"
 	},
 	"suggest": {
 		"ext-fileinfo": "Used for proper file type detection in the file abstraction layer",
diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php
index b7e0f625595e1da1b9300743eb5587b0e1170f70..eae14dc02e5ac35879895cd7b429839667e0f1a6 100644
--- a/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php
+++ b/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Fluid\ViewHelpers;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
@@ -184,7 +185,7 @@ class CObjectViewHelper extends AbstractViewHelper
     {
         return GeneralUtility::makeInstance(
             ContentObjectRenderer::class,
-            $GLOBALS['TSFE'] ?? GeneralUtility::makeInstance(TypoScriptFrontendController::class, null, 0, 0)
+            $GLOBALS['TSFE'] ?? GeneralUtility::makeInstance(TypoScriptFrontendController::class, GeneralUtility::makeInstance(Context::class))
         );
     }
 
diff --git a/typo3/sysext/fluid/Tests/Functional/ViewHelpers/TypolinkViewHelperTest.php b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/TypolinkViewHelperTest.php
index 482ae66dc1e2a76c5fc4ea376b2e4bc0bfcb40b5..981094bf772882dad82528f3b96f5e7db178b9a2 100644
--- a/typo3/sysext/fluid/Tests/Functional/ViewHelpers/TypolinkViewHelperTest.php
+++ b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/TypolinkViewHelperTest.php
@@ -16,9 +16,11 @@ namespace TYPO3\CMS\Fluid\Tests\Functional\ViewHelpers;
  */
 
 use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
 
-class TypolinkViewHelperTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
+class TypolinkViewHelperTest extends FunctionalTestCase
 {
     use SiteBasedTestTrait;
 
@@ -64,6 +66,9 @@ class TypolinkViewHelperTest extends \TYPO3\TestingFramework\Core\Functional\Fun
             'foo' => 'bar',
             'temp' => 'test',
         ];
+        $_SERVER['HTTP_HOST'] = 'example.com';
+        $_SERVER['REQUEST_URI'] = '/en/';
+        GeneralUtility::flushInternalRuntimeCaches();
     }
 
     /**
diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
index e94987739a6b37014a5a085560e4f8094d2d766c..c264045f72d23a5192ea8d3f8607c805d974da07 100644
--- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
+++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
@@ -40,6 +40,7 @@ use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
 use TYPO3\CMS\Core\Error\Http\ShortcutTargetPageNotFoundException;
 use TYPO3\CMS\Core\Exception\Page\RootLineException;
 use TYPO3\CMS\Core\Http\ImmediateResponseException;
+use TYPO3\CMS\Core\Http\ServerRequestFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Localization\Locales;
 use TYPO3\CMS\Core\Locking\Exception\LockAcquireWouldBlockException;
@@ -50,6 +51,7 @@ use TYPO3\CMS\Core\PageTitle\PageTitleProviderManager;
 use TYPO3\CMS\Core\Resource\StorageRepository;
 use TYPO3\CMS\Core\Routing\PageArguments;
 use TYPO3\CMS\Core\Site\Entity\Site;
+use TYPO3\CMS\Core\Site\Entity\SiteInterface;
 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
@@ -105,6 +107,16 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      */
     public $type = '';
 
+    /**
+     * @var Site
+     */
+    protected $site;
+
+    /**
+     * @var SiteLanguage
+     */
+    protected $language;
+
     /**
      * The submitted cHash
      * @var string
@@ -653,26 +665,77 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      * The processing of these variables goes on later in this class.
      * Also sets a unique string (->uniqueString) for this script instance; A md5 hash of the microtime()
      *
-     * @param array $_ unused, previously defined to set TYPO3_CONF_VARS
-     * @param mixed $id The value of GeneralUtility::_GP('id')
-     * @param int $type The value of GeneralUtility::_GP('type')
-     * @param bool|string $_1 unused, previously the value of GeneralUtility::_GP('no_cache')
-     * @param string $cHash The value of GeneralUtility::_GP('cHash')
-     * @param string $_2 previously was used to define the jumpURL
-     * @param string $MP The value of GeneralUtility::_GP('MP')
-     */
-    public function __construct($_ = null, $id, $type, $_1 = null, $cHash = '', $_2 = null, $MP = '')
-    {
-        // Setting some variables:
-        $this->id = $id;
-        $this->type = $type;
-        $this->cHash = $cHash;
-        $this->MP = $GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'] ? (string)$MP : '';
+     * @param Context|array $context the Context object to work on, previously defined to set TYPO3_CONF_VARS
+     * @param mixed|SiteInterface $siteOrId The resolved site to work on, previously this was the value of GeneralUtility::_GP('id')
+     * @param int|SiteLanguage $siteLanguageOrType The resolved language to work on, previously the value of GeneralUtility::_GP('type')
+     * @param bool|string|PageArguments $pageArguments The PageArguments object containing ID, type and GET parameters, previously unused or the value of GeneralUtility::_GP('no_cache')
+     * @param string|FrontendUserAuthentication $cHashOrFrontendUser FrontendUserAuthentication object, previously the value of GeneralUtility::_GP('cHash'), use the PageArguments object instead, will be removed in TYPO3 v11.0
+     * @param string $_2 previously was used to define the jumpURL, use the PageArguments object instead, will be removed in TYPO3 v11.0
+     * @param string $MP The value of GeneralUtility::_GP('MP'), use the PageArguments object instead, will be removed in TYPO3 v11.0
+     */
+    public function __construct($context = null, $siteOrId = null, $siteLanguageOrType = null, $pageArguments = null, $cHashOrFrontendUser = null, $_2 = null, $MP = null)
+    {
+        if ($context instanceof Context) {
+            $this->context = $context;
+        } else {
+            // Use the global context for now
+            trigger_error('TypoScriptFrontendController requires a context object as first constructor argument in TYPO3 v11.0, now falling back to the global Context. This fallback layer will be removed in TYPO3 v11.0', E_USER_DEPRECATED);
+            $this->context = GeneralUtility::makeInstance(Context::class);
+        }
+        $request = $GLOBALS['TYPO3_REQUEST'] ?? ServerRequestFactory::fromGlobals();
+        if ($siteOrId instanceof SiteInterface) {
+            $this->site = $siteOrId;
+        } else {
+            trigger_error('TypoScriptFrontendController should evaluate the parameter "id" by the PageArguments object, not by a separate constructor argument. This functionality will be removed in TYPO3 v11.0', E_USER_DEPRECATED);
+            $this->id = $siteOrId;
+            if ($request->getAttribute('site') instanceof SiteInterface) {
+                $this->site = $request->getAttribute('site');
+            } else {
+                throw new \InvalidArgumentException('TypoScriptFrontendController must be constructed with a valid Site object or a resolved site in the current request as fallback. None given.', 1561583122);
+            }
+        }
+        if ($siteLanguageOrType instanceof SiteLanguage) {
+            $this->language = $siteLanguageOrType;
+        } else {
+            $this->type = $siteLanguageOrType;
+            if ($request->getAttribute('language') instanceof SiteLanguage) {
+                $this->language = $request->getAttribute('language');
+            } else {
+                throw new \InvalidArgumentException('TypoScriptFrontendController must be constructed with a valid SiteLanguage object or a resolved site in the current request as fallback. None given.', 1561583127);
+            }
+        }
+
+        if (!$pageArguments instanceof PageArguments) {
+            $pageArguments = $request->getAttribute('routing');
+            if (!$pageArguments instanceof PageArguments) {
+                trigger_error('TypoScriptFrontendController must be constructed with a valid PageArguments object or a resolved page argument in the current request as fallback. None given.', E_USER_DEPRECATED);
+                $queryParams = $request->getQueryParams();
+                $pageId = $queryParams['id'] ?? $request->getParsedBody()['id'] ?? 0;
+                $pageType = $queryParams['type'] ?? $request->getParsedBody()['type'] ?? 0;
+                $pageArguments = new PageArguments((int)$pageId, (string)$pageType, [], $queryParams);
+            }
+        }
+        $this->setPageArguments($pageArguments);
+
+        if ($cHashOrFrontendUser !== null) {
+            if ($cHashOrFrontendUser instanceof FrontendUserAuthentication) {
+                $this->fe_user = $cHashOrFrontendUser;
+            } else {
+                trigger_error('TypoScriptFrontendController should evaluate the parameter "cHash" by the PageArguments object, not by a separate constructor argument. This functionality will be removed in TYPO3 v11.0', E_USER_DEPRECATED);
+                $this->cHash = $cHashOrFrontendUser;
+            }
+        }
+        if ($MP !== null) {
+            trigger_error('TypoScriptFrontendController should evaluate the MountPoint Parameter "MP" by the PageArguments object, not by a separate constructor argument. This functionality will be removed in TYPO3 v11.0', E_USER_DEPRECATED);
+            if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
+                $this->MP = (string)$MP;
+            }
+        }
+
+        $this->domainStartPage = $this->site->getRootPageId();
         $this->uniqueString = md5(microtime());
         $this->initPageRenderer();
         $this->initCaches();
-        // Use the global context for now
-        $this->context = GeneralUtility::makeInstance(Context::class);
     }
 
     /**
@@ -916,11 +979,11 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             ->setMaxResults(1);
 
         // $this->id always points to the ID of the default language page, so we check
-        // currentSiteLanguage to determine if we need to fetch a translation
-        if ($this->getCurrentSiteLanguage() instanceof SiteLanguage && $this->getCurrentSiteLanguage()->getLanguageId() > 0) {
+        // the current site language to determine if we need to fetch a translation
+        if ($this->language->getLanguageId() > 0) {
             $queryBuilder->andWhere(
                 $queryBuilder->expr()->eq('l10n_parent', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)),
-                $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter($this->getCurrentSiteLanguage()->getLanguageId(), \PDO::PARAM_INT))
+                $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter($this->language->getLanguageId(), \PDO::PARAM_INT))
             );
         } else {
             $queryBuilder->andWhere(
@@ -1563,11 +1626,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         $this->getTimeTracker()->setTSlogMessage('TSFE->reqCHash(): No &cHash parameter was sent for GET vars though required so caching is disabled', 2);
     }
 
-    /**
-     * @param PageArguments $pageArguments
-     * @internal
-     */
-    public function setPageArguments(PageArguments $pageArguments)
+    protected function setPageArguments(PageArguments $pageArguments): void
     {
         $this->pageArguments = $pageArguments;
         $queryParams = $pageArguments->getDynamicArguments();
@@ -1580,6 +1639,12 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         } else {
             $this->cHash_array = [];
         }
+        $this->id = $pageArguments->getPageId();
+        $this->type = $pageArguments->getPageType() ?: 0;
+        $this->cHash = $pageArguments->getArguments()['cHash'] ?? '';
+        if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
+            $this->MP = (string)($pageArguments->getArguments()['MP'] ?? '');
+        }
     }
 
     /**
@@ -1779,7 +1844,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
     {
         // Ensure the language base is used for the hash base calculation as well, otherwise TypoScript and page-related rendering
         // is not cached properly as we don't have any language-specific conditions anymore
-        $siteBase = (string)$this->getCurrentSiteLanguage()->getBase();
+        $siteBase = (string)$this->language->getBase();
 
         // Fetch the list of user groups
         /** @var UserAspect $userAspect */
@@ -1947,14 +2012,8 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             GeneralUtility::callUserFunction($_funcRef, $_params, $this);
         }
 
-        $siteLanguage = $this->getCurrentSiteLanguage();
-        if (!$siteLanguage) {
-            throw new PageNotFoundException('Frontend cannot be displayed, as there is no language available', 1557924417);
-        }
-
         // Initialize charset settings etc.
-        $languageKey = $siteLanguage->getTypo3Language();
-        $this->setOutputLanguage($languageKey);
+        $this->setOutputLanguage($this->language->getTypo3Language());
 
         // Rendering charset of HTML page.
         if (isset($this->config['config']['metaCharset']) && $this->config['config']['metaCharset'] !== 'utf-8') {
@@ -1962,7 +2021,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         }
 
         // Get values from site language
-        $languageAspect = LanguageAspectFactory::createFromSiteLanguage($siteLanguage);
+        $languageAspect = LanguageAspectFactory::createFromSiteLanguage($this->language);
 
         $languageId = $languageAspect->getId();
         $languageContentId = $languageAspect->getContentId();
@@ -2070,10 +2129,8 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             $this->updateRootLinesWithTranslations();
         }
 
-        // Finding the ISO code for the currently selected language
-        // fetched by the sys_language record when not fetching content from the default language
         // @deprecated - can be removed in TYPO3 v11.0
-        $this->sys_language_isocode = $siteLanguage->getTwoLetterIsoCode();
+        $this->sys_language_isocode = $this->language->getTwoLetterIsoCode();
 
         $_params = [];
         foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_postProcess'] ?? [] as $_funcRef) {
@@ -2101,9 +2158,8 @@ class TypoScriptFrontendController implements LoggerAwareInterface
     public function settingLocale()
     {
         trigger_error('TSFE->settingLocale() will be removed in TYPO3 v11.0. Use Locales::setSystemLocaleFromSiteLanguage() instead, as this functionality is independent of TSFE.', E_USER_DEPRECATED);
-        $siteLanguage = $this->getCurrentSiteLanguage();
-        if ($siteLanguage->getLocale() && !Locales::setSystemLocaleFromSiteLanguage($siteLanguage)) {
-            $this->getTimeTracker()->setTSlogMessage('Locale "' . htmlspecialchars($siteLanguage->getLocale()) . '" not found.', 3);
+        if ($this->language->getLocale() && !Locales::setSystemLocaleFromSiteLanguage($this->language)) {
+            $this->getTimeTracker()->setTSlogMessage('Locale "' . htmlspecialchars($this->language->getLocale()) . '" not found.', 3);
         }
     }
 
@@ -2937,7 +2993,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             $response = $response->withHeader('Content-Type', $this->contentType . '; charset=' . trim($this->metaCharset));
         }
         // Set header for content language unless disabled
-        $contentLanguage = $this->getCurrentSiteLanguage() instanceof SiteLanguage ? $this->getCurrentSiteLanguage()->getTwoLetterIsoCode() : '';
+        $contentLanguage = $this->language->getTwoLetterIsoCode();
         if (empty($this->config['config']['disableLanguageHeader']) && !empty($contentLanguage)) {
             $response = $response->withHeader('Content-Language', trim($contentLanguage));
         }
@@ -3702,21 +3758,6 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         return GeneralUtility::makeInstance(TimeTracker::class);
     }
 
-    /**
-     * Returns the currently configured "site language" if a site is configured (= resolved) in the current request.
-     *
-     * @internal
-     */
-    protected function getCurrentSiteLanguage(): ?SiteLanguage
-    {
-        if (isset($GLOBALS['TYPO3_REQUEST'])
-            && $GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface
-            && $GLOBALS['TYPO3_REQUEST']->getAttribute('language') instanceof SiteLanguage) {
-            return $GLOBALS['TYPO3_REQUEST']->getAttribute('language');
-        }
-        return null;
-    }
-
     /**
      * Return the global instance of this class.
      *
@@ -3742,4 +3783,24 @@ class TypoScriptFrontendController implements LoggerAwareInterface
 
         throw new \LogicException('TypoScriptFrontendController was tried to be injected before initial creation', 1538370377);
     }
+
+    public function getLanguage(): SiteLanguage
+    {
+        return $this->language;
+    }
+
+    public function getSite(): Site
+    {
+        return $this->site;
+    }
+
+    public function getContext(): Context
+    {
+        return $this->context;
+    }
+
+    public function getPageArguments(): PageArguments
+    {
+        return $this->pageArguments;
+    }
 }
diff --git a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
index cebd55804c8c654520e2551e8c657187b33c1258..b9b1fdf2082d4c9f7bf7ee922b68a56482d0aa9d 100644
--- a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
@@ -36,15 +36,11 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * a different middleware later-on might unset the BE_USER as he/she is not allowed to preview a certain
  * page due to rights management. As this can only happen once the page ID is resolved, this will happen
  * after the routing middleware.
- *
- * Currently, this middleware depends on the availability of $GLOBALS['TSFE'], however, this is solely
- * due to backwards-compatibility and will be disabled in the future.
  */
 class BackendUserAuthenticator implements MiddlewareInterface
 {
     /**
-     * Creates a frontend user authentication object, tries to authenticate a user
-     * and stores the object in $GLOBALS['TSFE']->fe_user.
+     * Creates a backend user authentication object, tries to authenticate a user
      *
      * @param ServerRequestInterface $request
      * @param RequestHandlerInterface $handler
diff --git a/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php b/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php
index a8e332c5b1cbd1286d651edf59a9ae695a3d002c..09a7ee440b3037057365c95e002dc5144beb477f 100644
--- a/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php
@@ -27,13 +27,12 @@ use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
 
 /**
  * This middleware authenticates a Frontend User (fe_users).
- * A valid $GLOBALS['TSFE'] object is needed for the time being, being fully backwards-compatible.
  */
 class FrontendUserAuthenticator implements MiddlewareInterface
 {
     /**
-     * Creates a frontend user authentication object, tries to authenticate a user
-     * and stores the object in $GLOBALS['TSFE']->fe_user.
+     * Creates a frontend user authentication object, tries to authenticate a user and stores
+     * it in the current request as attribute.
      *
      * @param ServerRequestInterface $request
      * @param RequestHandlerInterface $handler
@@ -59,11 +58,9 @@ class FrontendUserAuthenticator implements MiddlewareInterface
         $frontendUser->start();
         $frontendUser->unpack_uc();
 
-        // Keep the backwards-compatibility for TYPO3 v9, to have the fe_user within the global TSFE object
-        $GLOBALS['TSFE']->fe_user = $frontendUser;
-
-        // Register the frontend user as aspect
+        // Register the frontend user as aspect and within the session
         $this->setFrontendUserAspect(GeneralUtility::makeInstance(Context::class), $frontendUser);
+        $request = $request->withAttribute('frontend.user', $frontendUser);
 
         $response = $handler->handle($request);
 
diff --git a/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php b/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php
index 7d6ff74ac03211777cb69c02e19cde20dd895e1a..6bf951d4e886045f124bb274309e58626df02ed9 100644
--- a/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php
@@ -47,16 +47,12 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
     protected $cacheHashCalculator;
 
     /**
-     * @var TypoScriptFrontendController
+     * @var bool will be used to set $TSFE->no_cache later-on
      */
-    protected $controller;
+    protected $disableCache = false;
 
-    /**
-     * @param TypoScriptFrontendController|null $controller
-     */
-    public function __construct(TypoScriptFrontendController $controller = null)
+    public function __construct()
     {
-        $this->controller = $controller ?? $GLOBALS['TSFE'];
         $this->cacheHashCalculator = GeneralUtility::makeInstance(CacheHashCalculator::class);
     }
 
@@ -69,6 +65,7 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
      */
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
+        $this->disableCache = (bool)$request->getAttribute('noCache', false);
         $pageNotFoundOnValidationError = (bool)($GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFoundOnCHashError'] ?? true);
         /** @var PageArguments $pageArguments */
         $pageArguments = $request->getAttribute('routing', null);
@@ -81,7 +78,12 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
                 ['code' => PageAccessFailureReasons::INVALID_PAGE_ARGUMENTS]
             );
         }
-        if ($this->controller->no_cache && !$pageNotFoundOnValidationError) {
+        if ($GLOBALS['TYPO3_CONF_VARS']['FE']['disableNoCacheParameter'] ?? true) {
+            $cachingDisabledByRequest = false;
+        } else {
+            $cachingDisabledByRequest = $pageArguments->getArguments()['no_cache'] ?? $request->getParsedBody()['no_cache'] ?? false;
+        }
+        if (($cachingDisabledByRequest || $this->disableCache) && !$pageNotFoundOnValidationError) {
             // No need to test anything if caching was already disabled.
             return $handler->handle($request);
         }
@@ -116,6 +118,8 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
                 );
             }
         }
+
+        $request = $request->withAttribute('noCache', $this->disableCache);
         return $handler->handle($request);
     }
 
@@ -153,7 +157,7 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
             return false;
         }
         // Caching is disabled now (but no 404)
-        $this->controller->no_cache = true;
+        $this->disableCache = true;
         $this->getTimeTracker()->setTSlogMessage('The incoming cHash "' . $cHash . '" and calculated cHash "' . $calculatedCacheHash . '" did not match, so caching was disabled. The fieldlist used was "' . implode(',', array_keys($relevantParameters)) . '"', 2);
         return true;
     }
@@ -177,7 +181,7 @@ class PageArgumentValidator implements MiddlewareInterface, LoggerAwareInterface
             return false;
         }
         // Caching is disabled now (but no 404)
-        $this->controller->no_cache = true;
+        $this->disableCache = true;
         $this->getTimeTracker()->setTSlogMessage('TSFE->reqCHash(): No &cHash parameter was sent for GET vars though required so caching is disabled', 2);
         return true;
     }
diff --git a/typo3/sysext/frontend/Classes/Middleware/PageResolver.php b/typo3/sysext/frontend/Classes/Middleware/PageResolver.php
index 6315a9a1fb9d73dd57f6aa9027d3f38579844e32..42d9136990df5e2d3f282dfa6135935f99415500 100644
--- a/typo3/sysext/frontend/Classes/Middleware/PageResolver.php
+++ b/typo3/sysext/frontend/Classes/Middleware/PageResolver.php
@@ -19,18 +19,12 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
-use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
-use TYPO3\CMS\Core\Context\Context;
-use TYPO3\CMS\Core\Context\UserAspect;
-use TYPO3\CMS\Core\Context\WorkspaceAspect;
 use TYPO3\CMS\Core\Routing\PageArguments;
 use TYPO3\CMS\Core\Routing\RouteNotFoundException;
 use TYPO3\CMS\Core\Routing\SiteRouteResult;
 use TYPO3\CMS\Core\Site\Entity\Site;
-use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\Controller\ErrorController;
-use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
 
 /**
@@ -44,16 +38,6 @@ use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
  */
 class PageResolver implements MiddlewareInterface
 {
-    /**
-     * @var TypoScriptFrontendController
-     */
-    protected $controller;
-
-    public function __construct(TypoScriptFrontendController $controller = null)
-    {
-        $this->controller = $controller ?? $GLOBALS['TSFE'];
-    }
-
     /**
      * Resolve the page ID
      *
@@ -73,9 +57,6 @@ class PageResolver implements MiddlewareInterface
             );
         }
 
-        // First, resolve the root page of the site, the Page ID of the current domain
-        $this->controller->domainStartPage = $site->getRootPageId();
-
         /** @var SiteRouteResult $previousResult */
         $previousResult = $request->getAttribute('routing', null);
         if (!$previousResult) {
@@ -90,6 +71,7 @@ class PageResolver implements MiddlewareInterface
         try {
             /** @var PageArguments $pageArguments */
             $pageArguments = $site->getRouter()->matchRequest($request, $previousResult);
+            $request = $request->withAttribute('routing', $pageArguments);
         } catch (RouteNotFoundException $e) {
             return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
                 $request,
@@ -106,9 +88,6 @@ class PageResolver implements MiddlewareInterface
             );
         }
 
-        $this->controller->id = $pageArguments->getPageId();
-        $this->controller->type = $pageArguments->getPageType() ?? $this->controller->type;
-        $request = $request->withAttribute('routing', $pageArguments);
         // stop in case arguments are dirty (=defined twice in route and GET query parameters)
         if ($pageArguments->areDirty()) {
             return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
@@ -121,33 +100,7 @@ class PageResolver implements MiddlewareInterface
         // merge the PageArguments with the request query parameters
         $queryParams = array_replace_recursive($request->getQueryParams(), $pageArguments->getArguments());
         $request = $request->withQueryParams($queryParams);
-        $this->controller->setPageArguments($pageArguments);
-
-        // as long as TSFE throws errors with the global object, this needs to be set,
-        // but should be removed later-on
-        $GLOBALS['TYPO3_REQUEST'] = $request;
-        $this->controller->determineId();
-
-        // No access? Then remove user and re-evaluate the page id
-        if ($this->controller->isBackendUserLoggedIn() && !$GLOBALS['BE_USER']->doesUserHaveAccess($this->controller->page, Permission::PAGE_SHOW)) {
-            unset($GLOBALS['BE_USER']);
-            // Register an empty backend user as aspect
-            $this->setBackendUserAspect(GeneralUtility::makeInstance(Context::class), null);
-            $this->controller->determineId();
-        }
 
         return $handler->handle($request);
     }
-
-    /**
-     * Register the backend user as aspect
-     *
-     * @param Context $context
-     * @param BackendUserAuthentication $user
-     */
-    protected function setBackendUserAspect(Context $context, BackendUserAuthentication $user = null)
-    {
-        $context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
-        $context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user ? $user->workspace : 0));
-    }
 }
diff --git a/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php b/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php
index e0f903950f9907982b2de10947809d5492503ff8..915efa5a2a43bb6ab72e7d63728e484b8d2aa8c1 100644
--- a/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php
+++ b/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php
@@ -19,7 +19,7 @@ namespace TYPO3\CMS\Frontend\Middleware;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
-use Psr\Http\Server\RequestHandlerInterface as PsrRequestHandlerInterface;
+use Psr\Http\Server\RequestHandlerInterface;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
@@ -29,7 +29,7 @@ use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
  *
  * Do all necessary preparation steps for rendering
  *
- * @internal this middleware might get removed in TYPO3 v10.0.
+ * @internal this middleware might get removed in TYPO3 v10.x.
  */
 class PrepareTypoScriptFrontendRendering implements MiddlewareInterface
 {
@@ -53,10 +53,10 @@ class PrepareTypoScriptFrontendRendering implements MiddlewareInterface
      * Initialize TypoScriptFrontendController to the point right before rendering of the page is triggered
      *
      * @param ServerRequestInterface $request
-     * @param PsrRequestHandlerInterface $handler
+     * @param RequestHandlerInterface $handler
      * @return ResponseInterface
      */
-    public function process(ServerRequestInterface $request, PsrRequestHandlerInterface $handler): ResponseInterface
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
         // as long as TSFE throws errors with the global object, this needs to be set, but
         // should be removed later-on once TypoScript Condition Matcher is built with the current request object.
diff --git a/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php b/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php
index 184acf5f4480acb54c752999e6b44e1054308c19..1e9b2775fac7be7651d1e1b8490b991948c38602 100644
--- a/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php
+++ b/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php
@@ -28,7 +28,7 @@ use TYPO3\CMS\Frontend\Page\PageRepository;
  * Checks mount points, shortcuts and redirects to the target.
  * Alternatively, checks if the current page is an redirect to an external page
  *
- * @internal this middleware might get removed in TYPO3 v10.0.
+ * @internal this middleware might get removed in TYPO3 v10.x.
  */
 class ShortcutAndMountPointRedirect implements MiddlewareInterface
 {
diff --git a/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php b/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php
index 55fba5f71d0a7bedb9839f5d54f73ba3133b99fc..7af1b35a48c8d0a26e70c43dfe3f9d2436098164 100644
--- a/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php
+++ b/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php
@@ -19,14 +19,26 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Context\UserAspect;
+use TYPO3\CMS\Core\Context\WorkspaceAspect;
+use TYPO3\CMS\Core\Routing\PageArguments;
+use TYPO3\CMS\Core\Site\Entity\Site;
+use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\ErrorController;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
 
 /**
  * Creates an instance of TypoScriptFrontendController and makes this globally available
  * via $GLOBALS['TSFE'].
  *
- * @internal this middleware might get removed in TYPO3 v10.0.
+ * In addition, determineId builds up the rootline based on a valid frontend-user authentication and
+ * Backend permissions if previewing.
+ *
+ * @internal this middleware might get removed in TYPO3 v11.0.
  */
 class TypoScriptFrontendInitialization implements MiddlewareInterface
 {
@@ -39,19 +51,61 @@ class TypoScriptFrontendInitialization implements MiddlewareInterface
      */
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
-        $GLOBALS['TSFE'] = GeneralUtility::makeInstance(
+        $GLOBALS['TYPO3_REQUEST'] = $request;
+        /** @var Site $site */
+        $site = $request->getAttribute('site', null);
+        $pageArguments = $request->getAttribute('routing', null);
+        if (!$pageArguments instanceof PageArguments) {
+            // Page Arguments must be set in order to validate. This middleware only works if PageArguments
+            // is available, and is usually combined with the Page Resolver middleware
+            return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+                $request,
+                'Page Arguments could not be resolved',
+                ['code' => PageAccessFailureReasons::INVALID_PAGE_ARGUMENTS]
+            );
+        }
+        $context = GeneralUtility::makeInstance(Context::class);
+
+        $controller = GeneralUtility::makeInstance(
             TypoScriptFrontendController::class,
-            null,
-            $request->getParsedBody()['id'] ?? $request->getQueryParams()['id'] ?? 0,
-            $request->getParsedBody()['type'] ?? $request->getQueryParams()['type'] ?? 0,
-            null,
-            $request->getParsedBody()['cHash'] ?? $request->getQueryParams()['cHash'] ?? '',
-            null,
-            $request->getParsedBody()['MP'] ?? $request->getQueryParams()['MP'] ?? ''
+            $context,
+            $site,
+            $request->getAttribute('language', $site->getDefaultLanguage()),
+            $pageArguments,
+            $request->getAttribute('frontend.user', null)
         );
-        if ($request->getParsedBody()['no_cache'] ?? $request->getQueryParams()['no_cache'] ?? false) {
-            $GLOBALS['TSFE']->set_no_cache('&no_cache=1 has been supplied, so caching is disabled! URL: "' . (string)$request->getUri() . '"');
+        if ($pageArguments->getArguments()['no_cache'] ?? $request->getParsedBody()['no_cache'] ?? false) {
+            $controller->set_no_cache('&no_cache=1 has been supplied, so caching is disabled! URL: "' . (string)$request->getUri() . '"');
+        }
+        // Usually only set by the PageArgumentValidator
+        if ($request->getAttribute('noCache', false)) {
+            $controller->no_cache = 1;
+        }
+
+        $controller->determineId();
+
+        // No access? Then remove user and re-evaluate the page id
+        if ($controller->isBackendUserLoggedIn() && !$GLOBALS['BE_USER']->doesUserHaveAccess($controller->page, Permission::PAGE_SHOW)) {
+            unset($GLOBALS['BE_USER']);
+            // Register an empty backend user as aspect
+            $this->setBackendUserAspect($context, null);
+            $controller->determineId();
         }
+
+        // Make TSFE globally available
+        $GLOBALS['TSFE'] = $controller;
         return $handler->handle($request);
     }
+
+    /**
+     * Register the backend user as aspect
+     *
+     * @param Context $context
+     * @param BackendUserAuthentication|null $user
+     */
+    protected function setBackendUserAspect(Context $context, ?BackendUserAuthentication $user): void
+    {
+        $context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
+        $context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user ? $user->workspace : 0));
+    }
 }
diff --git a/typo3/sysext/frontend/Classes/Typolink/AbstractTypolinkBuilder.php b/typo3/sysext/frontend/Classes/Typolink/AbstractTypolinkBuilder.php
index 1b83a471c23f7a53c32d7ea7b84e543d98536a72..e184dc30c259550e92ce02d66f11fdf3e60bac8b 100644
--- a/typo3/sysext/frontend/Classes/Typolink/AbstractTypolinkBuilder.php
+++ b/typo3/sysext/frontend/Classes/Typolink/AbstractTypolinkBuilder.php
@@ -15,7 +15,14 @@ namespace TYPO3\CMS\Frontend\Typolink;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Http\ServerRequestFactory;
+use TYPO3\CMS\Core\Routing\PageArguments;
 use TYPO3\CMS\Core\Service\DependencyOrderingService;
+use TYPO3\CMS\Core\Site\Entity\NullSite;
+use TYPO3\CMS\Core\Site\Entity\Site;
+use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
+use TYPO3\CMS\Core\Site\SiteFinder;
 use TYPO3\CMS\Core\TypoScript\TemplateService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -204,12 +211,32 @@ abstract class AbstractTypolinkBuilder
         // This usually happens when typolink is created by the TYPO3 Backend, where no TSFE object
         // is there. This functionality is currently completely internal, as these links cannot be
         // created properly from the Backend.
-        // However, this is added to avoid any exceptions when trying to create a link
+        // However, this is added to avoid any exceptions when trying to create a link.
+        // Detecting the "first" site usually comes from the fact that TSFE needs to be instantiated
+        // during tests
+        $request = $GLOBALS['TYPO3_REQUEST'] ?? ServerRequestFactory::fromGlobals();
+        $site = $request->getAttribute('site');
+        if (!$site instanceof Site) {
+            $sites = GeneralUtility::makeInstance(SiteFinder::class)->getAllSites();
+            $site = reset($sites);
+            if (!$site instanceof Site) {
+                $site = new NullSite();
+            }
+        }
+        $language = $request->getAttribute('language');
+        if (!$language instanceof SiteLanguage) {
+            $language = $site->getDefaultLanguage();
+        }
+
+        $id = $request->getQueryParams()['id'] ?? $request->getParsedBody()['id'] ?? $site->getRootPageId();
+        $type = $request->getQueryParams()['type'] ?? $request->getParsedBody()['type'] ?? '0';
+
         $this->typoScriptFrontendController = GeneralUtility::makeInstance(
             TypoScriptFrontendController::class,
-            null,
-            GeneralUtility::_GP('id'),
-            (int)GeneralUtility::_GP('type')
+            GeneralUtility::makeInstance(Context::class),
+            $site,
+            $language,
+            $request->getAttribute('routing', new PageArguments((int)$id, (string)$type, []))
         );
         $this->typoScriptFrontendController->sys_page = GeneralUtility::makeInstance(PageRepository::class);
         $this->typoScriptFrontendController->tmpl = GeneralUtility::makeInstance(TemplateService::class);
diff --git a/typo3/sysext/frontend/Configuration/RequestMiddlewares.php b/typo3/sysext/frontend/Configuration/RequestMiddlewares.php
index bf043ef2cd1a85bf2f1fd1a0e5e7b923e6f255a8..41791e69d37f29b2cf778638755b616dbc2da4f2 100644
--- a/typo3/sysext/frontend/Configuration/RequestMiddlewares.php
+++ b/typo3/sysext/frontend/Configuration/RequestMiddlewares.php
@@ -43,41 +43,14 @@ return [
                 'typo3/cms-frontend/maintenance-mode'
             ]
         ],
-        /** internal: do not use or reference this middleware in your own code, as this will be possibly be removed */
-        'typo3/cms-frontend/tsfe' => [
-            'target' => \TYPO3\CMS\Frontend\Middleware\TypoScriptFrontendInitialization::class,
-            'after' => [
-                'typo3/cms-frontend/eid',
-            ]
-        ],
-        /** internal: do not use or reference this middleware in your own code, as this will be possibly be removed */
-        'typo3/cms-frontend/output-compression' => [
-            'target' => \TYPO3\CMS\Frontend\Middleware\OutputCompression::class,
-            'after' => [
-                'typo3/cms-frontend/tsfe',
-            ]
-        ],
-        'typo3/cms-frontend/authentication' => [
-            'target' => \TYPO3\CMS\Frontend\Middleware\FrontendUserAuthenticator::class,
-            'after' => [
-                'typo3/cms-frontend/tsfe',
-            ]
-        ],
-        'typo3/cms-frontend/backend-user-authentication' => [
-            'target' => \TYPO3\CMS\Frontend\Middleware\BackendUserAuthenticator::class,
-            'after' => [
-                'typo3/cms-frontend/tsfe',
-            ]
-        ],
         'typo3/cms-frontend/site' => [
             'target' => \TYPO3\CMS\Frontend\Middleware\SiteResolver::class,
             'after' => [
                 'typo3/cms-core/normalized-params-attribute',
-                'typo3/cms-frontend/tsfe',
-                'typo3/cms-frontend/authentication',
-                'typo3/cms-frontend/backend-user-authentication',
             ],
             'before' => [
+                'typo3/cms-frontend/authentication',
+                'typo3/cms-frontend/backend-user-authentication',
                 'typo3/cms-frontend/page-resolver'
             ]
         ],
@@ -99,13 +72,31 @@ return [
                 'typo3/cms-frontend/page-resolver'
             ]
         ],
+        'typo3/cms-frontend/backend-user-authentication' => [
+            'target' => \TYPO3\CMS\Frontend\Middleware\BackendUserAuthenticator::class,
+            'before' => [
+                'typo3/cms-frontend/authentication',
+            ]
+        ],
+        'typo3/cms-frontend/authentication' => [
+            'target' => \TYPO3\CMS\Frontend\Middleware\FrontendUserAuthenticator::class,
+            'before' => [
+                'typo3/cms-frontend/tsfe',
+            ],
+            'after' => [
+                'typo3/cms-frontend/maintenance-mode',
+                'typo3/cms-frontend/site'
+            ]
+        ],
         'typo3/cms-frontend/page-resolver' => [
             'target' => \TYPO3\CMS\Frontend\Middleware\PageResolver::class,
             'after' => [
-                'typo3/cms-frontend/tsfe',
+                'typo3/cms-frontend/site',
                 'typo3/cms-frontend/authentication',
                 'typo3/cms-frontend/backend-user-authentication',
-                'typo3/cms-frontend/site',
+            ],
+            'before' => [
+                'typo3/cms-frontend/tsfe',
             ]
         ],
         'typo3/cms-frontend/page-argument-validator' => [
@@ -114,14 +105,29 @@ return [
                 'typo3/cms-frontend/page-resolver',
             ],
             'before' => [
-                'typo3/cms-frontend/prepare-tsfe-rendering',
+                'typo3/cms-frontend/tsfe',
+            ]
+        ],
+        /** internal: do not use or reference this middleware in your own code, as this will be possibly be removed */
+        'typo3/cms-frontend/tsfe' => [
+            'target' => \TYPO3\CMS\Frontend\Middleware\TypoScriptFrontendInitialization::class,
+            'after' => [
+                'typo3/cms-frontend/eid',
+                'typo3/cms-frontend/page-argument-validator',
+            ]
+        ],
+        /** internal: do not use or reference this middleware in your own code, as this will be possibly be removed */
+        'typo3/cms-frontend/output-compression' => [
+            'target' => \TYPO3\CMS\Frontend\Middleware\OutputCompression::class,
+            'after' => [
+                'typo3/cms-frontend/tsfe',
             ]
         ],
         /** internal: do not use or reference this middleware in your own code, as this will be possibly be removed */
         'typo3/cms-frontend/prepare-tsfe-rendering' => [
             'target' => \TYPO3\CMS\Frontend\Middleware\PrepareTypoScriptFrontendRendering::class,
             'after' => [
-                'typo3/cms-frontend/page-argument-validator',
+                'typo3/cms-frontend/tsfe',
             ]
         ],
         /** internal: do not use or reference this middleware in your own code, as this will be possibly be removed */
diff --git a/typo3/sysext/frontend/Tests/Functional/Configuration/TypoScript/ConditionMatching/ConditionMatcherTest.php b/typo3/sysext/frontend/Tests/Functional/Configuration/TypoScript/ConditionMatching/ConditionMatcherTest.php
index b535eb6dfe86ec68614640fe20cac8e77425dd97..35e63418b3998fb332c4951e8c63b9808653acfa 100644
--- a/typo3/sysext/frontend/Tests/Functional/Configuration/TypoScript/ConditionMatching/ConditionMatcherTest.php
+++ b/typo3/sysext/frontend/Tests/Functional/Configuration/TypoScript/ConditionMatching/ConditionMatcherTest.php
@@ -20,6 +20,7 @@ use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Context\UserAspect;
 use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Log\Logger;
+use TYPO3\CMS\Core\Routing\PageArguments;
 use TYPO3\CMS\Core\Site\Entity\Site;
 use TYPO3\CMS\Core\TypoScript\TemplateService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -445,11 +446,26 @@ class ConditionMatcherTest extends FunctionalTestCase
      */
     protected function setupFrontendController(int $pageId): void
     {
+        $site = new Site('angelo', 13, [
+            'languages' => [
+                [
+                    'languageId' => 0,
+                    'title' => 'United States',
+                    'locale' => 'en_US.UTF-8',
+                ],
+                [
+                    'languageId' => 2,
+                    'title' => 'UK',
+                    'locale' => 'en_UK.UTF-8',
+                ]
+            ]
+        ]);
         $GLOBALS['TSFE'] = GeneralUtility::makeInstance(
             TypoScriptFrontendController::class,
-            null,
-            $pageId,
-            0
+            GeneralUtility::makeInstance(Context::class),
+            $site,
+            $site->getLanguageById(0),
+            new PageArguments($pageId, '0', [])
         );
         $GLOBALS['TSFE']->sys_page = GeneralUtility::makeInstance(PageRepository::class);
         $GLOBALS['TSFE']->tmpl = GeneralUtility::makeInstance(TemplateService::class);
diff --git a/typo3/sysext/frontend/Tests/Functional/ContentObject/ContentObjectRendererTest.php b/typo3/sysext/frontend/Tests/Functional/ContentObject/ContentObjectRendererTest.php
index 113801659c2d8afaaee30a136e9fd315d2e90736..a31f79c4d86fb6a0953bb4d2a7bff849365b7140 100644
--- a/typo3/sysext/frontend/Tests/Functional/ContentObject/ContentObjectRendererTest.php
+++ b/typo3/sysext/frontend/Tests/Functional/ContentObject/ContentObjectRendererTest.php
@@ -14,39 +14,72 @@ namespace TYPO3\CMS\Frontend\Tests\Functional\ContentObject;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Routing\PageArguments;
+use TYPO3\CMS\Core\Site\SiteFinder;
+use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait;
 use TYPO3\CMS\Core\TypoScript\TemplateService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3\CMS\Frontend\Page\PageRepository;
 use TYPO3\CMS\Frontend\Typolink\PageLinkBuilder;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
 
 /**
  * Testcase for TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
  */
-class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
+class ContentObjectRendererTest extends FunctionalTestCase
 {
+    use SiteBasedTestTrait;
+
+    /**
+     * @var array[]
+     */
+    protected const LANGUAGE_PRESETS = [
+        'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en_US.UTF8'],
+    ];
+
     /**
      * @var ContentObjectRenderer
      */
     protected $subject;
 
+    /**
+     * @var TypoScriptFrontendController
+     */
+    protected $typoScriptFrontendController;
+
     protected function setUp(): void
     {
         parent::setUp();
+        $this->writeSiteConfiguration(
+            'test',
+            $this->buildSiteConfiguration(1, '/'),
+            [
+                $this->buildDefaultLanguageConfiguration('EN', '/en/'),
+            ],
+            [
+                $this->buildErrorHandlingConfiguration('Fluid', [404])
+            ]
+        );
+        $_SERVER['HTTP_HOST'] = 'example.com';
+        $_SERVER['REQUEST_URI'] = '/en/';
+        $_GET['id'] = 1;
+        GeneralUtility::flushInternalRuntimeCaches();
+        $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByIdentifier('test');
 
-        $typoScriptFrontendController = GeneralUtility::makeInstance(
+        $this->typoScriptFrontendController = GeneralUtility::makeInstance(
             TypoScriptFrontendController::class,
-            null,
-            1,
-            0
+            GeneralUtility::makeInstance(Context::class),
+            $site,
+            $site->getDefaultLanguage(),
+            new PageArguments(1, '0', [])
         );
-        $typoScriptFrontendController->sys_page = GeneralUtility::makeInstance(PageRepository::class);
-        $typoScriptFrontendController->tmpl = GeneralUtility::makeInstance(TemplateService::class);
-        $GLOBALS['TSFE'] = $typoScriptFrontendController;
-
-        $this->subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
+        $this->typoScriptFrontendController->sys_page = GeneralUtility::makeInstance(PageRepository::class);
+        $this->typoScriptFrontendController->tmpl = GeneralUtility::makeInstance(TemplateService::class);
+        $this->subject = GeneralUtility::makeInstance(ContentObjectRenderer::class, $this->typoScriptFrontendController);
     }
 
     /**
@@ -201,7 +234,7 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\
      */
     public function getQueryCallsGetTreeListWithNegativeValuesIfRecursiveIsSet()
     {
-        $this->subject = $this->getAccessibleMock(ContentObjectRenderer::class, ['getTreeList']);
+        $this->subject = $this->getAccessibleMock(ContentObjectRenderer::class, ['getTreeList'], [$this->typoScriptFrontendController]);
         $this->subject->start([], 'tt_content');
 
         $conf = [
@@ -226,9 +259,9 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\
      */
     public function getQueryCallsGetTreeListWithCurrentPageIfThisIsSet()
     {
-        $GLOBALS['TSFE']->id = 27;
+        $this->typoScriptFrontendController->id = 27;
 
-        $this->subject = $this->getAccessibleMock(ContentObjectRenderer::class, ['getTreeList']);
+        $this->subject = $this->getAccessibleMock(ContentObjectRenderer::class, ['getTreeList'], [$this->typoScriptFrontendController]);
         $this->subject->start([], 'tt_content');
 
         $conf = [
diff --git a/typo3/sysext/frontend/Tests/Unit/ContentObject/Menu/AbstractMenuContentObjectTest.php b/typo3/sysext/frontend/Tests/Unit/ContentObject/Menu/AbstractMenuContentObjectTest.php
index 0269b62e667f0c8a1d1c1a1b676d6910e9da4fc9..76abf1a732693268a9c7e24b130dbb76992bf763 100644
--- a/typo3/sysext/frontend/Tests/Unit/ContentObject/Menu/AbstractMenuContentObjectTest.php
+++ b/typo3/sysext/frontend/Tests/Unit/ContentObject/Menu/AbstractMenuContentObjectTest.php
@@ -22,6 +22,9 @@ use TYPO3\CMS\Core\Context\LanguageAspect;
 use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
+use TYPO3\CMS\Core\Http\ServerRequest;
+use TYPO3\CMS\Core\Routing\PageArguments;
+use TYPO3\CMS\Core\Site\Entity\Site;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
 use TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject;
@@ -44,10 +47,22 @@ class AbstractMenuContentObjectTest extends UnitTestCase
     protected function setUp(): void
     {
         parent::setUp();
+        $GLOBALS['TYPO3_REQUEST'] = new ServerRequest('https://www.example.com', 'GET');
         $proxyClassName = $this->buildAccessibleProxy(AbstractMenuContentObject::class);
         $this->subject = $this->getMockForAbstractClass($proxyClassName);
+        $site = new Site('test', 1, [
+            'base' => 'https://www.example.com',
+            'languages' => [
+                [
+                    'languageId' => 0,
+                    'title' => 'English',
+                    'locale' => 'en_UK',
+                    'base' => '/'
+                ]
+            ]
+        ]);
         $GLOBALS['TSFE'] = $this->getMockBuilder(\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::class)
-            ->setConstructorArgs([$GLOBALS['TYPO3_CONF_VARS'], 1, 1])
+            ->setConstructorArgs([new Context(), $site, $site->getDefaultLanguage(), new PageArguments(1, '1', [])])
             ->setMethods(['initCaches'])
             ->getMock();
         $GLOBALS['TSFE']->cObj = new ContentObjectRenderer();
diff --git a/typo3/sysext/frontend/Tests/Unit/Controller/TypoScriptFrontendControllerTest.php b/typo3/sysext/frontend/Tests/Unit/Controller/TypoScriptFrontendControllerTest.php
index b94278afbc6e7cb11df4733136eefc87e1b1abf0..2dff9524ef4015b7d85de7f7a3610f352b1f9c14 100644
--- a/typo3/sysext/frontend/Tests/Unit/Controller/TypoScriptFrontendControllerTest.php
+++ b/typo3/sysext/frontend/Tests/Unit/Controller/TypoScriptFrontendControllerTest.php
@@ -493,8 +493,7 @@ class TypoScriptFrontendControllerTest extends UnitTestCase
         $cacheManager->getCache('pages')->willReturn($nullCacheBackend);
         GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManager->reveal());
 
-        $subject = new TypoScriptFrontendController(null, 1, 0);
-        $subject->generatePageTitle();
-        $this->assertSame($pageTitle, $subject->indexedDocTitle);
+        $this->subject->generatePageTitle();
+        $this->assertSame($pageTitle, $this->subject->indexedDocTitle);
     }
 }
diff --git a/typo3/sysext/redirects/Classes/Service/RedirectService.php b/typo3/sysext/redirects/Classes/Service/RedirectService.php
index 12e4f3d7ef46fffaf4bba0378e1dc20b595962c3..6aad12893f4aaaaa0451acf06db87b48ab58f5f0 100644
--- a/typo3/sysext/redirects/Classes/Service/RedirectService.php
+++ b/typo3/sysext/redirects/Classes/Service/RedirectService.php
@@ -18,11 +18,13 @@ namespace TYPO3\CMS\Redirects\Service;
 use Psr\Http\Message\UriInterface;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerAwareTrait;
+use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Http\Uri;
 use TYPO3\CMS\Core\LinkHandling\LinkService;
 use TYPO3\CMS\Core\Resource\Exception\InvalidPathException;
 use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Resource\Folder;
+use TYPO3\CMS\Core\Routing\PageArguments;
 use TYPO3\CMS\Core\Site\Entity\SiteInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
@@ -285,11 +287,13 @@ class RedirectService implements LoggerAwareInterface
      */
     protected function bootFrontendController(?SiteInterface $site, array $queryParams): TypoScriptFrontendController
     {
+        $pageId = $site ? $site->getRootPageId() : ($GLOBALS['TSFE'] ? $GLOBALS['TSFE']->id : 0);
         $controller = GeneralUtility::makeInstance(
             TypoScriptFrontendController::class,
-            null,
-            $site ? $site->getRootPageId() : $GLOBALS['TSFE']->id,
-            0
+            GeneralUtility::makeInstance(Context::class),
+            $site,
+            $site->getDefaultLanguage(),
+            new PageArguments((int)$pageId, '0', [])
         );
         $controller->fe_user = $GLOBALS['TSFE']->fe_user ?? null;
         $controller->fetch_the_id();
diff --git a/typo3/sysext/redirects/Configuration/RequestMiddlewares.php b/typo3/sysext/redirects/Configuration/RequestMiddlewares.php
index b7e195cd3dbf771ab33487384440c97f32f677c1..288afab3e2f81ffd2a462432ce7218df88f26d4a 100644
--- a/typo3/sysext/redirects/Configuration/RequestMiddlewares.php
+++ b/typo3/sysext/redirects/Configuration/RequestMiddlewares.php
@@ -11,7 +11,6 @@ return [
                 'typo3/cms-frontend/page-resolver',
             ],
             'after' => [
-                'typo3/cms-frontend/tsfe',
                 'typo3/cms-frontend/authentication',
                 'typo3/cms-frontend/static-route-resolver',
             ],
diff --git a/typo3/sysext/seo/Tests/Functional/Canonical/CanonicalGeneratorTest.php b/typo3/sysext/seo/Tests/Functional/Canonical/CanonicalGeneratorTest.php
index 490f435ff1283553f76aaf1e8439df9a206065cc..94f780d57e7829d6065edfcadd45ee8085ca046e 100644
--- a/typo3/sysext/seo/Tests/Functional/Canonical/CanonicalGeneratorTest.php
+++ b/typo3/sysext/seo/Tests/Functional/Canonical/CanonicalGeneratorTest.php
@@ -17,6 +17,9 @@ namespace TYPO3\CMS\Seo\Tests\Functional\Canonical;
  */
 
 use Psr\Log\NullLogger;
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Routing\PageArguments;
+use TYPO3\CMS\Core\Site\SiteFinder;
 use TYPO3\CMS\Core\TypoScript\TemplateService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -45,17 +48,25 @@ class CanonicalGeneratorTest extends AbstractTestCase
             'website-local',
             $this->buildSiteConfiguration(1, 'http://localhost/')
         );
+        $_SERVER['HTTP_HOST'] = 'localhost';
+        $_SERVER['REQUEST_URI'] = '/';
+        GeneralUtility::flushInternalRuntimeCaches();
     }
 
     protected function initTypoScriptFrontendController(int $uid): TypoScriptFrontendController
     {
-        $typoScriptFrontendController = new TypoScriptFrontendController(null, $uid, 0);
+        $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByIdentifier('website-local');
+        $typoScriptFrontendController = new TypoScriptFrontendController(
+            GeneralUtility::makeInstance(Context::class),
+            $site,
+            $site->getDefaultLanguage(),
+            new PageArguments($uid, '0', [])
+        );
         $typoScriptFrontendController->cObj = new ContentObjectRenderer();
         $typoScriptFrontendController->cObj->setLogger(new NullLogger());
         $typoScriptFrontendController->sys_page = GeneralUtility::makeInstance(PageRepository::class);
         $typoScriptFrontendController->tmpl = GeneralUtility::makeInstance(TemplateService::class);
         $typoScriptFrontendController->getPageAndRootlineWithDomain(1);
-        $GLOBALS['TSFE'] = $typoScriptFrontendController;
         return $typoScriptFrontendController;
     }
 
diff --git a/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php b/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
index 2fa9a64c0f58654d90a77271bcbf1de253651ed8..c410ad95bb095c0d29b6ed1e2063f2920d540444 100644
--- a/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
+++ b/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
@@ -28,6 +28,7 @@ use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\NormalizedParams;
 use TYPO3\CMS\Core\Http\Stream;
 use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Routing\PageArguments;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3\CMS\Workspaces\Authentication\PreviewUserAuthentication;
@@ -64,6 +65,7 @@ class WorkspacePreview implements MiddlewareInterface
      */
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
+        $addInformationAboutDisabledCache = false;
         $keyword = $this->getPreviewInputCode($request);
         if ($keyword) {
             switch ($keyword) {
@@ -75,13 +77,14 @@ class WorkspacePreview implements MiddlewareInterface
                     $message = $this->getLogoutTemplateMessage($request->getQueryParams()['returnUrl'] ?? '');
                     return new HtmlResponse($message);
                 default:
+                    $pageArguments = $request->getAttribute('routing', null);
                     // A keyword was found in a query parameter or in a cookie
                     // If the keyword is valid, activate a BE User and override any existing BE Users
                     $configuration = $this->getPreviewConfigurationFromRequest($request, $keyword);
-                    if (is_array($configuration) && $configuration['fullWorkspace'] > 0) {
+                    if (is_array($configuration) && $configuration['fullWorkspace'] > 0 && $pageArguments instanceof PageArguments) {
                         $previewUser = $this->initializePreviewUser(
                             (int)$configuration['fullWorkspace'],
-                            $GLOBALS['TSFE']->id
+                            $pageArguments->getPageId()
                         );
                         if ($previewUser) {
                             $GLOBALS['BE_USER'] = $previewUser;
@@ -100,11 +103,17 @@ class WorkspacePreview implements MiddlewareInterface
             // Register the backend user as aspect
             $this->setBackendUserAspect(GeneralUtility::makeInstance(Context::class), null);
             // Caching is disabled, because otherwise generated URLs could include the ADMCMD_noBeUser parameter
-            $GLOBALS['TSFE']->set_no_cache('GET Parameter ADMCMD_noBeUser was given', true);
+            $request = $request->withAttribute('noCache', true);
+            $addInformationAboutDisabledCache = true;
         }
 
         $response = $handler->handle($request);
 
+        // Caching is disabled, because otherwise generated URLs could include the ADMCMD_noBeUser parameter
+        if ($addInformationAboutDisabledCache) {
+            $GLOBALS['TSFE']->set_no_cache('GET Parameter ADMCMD_noBeUser was given', true);
+        }
+
         // Add a info box to the frontend content
         if ($GLOBALS['TSFE']->doWorkspacePreview() && $GLOBALS['TSFE']->isOutputting()) {
             $previewInfo = $this->renderPreviewInfo($GLOBALS['TSFE'], $request->getAttribute('normalizedParams'));
diff --git a/typo3/sysext/workspaces/Configuration/RequestMiddlewares.php b/typo3/sysext/workspaces/Configuration/RequestMiddlewares.php
index eeb3a84f3eaa32b7d06e786528cabca8240abea3..98d2517b62181896231644426b55fd2eeed4dcf7 100644
--- a/typo3/sysext/workspaces/Configuration/RequestMiddlewares.php
+++ b/typo3/sysext/workspaces/Configuration/RequestMiddlewares.php
@@ -7,13 +7,14 @@ return [
         'typo3/cms-workspaces/preview' => [
             'target' => \TYPO3\CMS\Workspaces\Middleware\WorkspacePreview::class,
             'after' => [
-                // TSFE is needed to store information about the preview
-                'typo3/cms-frontend/tsfe',
+                // PageArguments are needed to store information about the preview
+                'typo3/cms-frontend/page-argument-validator',
                 // A preview user will override an existing logged-in backend user
                 'typo3/cms-frontend/backend-user-authentication',
             ],
             'before' => [
-                'typo3/cms-frontend/page-resolver',
+                // TSFE is needed to store information about the preview
+                'typo3/cms-frontend/tsfe',
             ]
         ],
     ]