问题
I am trying to migrate my ASP.NET Core 2.0 Angular 5
application with webpack
setup to ASP.NET Core 2.1 Angular 6
with Angular-Cli
.
Short question:
How can I force parsing razor pages directives from cshtml
with Microsoft.AspNetCore.SpaServices.Extensions
?
I do not want to use index.html
from Angular.json
, but index.cshtml
.
Long description:
I started a new ASP.NET Core project from Angular template. There are quite a few things that just magically works.
- There is an
index.html
file insideClientApp/src
folder which is automatically served when application starts. - When application runs, before
</body>
tag fromindex.html
(from first point) several scripts are inserted:inline.bundle.js
,polyfills.bundle.js
,vendor.bundle.js
,main.bundle.js
andstyles.bundle.css
before</head>
tag.
I am not sure who inserted those scripts, but I want to insert them to Razor page (cshtml
).
I tried to use code from my old project:
<!DOCTYPE html>
<html>
<head>
<base href="/" />
<title>@ViewData["Title"]</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
@{string googleAnalyticsId = Html.Raw(ViewData["GoogleAnalyticsId"]).ToString();}
@if (!string.IsNullOrEmpty(googleAnalyticsId))
{
<script>
(function(i, s, o, g, r, a, m)
{
...
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
ga('create', '@googleAnalyticsId', 'auto');
</script>
}
<script>
@Html.Raw(ViewData["TransferData"])
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/0.8.2/css/flag-icon.min.css" async defer />
<script src="https://apis.google.com/js/platform.js" async defer></script>
<app>
<!-- loading layout replaced by app after startupp -->
<div class="page-loading">
<div class="bar">
<i class="sphere"></i>
</div>
</div>
</app>
</body>
</html>
And point index options in Angular.json
to this index.cshtml
:
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "wwwroot/dist",
"index": "Views/Home/Index.cshtml", //<----- here
Problem is that content (all @ tags) is not processed by ASP.NET Core but it outputs direct content:
<!DOCTYPE html>
<html>
<head>
<base href="/" />
<title>@ViewData["Title"]</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
@{string googleAnalyticsId = Html.Raw(ViewData["GoogleAnalyticsId"]).ToString();}
@if (!string.IsNullOrEmpty(googleAnalyticsId))
{
<script>
...
but it should be:
<!DOCTYPE html>
<html>
<head>
<base href="/" />
<title>Test title</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<script>
I want to print some variables (from appsettings.json) to the end html page. Since I am already using ASP.NET Core, Razor page seems good solution.
I also try:
to add new RazorPage, C# content (@ directives) are processed, but no-one is inserting Angular scripts.
Response for AndyCunningham answer:
ng build --prod
writes this files:
<script type="text/javascript" src="runtime.b38c91f828237d6db7f0.js"></script><script type="text/javascript" src="polyfills.2fc3e5708eb8f0eafa68.js"></script><script type="text/javascript" src="main.16911708c355ee56ac06.js"></script>
to index.html
. How to write this to razor page.
回答1:
it's and old question, but I hope the answer help someone
Well, is difficut make that webpack insert the scripts tag in you index.cshtml, but you can include the tags in the index.cshtml like
@{
ViewData["title"] = "I'am from cshtml";
}
<app-root>Loading...</app-root>
<script type="text/javascript" src="/runtime.js"></script>
<script type="text/javascript" src="/polyfills.js"></script>
<script type="text/javascript" src="/styles.js"></script>
<script type="text/javascript" src="/vendor.js"></script>
<script type="text/javascript" src="/main.js"></script>
then you can router your mvc like
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
routes.MapRoute(
name: "spa-fallback",
template: "{*url:regex(^((?!.css|.map|.js|sockjs).)*$)}",
defaults: new { controller = "Home", action = "Index" });
});
See that all the routes that not correcponding with {controller}{action=Index}/{id?} fall in "spa-fallback" that say that if the file not have .css or .map or .js or .sockjs serve your Home/Index. It's necesary the "regex" for .NET serve the script files necesarys.
The last step is configure your angular.json to maintaine the name of the scripts using outputHashing:all
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"ClientApp": {
...
"architect": {
"build": {
...
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all", //<--add this line
...
},
....
},
"defaultProject": "ClientApp"
}
At last we can check if an url is valid or not (else any url server the index page) you can use in startup.cs some like
app.Use(async (context, next) =>
{
string path = context.Request.Path.Value.Substring(1);
bool encontrado = path.EndsWith(".js") || path.EndsWith(".css") || path.EndsWith(".map") || path.StartsWith("sockjs");
if (!encontrado)
{
..use your code to check the url...
}
if (encontrado)
await next.Invoke(); //<--continue
else
{ //send to an error404 page
context.Response.ContentType = "text/html";
await context.Response.SendFileAsync(Path.Combine(env.WebRootPath, "error404.html"));
}
});
NOTE: I put the href of the scripts in absolute path, e.g src="/runtime.js", well in package json we can have several scripts like
"scripts": {
"ng": "ng",
"start": "ng serve --base-href=/ --serve-path=/",
"start:fr": "ng serve --base-href=/fr-FR/ --configuration=fr --serve-path=/fr-FR",
"build": "ng build",
...
},
If we use --serve-path=fr-FR, the href of script must use this serve-path, e.g. src="/fr-FR/runtime.js"
回答2:
I'm basing this answer on my experience with React SPA extensions, but it should be helpful for Angular as well, as it uses the same ClientApp/index.html middleware mechanism, and the same IApplicationBuilder.UseSpa entrypoint.
The problem is that when you use app.UseSpa(...)
, the default implementation of this extension configures a middleware that listens for ALL UI requests and fwds them to index.html.
I've built a quick example of how we get around this for our projects: https://github.com/andycmaj/aspnet_spa_without_indexhtml/pull/1/files should show you what needs to change in order to ignore index.html and use a razor view instead.
Basically, i've re-implemented what UseSpa
does, but without attaching the middleware that intercepts and fwds to index.html.
Note that the Home
razor view still needs to do the more important things that index.html was doing. Most importantly, it needs to include bundle.js served by the SPA static content middleware.
回答3:
You're sort of on the right path, you still need everything you have in your _layout.cshtml
but you're not modifying Angular index.html. Instead your Home/Index.cshtml
or _layout.cshtml
will include the <app-root>
element as well as all your angular scripts. You'll likely want to disable hashes from thegenerated angular files and use ASP.NET to invalidate your JS.
This link explains this in detail but I still have some minor issues with it in Angular 6 + ASP.NET Core 2.1: Add Angular 5 CLI project to ASP.Net Core 2.0 project
来源:https://stackoverflow.com/questions/50815456/asp-net-core-2-1-angular-6-0-spa-template-razor-page-cshtml-for-index-instea