Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

Commit 52c69d8

Browse files
Update to newer API designs
1 parent fe900f7 commit 52c69d8

File tree

9 files changed

+198
-263
lines changed

9 files changed

+198
-263
lines changed

src/Microsoft.AspNetCore.SpaServices/AngularCli/AngularCliBuilder.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using Microsoft.AspNetCore.Builder;
45
using Microsoft.AspNetCore.SpaServices.Prerendering;
56
using System;
6-
using System.Linq;
77
using System.Threading.Tasks;
88

99
namespace Microsoft.AspNetCore.SpaServices.AngularCli
@@ -26,18 +26,22 @@ public AngularCliBuilder(string cliAppName)
2626
}
2727

2828
/// <inheritdoc />
29-
public Task Build(ISpaBuilder spaBuilder)
29+
public Task Build(IApplicationBuilder app)
3030
{
31-
// Locate the AngularCliMiddleware within the provided ISpaBuilder
32-
var angularCliMiddleware = spaBuilder
33-
.Properties.Keys.OfType<AngularCliMiddleware>().FirstOrDefault();
34-
if (angularCliMiddleware == null)
31+
// Locate the AngularCliMiddleware within the provided IApplicationBuilder
32+
if (app.Properties.TryGetValue(
33+
AngularCliMiddleware.AngularCliMiddlewareKey,
34+
out var angularCliMiddleware))
35+
{
36+
return ((AngularCliMiddleware)angularCliMiddleware)
37+
.StartAngularCliBuilderAsync(_cliAppName);
38+
}
39+
else
3540
{
3641
throw new Exception(
37-
$"Cannot use {nameof (AngularCliBuilder)} unless you are also using {nameof(AngularCliMiddleware)}.");
42+
$"Cannot use {nameof(AngularCliBuilder)} unless you are also using" +
43+
$" {nameof(AngularCliMiddlewareExtensions.UseAngularCliServer)}.");
3844
}
39-
40-
return angularCliMiddleware.StartAngularCliBuilderAsync(_cliAppName);
4145
}
4246
}
4347
}

src/Microsoft.AspNetCore.SpaServices/AngularCli/AngularCliMiddleware.cs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,41 @@
99
using Microsoft.AspNetCore.Hosting;
1010
using System.Threading;
1111
using Microsoft.AspNetCore.SpaServices.Proxy;
12+
using Microsoft.AspNetCore.Http;
1213

1314
namespace Microsoft.AspNetCore.SpaServices.AngularCli
1415
{
1516
internal class AngularCliMiddleware
1617
{
1718
private const string _middlewareResourceName = "/Content/Node/angular-cli-middleware.js";
1819

20+
internal readonly static string AngularCliMiddlewareKey = Guid.NewGuid().ToString();
21+
1922
private readonly INodeServices _nodeServices;
2023
private readonly string _middlewareScriptPath;
2124

22-
public AngularCliMiddleware(ISpaBuilder spaBuilder, string sourcePath)
25+
public AngularCliMiddleware(IApplicationBuilder appBuilder, string sourcePath, string urlPrefix, string defaultPage)
2326
{
2427
if (string.IsNullOrEmpty(sourcePath))
2528
{
2629
throw new ArgumentException("Cannot be null or empty", nameof(sourcePath));
2730
}
2831

2932
// Prepare to make calls into Node
30-
var appBuilder = spaBuilder.AppBuilder;
3133
_nodeServices = CreateNodeServicesInstance(appBuilder, sourcePath);
3234
_middlewareScriptPath = GetAngularCliMiddlewareScriptPath(appBuilder);
3335

3436
// Start Angular CLI and attach to middleware pipeline
3537
var angularCliServerInfoTask = StartAngularCliServerAsync();
36-
spaBuilder.AddStartupTask(angularCliServerInfoTask);
3738

3839
// Proxy the corresponding requests through ASP.NET and into the Node listener
3940
// Anything under /<publicpath> (e.g., /dist) is proxied as a normal HTTP request
4041
// with a typical timeout (100s is the default from HttpClient).
41-
UseProxyToLocalAngularCliMiddleware(appBuilder, spaBuilder.PublicPath,
42+
UseProxyToLocalAngularCliMiddleware(appBuilder, urlPrefix, defaultPage,
4243
angularCliServerInfoTask, TimeSpan.FromSeconds(100));
4344

4445
// Advertise the availability of this feature to other SPA middleware
45-
spaBuilder.Properties.Add(this, null);
46+
appBuilder.Properties.Add(AngularCliMiddlewareKey, this);
4647
}
4748

4849
public Task StartAngularCliBuilderAsync(string cliAppName)
@@ -65,6 +66,11 @@ private static INodeServices CreateNodeServicesInstance(
6566
ProjectPath = Path.Combine(Directory.GetCurrentDirectory(), sourcePath),
6667
};
6768

69+
if (!Directory.Exists(nodeServicesOptions.ProjectPath))
70+
{
71+
throw new DirectoryNotFoundException($"Directory not found: {nodeServicesOptions.ProjectPath}");
72+
}
73+
6874
return NodeServicesFactory.CreateNodeServices(nodeServicesOptions);
6975
}
7076

@@ -99,7 +105,7 @@ private async Task<AngularCliServerInfo> StartAngularCliServerAsync()
99105
}
100106

101107
private static void UseProxyToLocalAngularCliMiddleware(
102-
IApplicationBuilder appBuilder, string publicPath,
108+
IApplicationBuilder appBuilder, string urlPrefix, string defaultPage,
103109
Task<AngularCliServerInfo> serverInfoTask, TimeSpan requestTimeout)
104110
{
105111
// This is hardcoded to use http://localhost because:
@@ -110,7 +116,37 @@ private static void UseProxyToLocalAngularCliMiddleware(
110116
var proxyOptionsTask = serverInfoTask.ContinueWith(
111117
task => new ConditionalProxyMiddlewareTarget(
112118
"http", "localhost", task.Result.Port.ToString()));
113-
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(publicPath, requestTimeout, proxyOptionsTask);
119+
120+
// Requests outside /<urlPrefix> are proxied to the default page
121+
var hasRewrittenUrlMarker = new object();
122+
var defaultPageUrl = SpaDefaultPageExtensions.GetDefaultPageUrl(
123+
urlPrefix, defaultPage);
124+
var urlPrefixIsRoot = string.IsNullOrEmpty(urlPrefix) || urlPrefix == "/";
125+
appBuilder.Use((context, next) =>
126+
{
127+
if (!urlPrefixIsRoot && !context.Request.Path.StartsWithSegments(urlPrefix))
128+
{
129+
context.Items[hasRewrittenUrlMarker] = context.Request.Path;
130+
context.Request.Path = defaultPageUrl;
131+
}
132+
133+
return next();
134+
});
135+
136+
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(urlPrefix, requestTimeout, proxyOptionsTask);
137+
138+
// If we rewrote the path, rewrite it back. Don't want to interfere with
139+
// any other middleware.
140+
appBuilder.Use((context, next) =>
141+
{
142+
if (context.Items.ContainsKey(hasRewrittenUrlMarker))
143+
{
144+
context.Request.Path = (PathString)context.Items[hasRewrittenUrlMarker];
145+
context.Items.Remove(hasRewrittenUrlMarker);
146+
}
147+
148+
return next();
149+
});
114150
}
115151

116152
#pragma warning disable CS0649
Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using Microsoft.AspNetCore.Builder;
5+
46
namespace Microsoft.AspNetCore.SpaServices.AngularCli
57
{
68
/// <summary>
@@ -9,23 +11,24 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli
911
public static class AngularCliMiddlewareExtensions
1012
{
1113
/// <summary>
12-
/// Enables Angular CLI middleware support. This hosts an instance of the Angular CLI in memory in
13-
/// your application so that you can always serve up-to-date CLI-built resources without having
14-
/// to run CLI server manually.
15-
///
16-
/// Incoming requests that match Angular CLI-built files will be handled by returning the CLI server
17-
/// output directly.
14+
/// Handles requests by passing them through to an instance of the Angular CLI server.
15+
/// This means you can always serve up-to-date CLI-built resources without having
16+
/// to run the Angular CLI server manually.
1817
///
19-
/// This feature should only be used in development. For production deployments, be sure not to
20-
/// enable Angular CLI middleware.
18+
/// This feature should only be used in development. For production deployments, be
19+
/// sure not to enable the Angular CLI server.
2120
/// </summary>
22-
/// <param name="spaBuilder">The <see cref="ISpaBuilder"/>.</param>
23-
/// <param name="sourcePath">The path, relative to the application root, of the directory containing the SPA source files.</param>
24-
public static void UseAngularCliMiddleware(
25-
this ISpaBuilder spaBuilder,
26-
string sourcePath)
21+
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
22+
/// <param name="sourcePath">The disk path, relative to the current directory, of the directory containing the SPA source files. When Angular CLI executes, this will be its working directory.</param>
23+
/// <param name="urlPrefix">The URL prefix from which your SPA's files are served. This needs to match the <c>--deploy-url</c> option passed to Angular CLI.</param>
24+
/// <param name="defaultPage">Optional. Specifies the URL, relative to <paramref name="urlPrefix"/>, of the default HTML page that starts up your SPA. Defaults to <c>index.html</c>.</param>
25+
public static void UseAngularCliServer(
26+
this IApplicationBuilder app,
27+
string sourcePath,
28+
string urlPrefix,
29+
string defaultPage = null)
2730
{
28-
new AngularCliMiddleware(spaBuilder, sourcePath);
31+
new AngularCliMiddleware(app, sourcePath, urlPrefix, defaultPage);
2932
}
3033
}
3134
}

src/Microsoft.AspNetCore.SpaServices/DefaultSpaBuilder.cs

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/Microsoft.AspNetCore.SpaServices/ISpaBuilder.cs

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/Microsoft.AspNetCore.SpaServices/Prerendering/ISpaPrerendererBuilder.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using Microsoft.AspNetCore.Builder;
45
using System.Threading.Tasks;
56

67
namespace Microsoft.AspNetCore.SpaServices.Prerendering
@@ -17,8 +18,8 @@ public interface ISpaPrerendererBuilder
1718
/// exists on disk. Prerendering middleware can then execute that file in
1819
/// a Node environment.
1920
/// </summary>
20-
/// <param name="spaBuilder">The <see cref="ISpaBuilder"/>.</param>
21+
/// <param name="appBuilder">The <see cref="IApplicationBuilder"/>.</param>
2122
/// <returns>A <see cref="Task"/> representing completion of the build process.</returns>
22-
Task Build(ISpaBuilder spaBuilder);
23+
Task Build(IApplicationBuilder appBuilder);
2324
}
2425
}

0 commit comments

Comments
 (0)