Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Varning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Viktigt!
Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.
För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Visual Studio tillhandahåller projektmallar för att skapa ensidesappar (SPA) baserat på JavaScript-tekniker, till exempel Angular, React och Vue som har en ASP.NET Core-serverdel. Följande mallar:
- Skapa en Visual Studio-lösning med ett klientdelsprojekt och ett serverdelsprojekt.
- Använd Visual Studio-projekttypen för JavaScript och TypeScript (.esproj) för klientdelen.
- Använd ett ASP.NET Core-projekt för serverdelen.
Projekt som skapats med hjälp av Visual Studio-mallarna kan köras från kommandoraden i Windows, Linux och macOS. Om du vill köra appen använder du dotnet run --launch-profile https för att köra serverprojektet. När du kör serverprojektet startas automatiskt klientdelens JavaScript-utvecklingsserver. Startprofilen https krävs för närvarande.
Självstudier för Visual Studio
Kom igång genom att följa någon av självstudierna i Visual Studio-dokumentationen:
- Skapa en ASP.NET Core-app med Angular
- Skapa en ASP.NET Core-app med React
- Skapa en ASP.NET Core-app med Vue
Mer information finns i JavaScript och TypeScript i Visual Studio
ASP.NET Core SPA-mallar
Visual Studio innehåller mallar för att skapa ASP.NET Core-appar med en JavaScript- eller TypeScript-klientdel. Dessa mallar är tillgängliga i Visual Studio 2022 version 17.8 eller senare med ASP.NET och webbutveckling arbetsbelastning installerad.
Visual Studio-mallarna för att skapa ASP.NET Core-appar med en JavaScript- eller TypeScript-klientdel erbjuder följande fördelar:
- Rensa projektavgränsning för klientdelen och serverdelen.
- Håll dig up-to-date med de senaste klientdelsramverksversionerna.
- Integrera med det senaste frontend-kommandoradsverktyget, till exempel Vite.
- Mallar för både JavaScript & TypeScript (endast TypeScript för Angular).
- Omfattande JavaScript- och TypeScript-kodredigeringsupplevelse.
- Integrera JavaScript-byggverktyg med .NET-versionen.
- användargränssnitt för npm-beroendehantering.
- Kompatibel med felsökning och startkonfiguration i Visual Studio Code.
- Kör klientdelsenhetstester i Test Explorer med hjälp av JavaScript-testramverk.
Äldre ASP.NET Core SPA-mallar
Tidigare versioner av .NET SDK inkluderade vad som nu är äldre mallar för att skapa SPA-appar med ASP.NET Core. Dokumentation om dessa äldre mallar finns i .NET 7-versionen av SPA-översikten och artiklarna Angular och React .
Arkitektur för enkeltsidaprogrammallar
Spa-mallarna (Single Page Application) för Angular och React erbjuder möjligheten att utveckla Angular- och React-appar som finns på en .NET-serverdelsserver.
Vid publiceringen kopieras filerna i Angular- och React-appen till wwwroot mappen och hanteras via Static File Middleware.
I stället för att returnera HTTP 404 (hittades inte) hanterar en fallback-rutt okända begäranden till serverdelen och serverar index.html för SPA.
Under utvecklingen konfigureras appen för att använda klientdelsproxyn. React och Angular använder samma klientdelsproxy.
När appen startas index.html öppnas sidan i webbläsaren. Ett särskilt mellanprogram som endast är aktiverat under utveckling:
- Fångar upp inkommande begäranden.
- Kontrollerar om proxyn körs.
- Omdirigerar till URL:en för proxyn om den körs eller startar en ny instans av proxyn.
- Returnerar en sida till webbläsaren som uppdateras automatiskt med några sekunder tills proxyn är igång och webbläsaren omdirigeras.
               
              
            
Den främsta förmånen som ASP.NET Core SPA-mallar ger:
- Startar en proxy om den inte redan körs.
- Konfigurera HTTPS.
- Konfigurera vissa begäranden att proxas till ASP.NET Core-backendservern.
När webbläsaren skickar en begäran om en serverdelsslutpunkt, till exempel /weatherforecast i mallarna. SPA-proxyn tar emot begäran och skickar tillbaka den till servern transparent. Servern svarar och SPA-proxyn skickar begäran tillbaka till webbläsaren:
               
              
            
Publicerade enkeltsidiga applikationer
När appen publiceras blir SPA en samling filer i wwwroot mappen.
Det krävs ingen körningskomponent för att hantera appen:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("index.html");
app.Run();
I den föregående, av mallen genererade, Program.cs-filen:
- 
              app.UseStaticFiles tillåter att filerna hanteras.
- 
              app.MapFallbackToFile("index.html")gör det möjligt att hantera standarddokumentet för alla okända begäranden som servern tar emot.
När appen publiceras med dotnet publish ser följande uppgifter i csproj filen till att npm restore körs och att rätt npm-skript körs för att generera produktionsartefakter:
  <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
    <!-- Ensure Node.js is installed -->
    <Exec Command="node --version" ContinueOnError="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
    </Exec>
    <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
    <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
  </Target>
  <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
    <!-- Include the newly-built files in the publish output -->
    <ItemGroup>
      <DistFiles Include="$(SpaRoot)build\**" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
        <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>
</Project>
Utveckla single page-applikationer
Projektfilen definierar några egenskaper som styr appens beteende under utvecklingen:
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
    <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
    <IsPackable>false</IsPackable>
    <SpaRoot>ClientApp\</SpaRoot>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
    <SpaProxyServerUrl>https://localhost:44414</SpaProxyServerUrl>
    <SpaProxyLaunchCommand>npm start</SpaProxyLaunchCommand>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.1" />
  </ItemGroup>
  <ItemGroup>
    <!-- Don't publish the SPA source files, but do show them in the project files list -->
    <Content Remove="$(SpaRoot)**" />
    <None Remove="$(SpaRoot)**" />
    <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
  </ItemGroup>
  <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
    <!-- Ensure Node.js is installed -->
    <Exec Command="node --version" ContinueOnError="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
    </Exec>
    <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
    <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
  </Target>
  <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
    <!-- Include the newly-built files in the publish output -->
    <ItemGroup>
      <DistFiles Include="$(SpaRoot)build\**" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
        <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>
</Project>
- 
              SpaProxyServerUrl: Styr URL:en där servern förväntar sig att SPA-proxyn ska köras. Det här är URL:en:- Servern pingar efter att proxyn har startats för att veta om den är klar.
- Där den omdirigerar webbläsaren efter ett lyckat svar.
 
- 
              SpaProxyLaunchCommand: Kommandot som servern använder för att starta SPA-proxyn när den identifierar att proxyn inte körs.
Paketet Microsoft.AspNetCore.SpaProxy ansvarar för föregående logik för att identifiera proxyn och omdirigera webbläsaren.
Den värdstartsmonteringen som definieras i Properties/launchSettings.json används för att automatiskt lägga till de nödvändiga komponenterna som krävs under utveckling, för att identifiera om proxyn körs och annars starta den.
{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:51783",
      "sslPort": 44329
    }
  },
  "profiles": {
    "MyReact": {
      "commandName": "Project",
      "launchBrowser": true,
      "applicationUrl": "https://localhost:7145;http://localhost:5273",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
      }
    }
  }
}
Installation för klientappen
Den här konfigurationen är specifik för det klientdelsramverk som appen använder, men många aspekter av konfigurationen är liknande.
Angular-konfiguration
Mallgenererade ClientApp/package.json-filen:
{
  "name": "myangular",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "prestart": "node aspnetcore-https",
    "start": "run-script-os",
    "start:windows": "ng serve --port 44483 --ssl --ssl-cert \"%APPDATA%\\ASP.NET\\https\\%npm_package_name%.pem\" --ssl-key \"%APPDATA%\\ASP.NET\\https\\%npm_package_name%.key\"",
    "start:default": "ng serve --port 44483 --ssl --ssl-cert \"$HOME/.aspnet/https/${npm_package_name}.pem\" --ssl-key \"$HOME/.aspnet/https/${npm_package_name}.key\"",
    "build": "ng build",
    "build:ssr": "ng run MyAngular:server:dev",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^14.1.3",
    "@angular/common": "^14.1.3",
    "@angular/compiler": "^14.1.3",
    "@angular/core": "^14.1.3",
    "@angular/forms": "^14.1.3",
    "@angular/platform-browser": "^14.1.3",
    "@angular/platform-browser-dynamic": "^14.1.3",
    "@angular/platform-server": "^14.1.3",
    "@angular/router": "^14.1.3",
    "bootstrap": "^5.2.0",
    "jquery": "^3.6.0",
    "oidc-client": "^1.11.5",
    "popper.js": "^1.16.0",
    "run-script-os": "^1.1.6",
    "rxjs": "~7.5.6",
    "tslib": "^2.4.0",
    "zone.js": "~0.11.8"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^14.1.3",
    "@angular/cli": "^14.1.3",
    "@angular/compiler-cli": "^14.1.3",
    "@types/jasmine": "~4.3.0",
    "@types/jasminewd2": "~2.0.10",
    "@types/node": "^18.7.11",
    "jasmine-core": "~4.3.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.1.1",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "^2.0.0",
    "typescript": "~4.7.4"
  },
  "overrides": {
    "autoprefixer": "10.4.5"
  },
  "optionalDependencies": {}
}
- Innehåller skript som startar angular-utvecklingsservern: 
- Skriptet - prestartanropar- ClientApp/aspnetcore-https.js, som ansvarar för att säkerställa att HTTPS-certifikatet för utvecklingsservern är tillgängligt för SPA-proxyservern.
- Den - start:windowsoch- start:default:- Starta Angular-utvecklingsservern via ng serve.
- Ange porten, alternativen för att använda HTTPS och sökvägen till certifikatet och den associerade nyckeln. Det angivna portnumret matchar det portnummer som anges i .csprojfilen.
 
- Starta Angular-utvecklingsservern via 
Den mallgenererade ClientApp/angular.json filen innehåller:
- Kommandot - serve.
- Ett - proxyconfig-element i- development-konfigurationen för att indikera att- proxy.conf.jsbör användas för att konfigurera frontend-proxy, som visas i den följande markerade JSON:- { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "MyAngular": { "projectType": "application", "schematics": { "@schematics/angular:application": { "strict": true } }, "root": "", "sourceRoot": "src", "prefix": "app", "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "progress": false, "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", "allowedCommonJsDependencies": [ "oidc-client" ], "assets": [ "src/assets" ], "styles": [ "node_modules/bootstrap/dist/css/bootstrap.min.css", "src/styles.css" ], "scripts": [] }, "configurations": { "production": { "budgets": [ { "type": "initial", "maximumWarning": "500kb", "maximumError": "1mb" }, { "type": "anyComponentStyle", "maximumWarning": "2kb", "maximumError": "4kb" } ], "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "outputHashing": "all" }, "development": { "buildOptimizer": false, "optimization": false, "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true } }, "defaultConfiguration": "production" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { "browserTarget": "MyAngular:build:production" }, "development": { "browserTarget": "MyAngular:build:development", "proxyConfig": "proxy.conf.js" } }, "defaultConfiguration": "development" }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "MyAngular:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.spec.json", "karmaConfig": "karma.conf.js", "assets": [ "src/assets" ], "styles": [ "src/styles.css" ], "scripts": [] } }, "server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist-server", "main": "src/main.ts", "tsConfig": "tsconfig.server.json" }, "configurations": { "dev": { "optimization": true, "outputHashing": "all", "sourceMap": false, "namedChunks": false, "extractLicenses": true, "vendorChunk": true }, "production": { "optimization": true, "outputHashing": "all", "sourceMap": false, "namedChunks": false, "extractLicenses": true, "vendorChunk": false } } } } } }, "defaultProject": "MyAngular" }
              ClientApp/proxy.conf.js definierar de rutter som måste dirigeras tillbaka till serverbackend. Den allmänna uppsättningen alternativ definieras på http-proxy-middleware för react och angular eftersom båda använder samma proxy.
Följande markerade kod från ClientApp/proxy.conf.js använder logik baserat på de miljövariabler som angetts under utvecklingen för att fastställa vilken port serverdelen körs på:
const { env } = require('process');
const target = env.ASPNETCORE_HTTPS_PORTS ? `https://localhost:${env.ASPNETCORE_HTTPS_PORTS}` :
  env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:51951';
const PROXY_CONFIG = [
  {
    context: [
      "/weatherforecast",
   ],
    target: target,
    secure: false,
    headers: {
      Connection: 'Keep-Alive'
    }
  }
]
module.exports = PROXY_CONFIG;
React-konfiguration
- Avsnittet - package.jsonskript innehåller följande skript som startar react-appen under utvecklingen, enligt följande markerade kod:- { "name": "myreact", "version": "0.1.0", "private": true, "dependencies": { "bootstrap": "^5.2.0", "http-proxy-middleware": "^2.0.6", "jquery": "^3.6.0", "merge": "^2.1.1", "oidc-client": "^1.11.5", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-bootstrap": "^0.26.2", "react-router-dom": "^6.3.0", "react-scripts": "^5.0.1", "reactstrap": "^9.1.3", "rimraf": "^3.0.2", "web-vitals": "^2.1.4", "workbox-background-sync": "^6.5.4", "workbox-broadcast-update": "^6.5.4", "workbox-cacheable-response": "^6.5.4", "workbox-core": "^6.5.4", "workbox-expiration": "^6.5.4", "workbox-google-analytics": "^6.5.4", "workbox-navigation-preload": "^6.5.4", "workbox-precaching": "^6.5.4", "workbox-range-requests": "^6.5.4", "workbox-routing": "^6.5.4", "workbox-strategies": "^6.5.4", "workbox-streams": "^6.5.4" }, "devDependencies": { "ajv": "^8.11.0", "cross-env": "^7.0.3", "eslint": "^8.22.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-flowtype": "^8.0.3", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-react": "^7.30.1", "nan": "^2.16.0", "typescript": "^4.7.4" }, "overrides": { "autoprefixer": "10.4.5" }, "resolutions": { "css-what": "^5.0.1", "nth-check": "^3.0.1" }, "scripts": { "prestart": "node aspnetcore-https && node aspnetcore-react", "start": "rimraf ./build && react-scripts start", "build": "react-scripts build", "test": "cross-env CI=true react-scripts test --env=jsdom", "eject": "react-scripts eject", "lint": "eslint ./src/" }, "eslintConfig": { "extends": [ "react-app" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }
- Skriptet - prestartanropar:- 
              aspnetcore-https.js, som ansvarar för att säkerställa att HTTPS-certifikatet för utvecklingsservern är tillgängligt för SPA-proxyservern.
- Anropar aspnetcore-react.jsför att konfigurera lämplig.env.development.localfil för att använda det lokala HTTPS-utvecklingscertifikatet.aspnetcore-react.jskonfigurerar det lokala HTTPS-utvecklingscertifikatet genom att lägga tillSSL_CRT_FILE=<certificate-path>ochSSL_KEY_FILE=<key-path>till filen.
 
- 
              
- Filen - .env.developmentdefinierar porten för utvecklingsservern och anger HTTPS.
              src/setupProxy.js Konfigurerar SPA-proxyn för att vidarebefordra begäranden till serverdelen. Den allmänna uppsättningen alternativ definieras i http-proxy-middleware.
Följande markerade kod i ClientApp/src/setupProxy.js använder logik baserat på de miljövariabler som angetts under utvecklingen för att fastställa vilken port serverdelen körs på:
const { createProxyMiddleware } = require('http-proxy-middleware');
const { env } = require('process');
const target = env.ASPNETCORE_HTTPS_PORTS ? `https://localhost:${env.ASPNETCORE_HTTPS_PORTS}` :
  env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:51783';
const context = [
  "/weatherforecast",
];
const onError = (err, req, resp, target) => {
    console.error(`${err.message}`);
}
module.exports = function (app) {
  const appProxy = createProxyMiddleware(context, {
    target: target,
    // Handle errors to prevent the proxy middleware from crashing when
    // the ASP NET Core webserver is unavailable
    onError: onError,
    secure: false,
    // Uncomment this line to add support for proxying websockets
    //ws: true, 
    headers: {
      Connection: 'Keep-Alive'
    }
  });
  app.use(appProxy);
};
Spa-ramverksversion som stöds i ASP.NET Core SPA-mallar
SPA-projektmallarna som levereras med varje ASP.NET Core-version refererar till den senaste versionen av lämpligt SPA-ramverk.
SPA-ramverk har vanligtvis en kortare versionscykel än .NET. På grund av de två olika versionscyklerna kan den version av SPA-ramverket som stöds och .NET bli osynkroniserad: den större SPA-ramverksversionen, som en .NET-huvudversion är beroende av, kan gå ur support, medan .NET-versionen som SPA-ramverket levereras med fortfarande stöds.
De ASP.NET Core SPA-mallarna kan uppdateras i en korrigeringsversion till en ny SPA-ramverksversion för att hålla mallarna i ett tillstånd som stöds och är säkert.
Ytterligare resurser
ASP.NET Core