Передача данных из ASP.NET Core в Typescript в приложении на основе Angular Cli
Я пытаюсь настроить SPA, где я могу передать данные из моего appsettings.json моей клиентской стороне на серверной визуализации. Я следовал инструкциям по настройке SSR с использованием новых шаблонов SpaServices.
https://docs.microsoft.com/en-us/aspnet/core/spa/angular
Однако я не понимаю, как выполнить задачу, обозначенную здесь
Вы можете передать это другим частям вашего приложения любым способом, поддерживаемым Angular.
Я вижу пример, который используется base_url, но кажется, что база вводится в страницу как элемент DOM
<base href='/'>
Но не ясно, как читать другие предметы таким образом. Я тестирую прохождение, независимо от того, является ли приложение Https или нет, у меня есть этот раздел в моем Startup.cs
options.SupplyData = (context, data) =>
{
data["isHttpsRequest"] = context.Request.IsHttps;
};
и в main.server.ts
{ provide: 'isHttps', useValue: params.data.isHttpsRequest }
но именно в main.ts я теряюсь, у меня что-то вроде этого
export function getBaseUrl() {
return document.getElementsByTagName('base')[0].href;
}
export function getIsHttps() {
// NO idea what needs to go here
return "";
}
const providers = [
{ provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] },
{ provide: 'isHttps', useFactory: getIsHttps, deps: [] }
];
Я не уверен, как SpaServices вводит значение Prerender в приложение (я просматривал код, но он мне не понятен). Значение помещено в окно? Как мне прочитать значение, чтобы я мог добавить его в конструкторы компонентов?
2 ответа
Нашел ответ. Вы можете использовать официальный TransferState от Angular. Вам нужно будет изменить следующие файлы
app.server.module.ts (Добавить ServerTransferStateModule)
import { NgModule } from '@angular/core';
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule
],
bootstrap: [AppComponent],
})
export class AppServerModule { }
app.module.ts (Добавить BrowserTransferStateModule)
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'universal-demo-v5' }),
HttpClientModule,
BrowserTransferStateModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Это добавляет модули, необходимые для использования TransferState.
Затем вам нужно будет указать значение, отправленное сервером dotnet на main.server.ts
и добавьте фиктивного провайдера на main.ts
чтобы не поднимать конфликт.
main.server.ts
import "zone.js/dist/zone-node";
import "reflect-metadata";
import { renderModule, renderModuleFactory } from "@angular/platform-server";
import { APP_BASE_HREF } from "@angular/common";
import { enableProdMode } from "@angular/core";
import { provideModuleMap } from "@nguniversal/module-map-ngfactory-loader";
import { createServerRenderer } from "aspnet-prerendering";
export { AppServerModule } from "./app/app.server.module";
enableProdMode();
export default createServerRenderer(params => {
const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;
const options = {
document: params.data.originalHtml,
url: params.url,
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP),
{ provide: APP_BASE_HREF, useValue: params.baseUrl },
{ provide: "BASE_URL", useValue: params.origin + params.baseUrl},
//Added provider, ServerParams is the data sent on Startup.cs
{ provide: "SERVER_PARAMS", useValue: params.data.ServerParams }
]
};
const renderPromise = AppServerModuleNgFactory
? /* AoT */ renderModuleFactory(AppServerModuleNgFactory, options)
: /* dev */ renderModule(AppServerModule, options);
return renderPromise.then(html => ({ html }));
});
main.ts (Добавляйте фиктивный провайдер и приложение начальной загрузки только после завершения загрузки DOM. Это даст нам время для полного сохранения объекта в TransferState)
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";
export function getBaseUrl() {
return document.getElementsByTagName("base")[0].href;
}
const providers = [
{ provide: "BASE_URL", useFactory: getBaseUrl, deps: [] },
{ provide: "SERVER_PARAMS", useValue: "" }
];
if (environment.production) {
enableProdMode();
}
document.addEventListener("DOMContentLoaded", () => {
platformBrowserDynamic(providers)
.bootstrapModule(AppModule)
.catch(err => console.log(err));
});
Наконец, мы сохраняем предоставленный сервером объект на app.component.ts
на TransferState
app.component.ts
import { Component, Inject } from "@angular/core";
import { TransferState, makeStateKey } from "@angular/platform-browser";
const SERVER_PARAMS = makeStateKey("serverParams");
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
serverParams: any;
// Provider set on main.ts and main.server.ts
constructor(@Inject("SERVER_PARAMS") private stateInj: string, private state: TransferState) {
this.serverParams = this.state.get(SERVER_PARAMS, null as any);
if (!this.serverParams) {
this.state.set(SERVER_PARAMS, stateInj as any);
}
}
}
ВОТ И ВСЕ
Теперь вы можете использовать состояние передачи на любом компоненте, чтобы получить данные как
home.component.ts
import { Component, Inject } from "@angular/core";
import { TransferState, makeStateKey } from "@angular/platform-browser";
const SERVER_PARAMS = makeStateKey("serverParams");
@Component({
selector: "app-home",
templateUrl: "./home.component.html"
})
export class HomeComponent {
serverParameter = "PLACEHOLDER";
constructor(public state: TransferState) {}
ngOnInit() {
this.serverParameter = this.state.get(SERVER_PARAMS, "");
}
}
Поэтому я углубился в это и попытался заставить его работать, но, к сожалению, он не предназначен для работы, как ты, или я думал, что это должно работать. "Вы можете передать это другим частям вашего приложения любым способом, поддерживаемым Angular", что означает, что оно должно быть доступно для кода на стороне клиента либо с помощью глобального пространства имен, либо с помощью других средств (о которых я не могу думать). Когда приложение отображается через main.server.ts, вы можете встраивать переменные с сервера, но это не значит, что они доступны клиентскому приложению автоматически... на мой взгляд, это наполовину испеченное решение, и вы и я не единственный, кого это смущает (см. https://github.com/aspnet/JavaScriptServices/issues/1444).
Я рекомендую вам поискать другие способы включения данных на стороне сервера, например, службу конфигурации в загрузчике вашего приложения, которая получает конфигурацию при запуске, или встраивание объекта JSON в страницу хостинга Angular, написанную кодом на стороне сервера.