Angular 5 State Transfer does not work within ASP.NET Core SPA #312

Closed
opened 2025-08-09 17:15:48 +00:00 by fergalmoran · 0 comments
Owner

Originally created by @OleksandrKrutykh on 11/21/2017

Description

Angular 5 contains a new feature that allows sending a component state from the server to the browser (see this blog entry, section "Angular Universal State Transfer API and DOM Support"). This feature does not seem to work when an Angular app is hosted by ASP.NET Core SPA. The TransferState object in the browser is empty, as if the server side didn't save anything there.

Steps to Reproduce

As the official documentation for State Transfer is not available yet, the design document referenced in the pull request was used as the instruction.

A sample project for Visual Studio 2017 was created using the "MVC ASP.NET Core with Angular" project template and the following changes were made there:

  • The versions of Angular packages in package.json were changed to 5.0.2
  • All Angular components except the root AppComponent were removed from the project
  • The imports lists in ./ClientApp/app/app.browser.module.ts and ./ClientApp/app/app.server.module.ts were updated to contain BrowserModule.withServerTransition(...)
  • BrowserTransferStateModule and ServerTransferStateModule were added to the imports of app.browser.module.ts and app.server.module.ts respectively
  • The call of platformBrowserDynamic().bootstrapModule(AppModule) in ./ClientApp/boot.browser.ts was wrapped into a listener of DOMContentLoaded event. See this comment

The sample Visual Studio project: AngularTest.zip

The single Angular component in the project was modified to look like this:

import { Component } from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { Inject, PLATFORM_ID } from '@angular/core';
import { TransferState, StateKey, makeStateKey } from '@angular/platform-browser';

const stateKey: StateKey<string> = makeStateKey('AppComponent');

@Component({
    selector: 'app',
    template: '<p>{{text}}</p>',
})
export class AppComponent {
    text: string;

    constructor(
        @Inject(PLATFORM_ID) platformId: Object,
        transferState: TransferState
    ) {
        if (isPlatformServer(platformId)) {
            this.text = "Hello from server";
            transferState.onSerialize(stateKey, () => "42");
        } else {
            const payload: string = transferState.get(stateKey, "Not found!");
            this.text = `Hello from client. Payload from server: ${payload}`;
            transferState.remove(stateKey);
        }
    }
}

On the server side, the component puts string "42" in the TransferState. In the browser, the component tries to restore the string from the TransferState.

Expected Result

When the application is started from within Visual Studio (in IIS Express), the web page briefly shows the text "Hello from server", which is then replaced with "Hello from client. Payload from server: 42".

Actual Result

The the web page shows the text "Hello from server", which is then replaced with "Hello from client. Payload from server: Not found!".

According to this section of the State Transfer design document, the server response should contain a <script> tag with the serialized TransferState inside. But the actual response (see an example here:
Response.txt) does not contain any <script> tags except for the ones corresponding to the <script> tags in ./Views/Home/Index.cshtml

Environment

  • Operating system: Windows 10 Pro version 1703
  • Visual Studio 2017 Community Edition, version 15.4.4
  • .NET Core version 2.0.3
  • Template package: Microsoft.AspNetCore.SpaTemplates version 2.0.3
  • Angular version 5.0.2
  • Browsers tested: Firefox 57, Chrome 62, Edge 15.
*Originally created by @OleksandrKrutykh on 11/21/2017* ## Description Angular 5 contains a new feature that allows sending a component state from the server to the browser (see this [blog entry](https://blog.angular.io/version-5-0-0-of-angular-now-available-37e414935ced#52d1), section "Angular Universal State Transfer API and DOM Support"). This feature does not seem to work when an Angular app is hosted by ASP.NET Core SPA. The `TransferState` object in the browser is empty, as if the server side didn't save anything there. ## Steps to Reproduce As the official documentation for State Transfer is not available yet, the [design document](https://docs.google.com/document/d/1Hv3VTRQC0H5yPe8ivJXaGst93yRAtD6nEFkQDLiK_IU/preview) referenced in the [pull request](https://github.com/angular/angular/pull/19134) was used as the instruction. A sample project for Visual Studio 2017 was created using the "MVC ASP.NET Core with Angular" project template and the following changes were made there: - The versions of Angular packages in package.json were changed to 5.0.2 - All Angular components except the root `AppComponent` were removed from the project - The imports lists in ./ClientApp/app/app.browser.module.ts and ./ClientApp/app/app.server.module.ts were updated to contain `BrowserModule.withServerTransition(...)` - `BrowserTransferStateModule` and `ServerTransferStateModule` were added to the imports of app.browser.module.ts and app.server.module.ts respectively - The call of `platformBrowserDynamic().bootstrapModule(AppModule)` in ./ClientApp/boot.browser.ts was wrapped into a listener of `DOMContentLoaded` event. See [this comment](https://github.com/angular/angular/pull/19134#issuecomment-337551723) The sample Visual Studio project: [AngularTest.zip](https://github.com/aspnet/JavaScriptServices/files/1489531/AngularTest.zip) The single Angular component in the project was modified to look like this: ```typescript import { Component } from '@angular/core'; import { isPlatformServer } from '@angular/common'; import { Inject, PLATFORM_ID } from '@angular/core'; import { TransferState, StateKey, makeStateKey } from '@angular/platform-browser'; const stateKey: StateKey<string> = makeStateKey('AppComponent'); @Component({ selector: 'app', template: '<p>{{text}}</p>', }) export class AppComponent { text: string; constructor( @Inject(PLATFORM_ID) platformId: Object, transferState: TransferState ) { if (isPlatformServer(platformId)) { this.text = "Hello from server"; transferState.onSerialize(stateKey, () => "42"); } else { const payload: string = transferState.get(stateKey, "Not found!"); this.text = `Hello from client. Payload from server: ${payload}`; transferState.remove(stateKey); } } } ``` On the server side, the component puts string "42" in the `TransferState`. In the browser, the component tries to restore the string from the `TransferState`. ### Expected Result When the application is started from within Visual Studio (in IIS Express), the web page briefly shows the text "Hello from server", which is then replaced with "Hello from client. Payload from server: 42". ### Actual Result The the web page shows the text "Hello from server", which is then replaced with "Hello from client. Payload from server: Not found!". According to this [section](https://docs.google.com/document/d/1Hv3VTRQC0H5yPe8ivJXaGst93yRAtD6nEFkQDLiK_IU/preview#heading=h.510vxb6wrgpg) of the State Transfer design document, the server response should contain a `<script>` tag with the serialized TransferState inside. But the actual response (see an example here: [Response.txt](https://github.com/aspnet/JavaScriptServices/files/1489539/Response.txt)) does not contain any `<script>` tags except for the ones corresponding to the `<script>` tags in ./Views/Home/Index.cshtml ## Environment - Operating system: Windows 10 Pro version 1703 - Visual Studio 2017 Community Edition, version 15.4.4 - .NET Core version 2.0.3 - Template package: Microsoft.AspNetCore.SpaTemplates version 2.0.3 - Angular version 5.0.2 - Browsers tested: Firefox 57, Chrome 62, Edge 15.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/JavaScriptServices#312
No description provided.