mirror of
https://github.com/aspnet/JavaScriptServices.git
synced 2025-12-22 17:47:53 +00:00
Further stylistic tweaks
This commit is contained in:
@@ -25,16 +25,14 @@ namespace Microsoft.AspNetCore.AngularServices
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = html.ViewContext.HttpContext.Request;
|
var request = html.ViewContext.HttpContext.Request;
|
||||||
var baseUri =
|
var baseUriString = string.Concat(
|
||||||
new Uri(
|
request.Scheme,
|
||||||
string.Concat(
|
"://",
|
||||||
request.Scheme,
|
request.Host.ToUriComponent(),
|
||||||
"://",
|
request.PathBase.ToUriComponent(),
|
||||||
request.Host.ToUriComponent(),
|
request.Path.ToUriComponent(),
|
||||||
request.PathBase.ToUriComponent(),
|
request.QueryString.ToUriComponent());
|
||||||
request.Path.ToUriComponent(),
|
var fullUri = new Uri(new Uri(baseUriString), url);
|
||||||
request.QueryString.ToUriComponent()));
|
|
||||||
var fullUri = new Uri(baseUri, url);
|
|
||||||
var response = await new HttpClient().GetAsync(fullUri.ToString());
|
var response = await new HttpClient().GetAsync(fullUri.ToString());
|
||||||
var responseBody = await response.Content.ReadAsStringAsync();
|
var responseBody = await response.Content.ReadAsStringAsync();
|
||||||
return new HtmlString(FormatAsScript(url, response.StatusCode, responseBody));
|
return new HtmlString(FormatAsScript(url, response.StatusCode, responseBody));
|
||||||
@@ -48,11 +46,13 @@ namespace Microsoft.AspNetCore.AngularServices
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static string FormatAsScript(string url, HttpStatusCode responseStatusCode, string responseBody)
|
private static string FormatAsScript(string url, HttpStatusCode responseStatusCode, string responseBody)
|
||||||
=>
|
{
|
||||||
"<script>" +
|
var preCachedUrl = JsonConvert.SerializeObject(url);
|
||||||
"window.__preCachedResponses = window.__preCachedResponses || {}; " +
|
var preCachedJson = JsonConvert.SerializeObject(new { statusCode = responseStatusCode, body = responseBody });
|
||||||
$"window.__preCachedResponses[{JsonConvert.SerializeObject(url)}] " +
|
return "<script>"
|
||||||
$"= {JsonConvert.SerializeObject(new { statusCode = responseStatusCode, body = responseBody })};" +
|
+ "window.__preCachedResponses = window.__preCachedResponses || {};"
|
||||||
"</script>";
|
+ $"window.__preCachedResponses[{preCachedUrl}] = {preCachedJson};"
|
||||||
|
+ "</script>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
|
using System;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.NodeServices
|
namespace Microsoft.AspNetCore.NodeServices
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
|
|
||||||
public static class Configuration
|
public static class Configuration
|
||||||
{
|
{
|
||||||
private static readonly string[] DefaultWatchFileExtensions = {".js", ".jsx", ".ts", ".tsx", ".json", ".html"};
|
private static readonly string[] DefaultWatchFileExtensions = {".js", ".jsx", ".ts", ".tsx", ".json", ".html"};
|
||||||
@@ -20,15 +18,18 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
=> AddNodeServices(serviceCollection, DefaultOptions);
|
=> AddNodeServices(serviceCollection, DefaultOptions);
|
||||||
|
|
||||||
public static void AddNodeServices(this IServiceCollection serviceCollection, NodeServicesOptions options)
|
public static void AddNodeServices(this IServiceCollection serviceCollection, NodeServicesOptions options)
|
||||||
=> serviceCollection.AddSingleton(typeof(INodeServices), serviceProvider =>
|
{
|
||||||
|
serviceCollection.AddSingleton(typeof(INodeServices), serviceProvider =>
|
||||||
{
|
{
|
||||||
var hostEnv = serviceProvider.GetRequiredService<IHostingEnvironment>();
|
var hostEnv = serviceProvider.GetRequiredService<IHostingEnvironment>();
|
||||||
if (string.IsNullOrEmpty(options.ProjectPath))
|
if (string.IsNullOrEmpty(options.ProjectPath))
|
||||||
{
|
{
|
||||||
options.ProjectPath = hostEnv.ContentRootPath;
|
options.ProjectPath = hostEnv.ContentRootPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateNodeServices(options);
|
return CreateNodeServices(options);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static INodeServices CreateNodeServices(NodeServicesOptions options)
|
public static INodeServices CreateNodeServices(NodeServicesOptions options)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,12 +64,14 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
{
|
{
|
||||||
return JsonConvert.DeserializeObject<T>(responseString);
|
return JsonConvert.DeserializeObject<T>(responseString);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(T) != typeof(string))
|
if (typeof(T) != typeof(string))
|
||||||
{
|
{
|
||||||
throw new ArgumentException(
|
throw new ArgumentException(
|
||||||
"Node module responded with non-JSON string. This cannot be converted to the requested generic type: " +
|
"Node module responded with non-JSON string. This cannot be converted to the requested generic type: " +
|
||||||
typeof(T).FullName);
|
typeof(T).FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (T)(object)responseString;
|
return (T)(object)responseString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
private readonly object _childProcessLauncherLock;
|
private readonly object _childProcessLauncherLock;
|
||||||
private readonly string _commandLineArguments;
|
private readonly string _commandLineArguments;
|
||||||
private readonly StringAsTempFile _entryPointScript;
|
private readonly StringAsTempFile _entryPointScript;
|
||||||
|
private Process _nodeProcess;
|
||||||
private TaskCompletionSource<bool> _nodeProcessIsReadySource;
|
private TaskCompletionSource<bool> _nodeProcessIsReadySource;
|
||||||
private readonly string _projectPath;
|
private readonly string _projectPath;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
@@ -27,18 +28,28 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
_commandLineArguments = commandLineArguments ?? string.Empty;
|
_commandLineArguments = commandLineArguments ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Process NodeProcess { get; private set; }
|
protected Process NodeProcess
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// This is only exposed to support the unreliable InputOutputStreamNodeInstance, which is just to verify that
|
||||||
|
// other hosting/transport mechanisms are possible. This shouldn't really be exposed, and will be removed.
|
||||||
|
return this._nodeProcess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Task<T> Invoke<T>(string moduleName, params object[] args)
|
public Task<T> Invoke<T>(string moduleName, params object[] args)
|
||||||
=> InvokeExport<T>(moduleName, null, args);
|
=> InvokeExport<T>(moduleName, null, args);
|
||||||
|
|
||||||
public Task<T> InvokeExport<T>(string moduleName, string exportedFunctionName, params object[] args)
|
public Task<T> InvokeExport<T>(string moduleName, string exportedFunctionName, params object[] args)
|
||||||
=> Invoke<T>(new NodeInvocationInfo
|
{
|
||||||
|
return Invoke<T>(new NodeInvocationInfo
|
||||||
{
|
{
|
||||||
ModuleName = moduleName,
|
ModuleName = moduleName,
|
||||||
ExportedFunctionName = exportedFunctionName,
|
ExportedFunctionName = exportedFunctionName,
|
||||||
Args = args
|
Args = args
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@@ -52,7 +63,7 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
{
|
{
|
||||||
lock (_childProcessLauncherLock)
|
lock (_childProcessLauncherLock)
|
||||||
{
|
{
|
||||||
if (NodeProcess == null || NodeProcess.HasExited)
|
if (_nodeProcess == null || _nodeProcess.HasExited)
|
||||||
{
|
{
|
||||||
var startInfo = new ProcessStartInfo("node")
|
var startInfo = new ProcessStartInfo("node")
|
||||||
{
|
{
|
||||||
@@ -79,7 +90,7 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
OnBeforeLaunchProcess();
|
OnBeforeLaunchProcess();
|
||||||
NodeProcess = Process.Start(startInfo);
|
_nodeProcess = Process.Start(startInfo);
|
||||||
ConnectToInputOutputStreams();
|
ConnectToInputOutputStreams();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +109,7 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
var initializationIsCompleted = false; // TODO: Make this thread-safe? (Interlocked.Exchange etc.)
|
var initializationIsCompleted = false; // TODO: Make this thread-safe? (Interlocked.Exchange etc.)
|
||||||
_nodeProcessIsReadySource = new TaskCompletionSource<bool>();
|
_nodeProcessIsReadySource = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
NodeProcess.OutputDataReceived += (sender, evt) =>
|
_nodeProcess.OutputDataReceived += (sender, evt) =>
|
||||||
{
|
{
|
||||||
if (evt.Data == "[Microsoft.AspNetCore.NodeServices:Listening]" && !initializationIsCompleted)
|
if (evt.Data == "[Microsoft.AspNetCore.NodeServices:Listening]" && !initializationIsCompleted)
|
||||||
{
|
{
|
||||||
@@ -111,7 +122,7 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeProcess.ErrorDataReceived += (sender, evt) =>
|
_nodeProcess.ErrorDataReceived += (sender, evt) =>
|
||||||
{
|
{
|
||||||
if (evt.Data != null)
|
if (evt.Data != null)
|
||||||
{
|
{
|
||||||
@@ -124,8 +135,8 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeProcess.BeginOutputReadLine();
|
_nodeProcess.BeginOutputReadLine();
|
||||||
NodeProcess.BeginErrorReadLine();
|
_nodeProcess.BeginErrorReadLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnBeforeLaunchProcess()
|
protected virtual void OnBeforeLaunchProcess()
|
||||||
@@ -151,9 +162,9 @@ namespace Microsoft.AspNetCore.NodeServices
|
|||||||
_entryPointScript.Dispose();
|
_entryPointScript.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NodeProcess != null && !NodeProcess.HasExited)
|
if (_nodeProcess != null && !_nodeProcess.HasExited)
|
||||||
{
|
{
|
||||||
NodeProcess.Kill();
|
_nodeProcess.Kill();
|
||||||
// TODO: Is there a more graceful way to end it? Or does this still let it perform any cleanup?
|
// TODO: Is there a more graceful way to end it? Or does this still let it perform any cleanup?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
|
|||||||
{
|
{
|
||||||
public JavaScriptModuleExport(string moduleName)
|
public JavaScriptModuleExport(string moduleName)
|
||||||
{
|
{
|
||||||
this.ModuleName = moduleName;
|
ModuleName = moduleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ModuleName { get; private set; }
|
public string ModuleName { get; private set; }
|
||||||
|
|||||||
@@ -17,18 +17,20 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<RenderToStringResult> RenderToString(
|
public static Task<RenderToStringResult> RenderToString(
|
||||||
string applicationBasePath,
|
string applicationBasePath,
|
||||||
INodeServices nodeServices,
|
INodeServices nodeServices,
|
||||||
JavaScriptModuleExport bootModule,
|
JavaScriptModuleExport bootModule,
|
||||||
string requestAbsoluteUrl,
|
string requestAbsoluteUrl,
|
||||||
string requestPathAndQuery)
|
string requestPathAndQuery)
|
||||||
=> await nodeServices.InvokeExport<RenderToStringResult>(
|
{
|
||||||
|
return nodeServices.InvokeExport<RenderToStringResult>(
|
||||||
NodeScript.Value.FileName,
|
NodeScript.Value.FileName,
|
||||||
"renderToString",
|
"renderToString",
|
||||||
applicationBasePath,
|
applicationBasePath,
|
||||||
bootModule,
|
bootModule,
|
||||||
requestAbsoluteUrl,
|
requestAbsoluteUrl,
|
||||||
requestPathAndQuery);
|
requestPathAndQuery);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,9 +24,14 @@ namespace Microsoft.AspNetCore.SpaServices
|
|||||||
string routeKey,
|
string routeKey,
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
=> !HasDotInLastSegment(values[_clientRouteTokenName] as string ?? string.Empty);
|
{
|
||||||
|
return !HasDotInLastSegment(values[_clientRouteTokenName] as string ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
private bool HasDotInLastSegment(string uri)
|
private bool HasDotInLastSegment(string uri)
|
||||||
=> uri.IndexOf('.', uri.LastIndexOf('/') + 1) >= 0;
|
{
|
||||||
|
var lastSegmentStartPos = uri.LastIndexOf('/');
|
||||||
|
return uri.IndexOf('.', lastSegmentStartPos + 1) >= 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,13 +17,15 @@ namespace Microsoft.AspNetCore.Builder
|
|||||||
object defaults,
|
object defaults,
|
||||||
object constraints = null,
|
object constraints = null,
|
||||||
object dataTokens = null)
|
object dataTokens = null)
|
||||||
=> MapSpaFallbackRoute(
|
{
|
||||||
|
MapSpaFallbackRoute(
|
||||||
routeBuilder,
|
routeBuilder,
|
||||||
name,
|
name,
|
||||||
/* templatePrefix */ null,
|
/* templatePrefix */ null,
|
||||||
defaults,
|
defaults,
|
||||||
constraints,
|
constraints,
|
||||||
dataTokens);
|
dataTokens);
|
||||||
|
}
|
||||||
|
|
||||||
public static void MapSpaFallbackRoute(
|
public static void MapSpaFallbackRoute(
|
||||||
this IRouteBuilder routeBuilder,
|
this IRouteBuilder routeBuilder,
|
||||||
@@ -34,7 +36,6 @@ namespace Microsoft.AspNetCore.Builder
|
|||||||
object dataTokens = null)
|
object dataTokens = null)
|
||||||
{
|
{
|
||||||
var template = CreateRouteTemplate(templatePrefix);
|
var template = CreateRouteTemplate(templatePrefix);
|
||||||
|
|
||||||
var constraintsDict = ObjectToDictionary(constraints);
|
var constraintsDict = ObjectToDictionary(constraints);
|
||||||
constraintsDict.Add(ClientRouteTokenName, new SpaRouteConstraint(ClientRouteTokenName));
|
constraintsDict.Add(ClientRouteTokenName, new SpaRouteConstraint(ClientRouteTokenName));
|
||||||
|
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack
|
|||||||
requestMessage.Method = new HttpMethod(context.Request.Method);
|
requestMessage.Method = new HttpMethod(context.Request.Method);
|
||||||
|
|
||||||
using (
|
using (
|
||||||
var responseMessage =
|
var responseMessage = await _httpClient.SendAsync(
|
||||||
await
|
requestMessage,
|
||||||
_httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead,
|
HttpCompletionOption.ResponseHeadersRead,
|
||||||
context.RequestAborted))
|
context.RequestAborted))
|
||||||
{
|
{
|
||||||
if (responseMessage.StatusCode == HttpStatusCode.NotFound)
|
if (responseMessage.StatusCode == HttpStatusCode.NotFound)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -91,4 +91,4 @@ namespace Microsoft.AspNetCore.Builder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user