Compare commits

..

3 Commits

Author SHA1 Message Date
SteveSandersonMS
bd42deef7e Publish templates v0.6.2 2016-11-29 19:12:00 +00:00
SteveSandersonMS
939e0aeee0 Make 'fetchdata' components in templates compatible with latest TypeScript compiler 2016-11-29 19:10:48 +00:00
SteveSandersonMS
28b8136fa6 Detect legacy aspnet-prerendering mode earlier to fix #470 2016-11-29 17:23:14 +00:00
83 changed files with 536 additions and 683 deletions

View File

@@ -2,7 +2,6 @@ versionSuffix=$1
dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
projects=(
./src/Microsoft.AspNetCore.NodeServices
./src/Microsoft.AspNetCore.NodeServices.Sockets
./src/Microsoft.AspNetCore.SpaServices
./src/Microsoft.AspNetCore.AngularServices
./src/Microsoft.AspNetCore.ReactServices

View File

@@ -15,28 +15,28 @@
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.AngularServices": "1.1.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.AngularServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.EntityFrameworkCore.SQLite": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.EntityFrameworkCore.SQLite": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"AutoMapper": "5.0.2"
},
@@ -47,7 +47,7 @@
},
"frameworks": {
"netcoreapp1.1": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"

View File

@@ -3,7 +3,6 @@ using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.NodeServices;
using Microsoft.AspNetCore.NodeServices.Sockets;
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleApplication
@@ -17,10 +16,7 @@ namespace ConsoleApplication
// Set up the DI system
var services = new ServiceCollection();
services.AddNodeServices(options => {
// To compare with Socket hosting, uncomment the following line
// Since .NET Core 1.1, the HTTP hosting model has become basically as fast as the Socket hosting model
//options.UseSocketHosting();
options.HostingModel = NodeServicesOptions.DefaultNodeHostingModel;
options.ProjectPath = Directory.GetCurrentDirectory();
options.WatchFileExtensions = new string[] {}; // Don't watch anything
});

View File

@@ -5,12 +5,11 @@
},
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.NodeServices": "1.1.0-*",
"Microsoft.AspNetCore.NodeServices.Sockets": "1.1.0-*",
"Microsoft.Extensions.DependencyInjection": "1.1.0"
"Microsoft.AspNetCore.NodeServices": "1.0.0-*",
"Microsoft.Extensions.DependencyInjection": "1.0.0"
},
"frameworks": {
"netcoreapp1.0": {

View File

@@ -12,22 +12,29 @@
},
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.AspNetCore.NodeServices": "1.1.0-*"
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.NETCore.Platforms": "1.0.1",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.AspNetCore.NodeServices": "1.0.0-*"
},
"frameworks": {
"netcoreapp1.0": {}
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
]
}
},
"publishExclude": [
"node_modules",

View File

@@ -1,9 +1,6 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
yarn.lock
wwwroot/dist
# User-specific files
*.suo
*.user

View File

@@ -11,10 +11,9 @@
"webpack-hot-middleware": "^2.7.1"
},
"dependencies": {
"aspnet-prerendering": "^1.0.4",
"aspnet-webpack": "^1.0.3",
"aspnet-prerendering": "^1.0.4",
"ts-loader": "^0.8.1",
"typescript": "^2.0.0",
"webpack": "^1.13.3"
"typescript": "^1.7.5"
}
}

View File

@@ -12,22 +12,29 @@
},
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.1.0-*"
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.NETCore.Platforms": "1.0.1",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*"
},
"frameworks": {
"netcoreapp1.0": {}
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
]
}
},
"publishOptions": {
"exclude": [

View File

@@ -2,10 +2,9 @@
"compilerOptions": {
"moduleResolution": "node",
"module": "commonjs",
"target": "es5",
"target": "es6",
"jsx": "preserve",
"sourceMap": true,
"lib": ["es6", "dom"]
"sourceMap": true
},
"exclude": [
"node_modules"

View File

@@ -10,6 +10,6 @@ module.exports = {
},
plugins: [
extractLESS,
new webpack.optimize.UglifyJsPlugin({ minimize: true, compressor: { warnings: false } })
new webpack.optimize.UglifyJsPlugin({ minimize: true })
]
};

View File

@@ -9,6 +9,7 @@
"@types/react-router": "^2.0.30",
"@types/react-router-bootstrap": "^0.0.27",
"@types/react-router-redux": "^4.0.30",
"@types/redux": "3.5.27",
"@types/redux-thunk": "^2.1.28",
"@types/source-map": "^0.1.28",
"@types/uglify-js": "^2.0.27",

View File

@@ -1,28 +1,28 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.ReactServices": "1.1.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.ReactServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.EntityFrameworkCore.SQLite": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.EntityFrameworkCore.SQLite": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"AutoMapper": "5.0.2"
},
@@ -34,7 +34,10 @@
"frameworks": {
"netcoreapp1.0": {
"imports": []
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
},

View File

@@ -10,7 +10,7 @@ module.exports = {
module: {
loaders: [
{ test: /\.ts(x?)$/, include: /ReactApp/, exclude: /node_modules/, loader: 'babel-loader' },
{ test: /\.ts(x?)$/, include: /ReactApp/, exclude: /node_modules/, loader: 'ts-loader?silent' },
{ test: /\.ts(x?)$/, include: /ReactApp/, exclude: /node_modules/, loader: 'ts-loader' },
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader') },
{ test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000' }
]

View File

@@ -9,17 +9,29 @@
},
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.ReactServices": "1.1.0-*",
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0"
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.NETCore.Platforms": "1.0.1",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.AspNetCore.ReactServices": "1.0.0-*"
},
"frameworks": {
"netcoreapp1.0": {}
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
]
}
},
"publishOptions": {
"exclude": [

View File

@@ -1,6 +1,6 @@
{
"description": "Helpers for building Angular 2 applications on ASP.NET Core.",
"version": "1.1.0-*",
"version": "1.0.0-*",
"packOptions": {
"repository": {
"type": "git",
@@ -18,8 +18,8 @@
"xmlDoc": true
},
"dependencies": {
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.1.0-*"
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.1",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*"
},
"frameworks": {
"net451": {},

View File

@@ -1,3 +0,0 @@
/bin/
/node_modules/
yarn.lock

View File

@@ -1,21 +0,0 @@
using System;
namespace Microsoft.AspNetCore.NodeServices.Sockets
{
/// <summary>
/// Extension methods that help with populating a <see cref="NodeServicesOptions"/> object.
/// </summary>
public static class NodeServicesOptionsExtensions
{
/// <summary>
/// Configures the <see cref="INodeServices"/> service so that it will use out-of-process
/// Node.js instances and perform RPC calls over binary sockets (on Windows, this is
/// implemented as named pipes; on other platforms it uses domain sockets).
/// </summary>
public static void UseSocketHosting(this NodeServicesOptions options)
{
var pipeName = "pni-" + Guid.NewGuid().ToString("D"); // Arbitrary non-clashing string
options.NodeInstanceFactory = () => new SocketNodeInstance(options, pipeName);
}
}
}

View File

@@ -1,11 +0,0 @@
{
"compilerOptions": {
"target": "es3",
"module": "commonjs",
"moduleResolution": "node",
"types": ["node"]
},
"exclude": [
"node_modules"
]
}

View File

@@ -1,18 +0,0 @@
{
"name": "nodeservices.sockets",
"version": "1.0.0",
"description": "This is not really an NPM package and will not be published. This file exists only to reference compilation tools.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "./node_modules/.bin/webpack"
},
"author": "Microsoft",
"license": "Apache-2.0",
"devDependencies": {
"@types/node": "^6.0.42",
"ts-loader": "^0.8.2",
"typescript": "^2.0.0",
"webpack": "^1.13.1"
}
}

View File

@@ -1,39 +0,0 @@
{
"description": "Socket-based RPC for Microsoft.AspNetCore.NodeServices",
"version": "1.1.0-*",
"packOptions": {
"repository": {
"type": "git",
"url": "git://github.com/aspnet/javascriptservices"
},
"tags": [
"aspnetcore",
"aspnetcoremvc",
"nodeservices"
]
},
"buildOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk",
"embed": [
"Content/**/*"
],
"xmlDoc": true
},
"dependencies": {
"Microsoft.AspNetCore.NodeServices": "1.1.0-*"
},
"frameworks": {
"net451": {
"dependencies": {
"Microsoft.Tpl.Dataflow": "4.5.24"
}
},
"netstandard1.6": {
"dependencies": {
"System.IO.Pipes": "4.3.0",
"System.Threading.Tasks.Dataflow": "4.7.0"
}
}
}
}

View File

@@ -1,20 +0,0 @@
module.exports = {
target: 'node',
externals: ['fs', 'net', 'events', 'readline', 'stream'],
resolve: {
extensions: [ '.ts' ]
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader' },
]
},
entry: {
'entrypoint-socket': ['./TypeScript/SocketNodeInstanceEntryPoint'],
},
output: {
libraryTarget: 'commonjs',
path: './Content/Node',
filename: '[name].js'
}
};

View File

@@ -1,3 +1,2 @@
/bin/
/node_modules/
yarn.lock

View File

@@ -0,0 +1,18 @@
namespace Microsoft.AspNetCore.NodeServices
{
/// <summary>
/// Represents a way of creating and invoking code in a Node.js environment.
/// </summary>
public enum NodeHostingModel
{
/// <summary>
/// An out-of-process Node.js instance where RPC calls are made via HTTP.
/// </summary>
Http,
/// <summary>
/// An out-of-process Node.js instance where RPC calls are made over binary sockets.
/// </summary>
Socket,
}
}

View File

@@ -1,4 +1,5 @@
using System;
using Microsoft.AspNetCore.NodeServices.HostingModels;
namespace Microsoft.AspNetCore.NodeServices
{
@@ -18,8 +19,33 @@ namespace Microsoft.AspNetCore.NodeServices
{
throw new ArgumentNullException(nameof (options));
}
return new NodeServicesImpl(() => CreateNodeInstance(options));
}
return new NodeServicesImpl(options.NodeInstanceFactory);
private static INodeInstance CreateNodeInstance(NodeServicesOptions options)
{
if (options.NodeInstanceFactory != null)
{
// If you've explicitly supplied an INodeInstance factory, we'll use that. This is useful for
// custom INodeInstance implementations.
return options.NodeInstanceFactory();
}
else
{
switch (options.HostingModel)
{
case NodeHostingModel.Http:
return new HttpNodeInstance(options.ProjectPath, options.WatchFileExtensions, options.NodeInstanceOutputLogger,
options.EnvironmentVariables, options.InvocationTimeoutMilliseconds, options.LaunchWithDebugging, options.DebuggingPort, /* port */ 0);
case NodeHostingModel.Socket:
var pipeName = "pni-" + Guid.NewGuid().ToString("D"); // Arbitrary non-clashing string
return new SocketNodeInstance(options.ProjectPath, options.WatchFileExtensions, pipeName, options.NodeInstanceOutputLogger,
options.EnvironmentVariables, options.InvocationTimeoutMilliseconds, options.LaunchWithDebugging, options.DebuggingPort);
default:
throw new ArgumentException("Unknown hosting model: " + options.HostingModel);
}
}
}
}
}

View File

@@ -13,6 +13,11 @@ namespace Microsoft.AspNetCore.NodeServices
/// </summary>
public class NodeServicesOptions
{
/// <summary>
/// Defines the default <see cref="NodeHostingModel"/>.
/// </summary>
public const NodeHostingModel DefaultNodeHostingModel = NodeHostingModel.Http;
internal const string TimeoutConfigPropertyName = nameof(InvocationTimeoutMilliseconds);
private const int DefaultInvocationTimeoutMilliseconds = 60 * 1000;
private const string LogCategoryName = "Microsoft.AspNetCore.NodeServices";
@@ -31,6 +36,7 @@ namespace Microsoft.AspNetCore.NodeServices
EnvironmentVariables = new Dictionary<string, string>();
InvocationTimeoutMilliseconds = DefaultInvocationTimeoutMilliseconds;
HostingModel = DefaultNodeHostingModel;
WatchFileExtensions = (string[])DefaultWatchFileExtensions.Clone();
// In an ASP.NET environment, we can use the IHostingEnvironment data to auto-populate a few
@@ -47,15 +53,15 @@ namespace Microsoft.AspNetCore.NodeServices
NodeInstanceOutputLogger = loggerFactory != null
? loggerFactory.CreateLogger(LogCategoryName)
: new ConsoleLogger(LogCategoryName, null, false);
// By default, we use this package's built-in out-of-process-via-HTTP hosting/transport
this.UseHttpHosting();
}
/// <summary>
/// Specifies how to construct Node.js instances. An <see cref="INodeInstance"/> encapsulates all details about
/// how Node.js instances are launched and communicated with. A new <see cref="INodeInstance"/> will be created
/// automatically if the previous instance has terminated (e.g., because a source file changed).
/// Specifies which <see cref="NodeHostingModel"/> should be used.
/// </summary>
public NodeHostingModel HostingModel { get; set; }
/// <summary>
/// If set, this callback function will be invoked to supply the <see cref="INodeServices"/> instance.
/// </summary>
public Func<INodeInstance> NodeInstanceFactory { get; set; }

View File

@@ -44,81 +44,11 @@
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module.
__webpack_require__(2);
var net = __webpack_require__(3);
var path = __webpack_require__(4);
var readline = __webpack_require__(5);
var ArgsUtil_1 = __webpack_require__(6);
var ExitWhenParentExits_1 = __webpack_require__(7);
var virtualConnectionServer = __webpack_require__(8);
// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
// reference to Node's runtime 'require' function.
var dynamicRequire = eval('require');
// Signal to the .NET side when we're ready to accept invocations
var server = net.createServer().on('listening', function () {
console.log('[Microsoft.AspNetCore.NodeServices:Listening]');
});
// Each virtual connection represents a separate invocation
virtualConnectionServer.createInterface(server).on('connection', function (connection) {
readline.createInterface(connection, null).on('line', function (line) {
try {
// Get a reference to the function to invoke
var invocation = JSON.parse(line);
var invokedModule = dynamicRequire(path.resolve(process.cwd(), invocation.moduleName));
var invokedFunction = invocation.exportedFunctionName ? invokedModule[invocation.exportedFunctionName] : invokedModule;
// Prepare a callback for accepting non-streamed JSON responses
var hasInvokedCallback_1 = false;
var invocationCallback = function (errorValue, successValue) {
if (hasInvokedCallback_1) {
throw new Error('Cannot supply more than one result. The callback has already been invoked,'
+ ' or the result stream has already been accessed');
}
hasInvokedCallback_1 = true;
connection.end(JSON.stringify({
result: successValue,
errorMessage: errorValue && (errorValue.message || errorValue),
errorDetails: errorValue && (errorValue.stack || null)
}));
};
// Also support streamed binary responses
Object.defineProperty(invocationCallback, 'stream', {
enumerable: true,
get: function () {
hasInvokedCallback_1 = true;
return connection;
}
});
// Actually invoke it, passing through any supplied args
invokedFunction.apply(null, [invocationCallback].concat(invocation.args));
}
catch (ex) {
connection.end(JSON.stringify({
errorMessage: ex.message,
errorDetails: ex.stack
}));
}
});
});
// Begin listening now. The underlying transport varies according to the runtime platform.
// On Windows it's Named Pipes; on Linux/OSX it's Domain Sockets.
var useWindowsNamedPipes = /^win/.test(process.platform);
var parsedArgs = ArgsUtil_1.parseArgs(process.argv);
var listenAddress = (useWindowsNamedPipes ? '\\\\.\\pipe\\' : '/tmp/') + parsedArgs.listenAddress;
server.listen(listenAddress);
ExitWhenParentExits_1.exitWhenParentExits(parseInt(parsedArgs.parentPid));
module.exports = __webpack_require__(7);
/***/ },
/* 1 */,
/* 2 */
/***/ function(module, exports) {
@@ -160,12 +90,7 @@
/***/ },
/* 3 */
/***/ function(module, exports) {
module.exports = require("net");
/***/ },
/* 3 */,
/* 4 */
/***/ function(module, exports) {
@@ -173,12 +98,6 @@
/***/ },
/* 5 */
/***/ function(module, exports) {
module.exports = require("readline");
/***/ },
/* 6 */
/***/ function(module, exports) {
"use strict";
@@ -204,7 +123,7 @@
/***/ },
/* 7 */
/* 6 */
/***/ function(module, exports) {
/*
@@ -271,12 +190,95 @@
/***/ },
/* 8 */
/* 7 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
var events_1 = __webpack_require__(9);
var VirtualConnection_1 = __webpack_require__(10);
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module.
__webpack_require__(2);
var net = __webpack_require__(8);
var path = __webpack_require__(4);
var readline = __webpack_require__(9);
var ArgsUtil_1 = __webpack_require__(5);
var ExitWhenParentExits_1 = __webpack_require__(6);
var virtualConnectionServer = __webpack_require__(10);
// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
// reference to Node's runtime 'require' function.
var dynamicRequire = eval('require');
// Signal to the .NET side when we're ready to accept invocations
var server = net.createServer().on('listening', function () {
console.log('[Microsoft.AspNetCore.NodeServices:Listening]');
});
// Each virtual connection represents a separate invocation
virtualConnectionServer.createInterface(server).on('connection', function (connection) {
readline.createInterface(connection, null).on('line', function (line) {
try {
// Get a reference to the function to invoke
var invocation = JSON.parse(line);
var invokedModule = dynamicRequire(path.resolve(process.cwd(), invocation.moduleName));
var invokedFunction = invocation.exportedFunctionName ? invokedModule[invocation.exportedFunctionName] : invokedModule;
// Prepare a callback for accepting non-streamed JSON responses
var hasInvokedCallback_1 = false;
var invocationCallback = function (errorValue, successValue) {
if (hasInvokedCallback_1) {
throw new Error('Cannot supply more than one result. The callback has already been invoked,'
+ ' or the result stream has already been accessed');
}
hasInvokedCallback_1 = true;
connection.end(JSON.stringify({
result: successValue,
errorMessage: errorValue && (errorValue.message || errorValue),
errorDetails: errorValue && (errorValue.stack || null)
}));
};
// Also support streamed binary responses
Object.defineProperty(invocationCallback, 'stream', {
enumerable: true,
get: function () {
hasInvokedCallback_1 = true;
return connection;
}
});
// Actually invoke it, passing through any supplied args
invokedFunction.apply(null, [invocationCallback].concat(invocation.args));
}
catch (ex) {
connection.end(JSON.stringify({
errorMessage: ex.message,
errorDetails: ex.stack
}));
}
});
});
// Begin listening now. The underlying transport varies according to the runtime platform.
// On Windows it's Named Pipes; on Linux/OSX it's Domain Sockets.
var useWindowsNamedPipes = /^win/.test(process.platform);
var parsedArgs = ArgsUtil_1.parseArgs(process.argv);
var listenAddress = (useWindowsNamedPipes ? '\\\\.\\pipe\\' : '/tmp/') + parsedArgs.listenAddress;
server.listen(listenAddress);
ExitWhenParentExits_1.exitWhenParentExits(parseInt(parsedArgs.parentPid));
/***/ },
/* 8 */
/***/ function(module, exports) {
module.exports = require("net");
/***/ },
/* 9 */
/***/ function(module, exports) {
module.exports = require("readline");
/***/ },
/* 10 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
var events_1 = __webpack_require__(11);
var VirtualConnection_1 = __webpack_require__(12);
// Keep this in sync with the equivalent constant in the .NET code. Both sides split up their transmissions into frames with this max length,
// and both will reject longer frames.
var MaxFrameBodyLength = 16 * 1024;
@@ -458,13 +460,13 @@
/***/ },
/* 9 */
/* 11 */
/***/ function(module, exports) {
module.exports = require("events");
/***/ },
/* 10 */
/* 12 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
@@ -473,18 +475,17 @@
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var stream_1 = __webpack_require__(11);
var stream_1 = __webpack_require__(13);
/**
* Represents a virtual connection. Multiple virtual connections may be multiplexed over a single physical socket connection.
*/
var VirtualConnection = (function (_super) {
__extends(VirtualConnection, _super);
function VirtualConnection(_beginWriteCallback) {
var _this = _super.call(this) || this;
_this._beginWriteCallback = _beginWriteCallback;
_this._flowing = false;
_this._receivedDataQueue = [];
return _this;
_super.call(this);
this._beginWriteCallback = _beginWriteCallback;
this._flowing = false;
this._receivedDataQueue = [];
}
VirtualConnection.prototype._read = function () {
this._flowing = true;
@@ -515,7 +516,7 @@
/***/ },
/* 11 */
/* 13 */
/***/ function(module, exports) {
module.exports = require("stream");

View File

@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
@@ -34,19 +36,21 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
private bool _disposed;
private int _portNumber;
public HttpNodeInstance(NodeServicesOptions options, int port = 0)
public HttpNodeInstance(string projectPath, string[] watchFileExtensions, ILogger nodeInstanceOutputLogger,
IDictionary<string, string> environmentVars, int invocationTimeoutMilliseconds, bool launchWithDebugging,
int debuggingPort, int port = 0)
: base(
EmbeddedResourceReader.Read(
typeof(HttpNodeInstance),
"/Content/Node/entrypoint-http.js"),
options.ProjectPath,
options.WatchFileExtensions,
projectPath,
watchFileExtensions,
MakeCommandLineOptions(port),
options.NodeInstanceOutputLogger,
options.EnvironmentVariables,
options.InvocationTimeoutMilliseconds,
options.LaunchWithDebugging,
options.DebuggingPort)
nodeInstanceOutputLogger,
environmentVars,
invocationTimeoutMilliseconds,
launchWithDebugging,
debuggingPort)
{
_client = new HttpClient();
}

View File

@@ -1,17 +0,0 @@
namespace Microsoft.AspNetCore.NodeServices.HostingModels
{
/// <summary>
/// Extension methods that help with populating a <see cref="NodeServicesOptions"/> object.
/// </summary>
public static class NodeServicesOptionsExtensions
{
/// <summary>
/// Configures the <see cref="INodeServices"/> service so that it will use out-of-process
/// Node.js instances and perform RPC calls over HTTP.
/// </summary>
public static void UseHttpHosting(this NodeServicesOptions options)
{
options.NodeInstanceFactory = () => new HttpNodeInstance(options);
}
}
}

View File

@@ -2,7 +2,7 @@ using System.IO;
using System.IO.Pipes;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.NodeServices.Sockets.PhysicalConnections
namespace Microsoft.AspNetCore.NodeServices.HostingModels.PhysicalConnections
{
internal class NamedPipeConnection : StreamConnection
{

View File

@@ -2,7 +2,7 @@ using System;
using System.IO;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.NodeServices.Sockets.PhysicalConnections
namespace Microsoft.AspNetCore.NodeServices.HostingModels.PhysicalConnections
{
internal abstract class StreamConnection : IDisposable
{

View File

@@ -2,7 +2,7 @@ using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.NodeServices.Sockets.PhysicalConnections
namespace Microsoft.AspNetCore.NodeServices.HostingModels.PhysicalConnections
{
internal class UnixDomainSocketConnection : StreamConnection
{

View File

@@ -3,7 +3,7 @@ using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Microsoft.AspNetCore.NodeServices.Sockets.PhysicalConnections
namespace Microsoft.AspNetCore.NodeServices.HostingModels.PhysicalConnections
{
// From System.IO.Pipes/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs (an internal class in System.IO.Pipes)
internal sealed class UnixDomainSocketEndPoint : EndPoint

View File

@@ -1,15 +1,16 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.NodeServices.HostingModels;
using Microsoft.AspNetCore.NodeServices.Sockets.PhysicalConnections;
using Microsoft.AspNetCore.NodeServices.Sockets.VirtualConnections;
using Microsoft.AspNetCore.NodeServices.HostingModels.PhysicalConnections;
using Microsoft.AspNetCore.NodeServices.HostingModels.VirtualConnections;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Microsoft.AspNetCore.NodeServices.Sockets
namespace Microsoft.AspNetCore.NodeServices.HostingModels
{
/// <summary>
/// A specialisation of the OutOfProcessNodeInstance base class that uses a lightweight binary streaming protocol
@@ -41,19 +42,21 @@ namespace Microsoft.AspNetCore.NodeServices.Sockets
private string _socketAddress;
private VirtualConnectionClient _virtualConnectionClient;
public SocketNodeInstance(NodeServicesOptions options, string socketAddress)
public SocketNodeInstance(string projectPath, string[] watchFileExtensions, string socketAddress,
ILogger nodeInstanceOutputLogger, IDictionary<string, string> environmentVars,
int invocationTimeoutMilliseconds, bool launchWithDebugging, int debuggingPort)
: base(
EmbeddedResourceReader.Read(
typeof(SocketNodeInstance),
"/Content/Node/entrypoint-socket.js"),
options.ProjectPath,
options.WatchFileExtensions,
projectPath,
watchFileExtensions,
MakeNewCommandLineOptions(socketAddress),
options.NodeInstanceOutputLogger,
options.EnvironmentVariables,
options.InvocationTimeoutMilliseconds,
options.LaunchWithDebugging,
options.DebuggingPort)
nodeInstanceOutputLogger,
environmentVars,
invocationTimeoutMilliseconds,
launchWithDebugging,
debuggingPort)
{
_socketAddress = socketAddress;
}
@@ -76,7 +79,7 @@ namespace Microsoft.AspNetCore.NodeServices.Sockets
// wait for the same connection task. There's no reason why the first caller should have the
// special ability to cancel the connection process in a way that would affect subsequent
// callers. So, each caller just independently stops awaiting connection if that call is cancelled.
await ThrowOnCancellation(EnsureVirtualConnectionClientCreated(), cancellationToken);
await EnsureVirtualConnectionClientCreated().OrThrowOnCancellation(cancellationToken);
}
// For each invocation, we open a new virtual connection. This gives an API equivalent to opening a new
@@ -212,17 +215,6 @@ namespace Microsoft.AspNetCore.NodeServices.Sockets
return $"--listenAddress {listenAddress}";
}
private static Task ThrowOnCancellation(Task task, CancellationToken cancellationToken)
{
return task.IsCompleted
? task // If the task is already completed, no need to wrap it in a further layer of task
: task.ContinueWith(
_ => {}, // If the task completes, allow execution to continue
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
#pragma warning disable 649 // These properties are populated via JSON deserialization
private class RpcJsonResponse<TResult>
{

View File

@@ -4,7 +4,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
namespace Microsoft.AspNetCore.NodeServices.Sockets.VirtualConnections
namespace Microsoft.AspNetCore.NodeServices.HostingModels.VirtualConnections
{
/// <summary>
/// A virtual read/write connection, typically to a remote process. Multiple virtual connections can be

View File

@@ -5,7 +5,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.NodeServices.Sockets.VirtualConnections
namespace Microsoft.AspNetCore.NodeServices.HostingModels.VirtualConnections
{
/// <summary>
/// A callback that will be invoked if the <see cref="VirtualConnectionClient"/> encounters a read error.

View File

@@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.NodeServices
return InvokeExportWithPossibleRetryAsync<T>(moduleName, exportedFunctionName, args, /* allowRetry */ true, cancellationToken);
}
private async Task<T> InvokeExportWithPossibleRetryAsync<T>(string moduleName, string exportedFunctionName, object[] args, bool allowRetry, CancellationToken cancellationToken)
public async Task<T> InvokeExportWithPossibleRetryAsync<T>(string moduleName, string exportedFunctionName, object[] args, bool allowRetry, CancellationToken cancellationToken)
{
ThrowAnyOutstandingDelayedDisposalException();
var nodeInstance = GetOrCreateCurrentNodeInstance();

View File

@@ -1,12 +1,12 @@
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module.
import '../../Microsoft.AspNetCore.NodeServices/TypeScript/Util/OverrideStdOutputs';
import './Util/OverrideStdOutputs';
import * as net from 'net';
import * as path from 'path';
import * as readline from 'readline';
import { Duplex } from 'stream';
import { parseArgs } from '../../Microsoft.AspNetCore.NodeServices/TypeScript/Util/ArgsUtil';
import { exitWhenParentExits } from '../../Microsoft.AspNetCore.NodeServices/TypeScript/Util/ExitWhenParentExits';
import { parseArgs } from './Util/ArgsUtil';
import { exitWhenParentExits } from './Util/ExitWhenParentExits';
import * as virtualConnectionServer from './VirtualConnections/VirtualConnectionServer';
// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct

View File

@@ -9,8 +9,6 @@ namespace Microsoft.AspNetCore.NodeServices
public sealed class StringAsTempFile : IDisposable
{
private bool _disposedValue;
private bool _hasDeletedTempFile;
private object _fileDeletionLock = new object();
/// <summary>
/// Create a new instance of <see cref="StringAsTempFile"/>.
@@ -20,18 +18,6 @@ namespace Microsoft.AspNetCore.NodeServices
{
FileName = Path.GetTempFileName();
File.WriteAllText(FileName, content);
// Because .NET finalizers don't reliably run when the process is terminating, also
// add event handlers for other shutdown scenarios.
#if NET451
AppDomain.CurrentDomain.ProcessExit += HandleProcessExit;
AppDomain.CurrentDomain.DomainUnload += HandleProcessExit;
#else
// Note that this still doesn't capture SIGKILL (at least on macOS) - there doesn't
// appear to be a way of doing that. So in that case, the temporary file will be
// left behind.
System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += HandleAssemblyUnloading;
#endif
}
/// <summary>
@@ -54,45 +40,15 @@ namespace Microsoft.AspNetCore.NodeServices
{
if (disposing)
{
// Dispose managed state
#if NET451
AppDomain.CurrentDomain.ProcessExit -= HandleProcessExit;
AppDomain.CurrentDomain.DomainUnload -= HandleProcessExit;
#else
System.Runtime.Loader.AssemblyLoadContext.Default.Unloading -= HandleAssemblyUnloading;
#endif
// Would dispose managed state here, if there was any
}
EnsureTempFileDeleted();
File.Delete(FileName);
_disposedValue = true;
}
}
private void EnsureTempFileDeleted()
{
lock (_fileDeletionLock)
{
if (!_hasDeletedTempFile)
{
File.Delete(FileName);
_hasDeletedTempFile = true;
}
}
}
#if NET451
private void HandleProcessExit(object sender, EventArgs args)
{
EnsureTempFileDeleted();
}
#else
private void HandleAssemblyUnloading(System.Runtime.Loader.AssemblyLoadContext context)
{
EnsureTempFileDeleted();
}
#endif
/// <summary>
/// Implements the finalization part of the IDisposable pattern by calling Dispose(false).
/// </summary>

View File

@@ -1,6 +1,6 @@
{
"description": "Invoke Node.js modules at runtime in ASP.NET Core applications.",
"version": "1.1.0-*",
"version": "1.0.0-*",
"packOptions": {
"repository": {
"type": "git",
@@ -21,18 +21,26 @@
"xmlDoc": true
},
"dependencies": {
"Microsoft.AspNetCore.Hosting.Abstractions": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.AspNetCore.Hosting.Abstractions": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Newtonsoft.Json": "9.0.1",
"NETStandard.Library": "1.6.1-*"
"NETStandard.Library": "1.6.0"
},
"frameworks": {
"net451": {},
"net451": {
"frameworkAssemblies": {
"System.Net.Http": "4.0.0"
},
"dependencies": {
"Microsoft.Tpl.Dataflow": "4.5.24"
}
},
"netstandard1.6": {
"dependencies": {
"System.Diagnostics.Process": "4.3.0",
"System.IO.FileSystem.Watcher": "4.3.0",
"System.Runtime.Loader": "4.3.0"
"System.Diagnostics.Process": "4.1.0",
"System.IO.Pipes": "4.0.0",
"System.Threading.Tasks.Dataflow": "4.6.0"
}
}
},

View File

@@ -10,7 +10,8 @@ module.exports = {
]
},
entry: {
'entrypoint-http': ['./TypeScript/HttpNodeInstanceEntryPoint']
'entrypoint-http': ['./TypeScript/HttpNodeInstanceEntryPoint'],
'entrypoint-socket': ['./TypeScript/SocketNodeInstanceEntryPoint'],
},
output: {
libraryTarget: 'commonjs',

View File

@@ -1,6 +1,6 @@
{
"description": "Helpers for building React applications on ASP.NET Core.",
"version": "1.1.0-*",
"version": "1.0.0-*",
"packOptions": {
"repository": {
"type": "git",
@@ -18,8 +18,8 @@
"xmlDoc": true
},
"dependencies": {
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.1.0-*"
"Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.1",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*"
},
"frameworks": {
"net451": {},

View File

@@ -119,8 +119,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
unencodedAbsoluteUrl,
unencodedPathAndQuery,
CustomDataParameter,
TimeoutMillisecondsParameter,
request.PathBase.ToString());
TimeoutMillisecondsParameter);
if (!string.IsNullOrEmpty(result.RedirectUrl))
{

View File

@@ -30,7 +30,6 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
/// <param name="requestPathAndQuery">The path and query part of the URL of the currently-executing HTTP request. This is supplied to the prerendering code.</param>
/// <param name="customDataParameter">An optional JSON-serializable parameter to be supplied to the prerendering code.</param>
/// <param name="timeoutMilliseconds">The maximum duration to wait for prerendering to complete.</param>
/// <param name="requestPathBase">The PathBase for the currently-executing HTTP request.</param>
/// <returns></returns>
public static Task<RenderToStringResult> RenderToString(
string applicationBasePath,
@@ -39,8 +38,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
string requestAbsoluteUrl,
string requestPathAndQuery,
object customDataParameter,
int timeoutMilliseconds,
string requestPathBase)
int timeoutMilliseconds)
{
return nodeServices.InvokeExportAsync<RenderToStringResult>(
NodeScript.Value.FileName,
@@ -50,8 +48,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
requestAbsoluteUrl,
requestPathAndQuery,
customDataParameter,
timeoutMilliseconds,
requestPathBase);
timeoutMilliseconds);
}
}
}

View File

@@ -48,14 +48,11 @@ Instead, what `SpaServices` offers is ASP.NET Core APIs that know how to invoke
### 1. Enable the asp-prerender-* tag helpers
Make sure you've installed into your project:
Make sure you've installed the `Microsoft.AspNetCore.SpaServices` NuGet package and the `aspnet-prerendering` NPM package. Together these contain the server-side and client-side library code you'll need.
* The `Microsoft.AspNetCore.SpaServices` NuGet package, version 1.1.0-* or later
* The `aspnet-prerendering` NPM package, version 2.0.1 or later
Now go to your `Views/_ViewImports.cshtml` file, and add the following line:
Together these contain the server-side and client-side library code you'll need. Now go to your `Views/_ViewImports.cshtml` file, and add the following line:
@addTagHelper "*, Microsoft.AspNetCore.SpaServices"
@addTagHelper *, Microsoft.AspNetCore.SpaServices
### 2. Use asp-prerender-* in a view
@@ -70,9 +67,7 @@ If you run your application now, and browse to whatever page renders the view yo
Create a JavaScript file at the path matching the `asp-prerender-module` value you specified above. In this example, that means creating a folder called `ClientApp` at the root of your project, and creating a file inside it called `boot-server.js`. Try putting the following into it:
```javascript
var prerendering = require('aspnet-prerendering');
module.exports = prerendering.createServerRenderer(function(params) {
module.exports = function(params) {
return new Promise(function (resolve, reject) {
var result = '<h1>Hello world!</h1>'
+ '<p>Current time in Node is: ' + new Date() + '</p>'
@@ -81,7 +76,7 @@ module.exports = prerendering.createServerRenderer(function(params) {
resolve({ html: result });
});
});
};
```
If you try running your app now, you should see the HTML snippet generated by your JavaScript getting injected into your page.
@@ -103,9 +98,7 @@ For example, in your `cshtml`,
Now in your JavaScript prerendering function, you can access this data by reading `params.data`, e.g.:
```javascript
var prerendering = require('aspnet-prerendering');
module.exports = prerendering.createServerRenderer(function(params) {
module.exports = function(params) {
return new Promise(function (resolve, reject) {
var result = '<h1>Hello world!</h1>'
+ '<p>Is gold user: ' + params.data.isGoldUser + '</p>'
@@ -113,7 +106,7 @@ module.exports = prerendering.createServerRenderer(function(params) {
resolve({ html: result });
});
});
};
```
Notice that the property names are received in JavaScript-style casing (e.g., `isGoldUser`) even though they were sent in C#-style casing (e.g., `IsGoldUser`). This is because of how the JSON serialization is configured by default.
@@ -189,9 +182,7 @@ If you don't already have a `tsconfig.json` file at the root of your project, ad
Now you can delete `ClientApp/boot-server.js`, and in its place, create `ClientApp/boot-server.ts`, containing the TypeScript equivalent of what you had before:
```javascript
import { createServerRenderer } from 'aspnet-prerendering';
export default createServerRenderer(params => {
export default function (params: any): Promise<{ html: string}> {
return new Promise((resolve, reject) => {
const html = `
<h1>Hello world!</h1>
@@ -201,7 +192,7 @@ export default createServerRenderer(params => {
resolve({ html });
});
});
}
```
Finally, run `webpack` on the command line to build `ClientApp/dist/main-server.js`. Then you can tell `SpaServices` to use that file for server-side prerendering. In your MVC view where you use `aspnet-prerender-module`, update the attribute value:

View File

@@ -30,7 +30,6 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack
_pathPrefix = pathPrefix;
_options = options;
_httpClient = new HttpClient(new HttpClientHandler());
_httpClient.Timeout = _options.RequestTimeout;
}
public async Task Invoke(HttpContext context)

View File

@@ -1,20 +1,16 @@
using System;
namespace Microsoft.AspNetCore.SpaServices.Webpack
{
internal class ConditionalProxyMiddlewareOptions
{
public ConditionalProxyMiddlewareOptions(string scheme, string host, string port, TimeSpan requestTimeout)
public ConditionalProxyMiddlewareOptions(string scheme, string host, string port)
{
Scheme = scheme;
Host = host;
Port = port;
RequestTimeout = requestTimeout;
}
public string Scheme { get; }
public string Host { get; }
public string Port { get; }
public TimeSpan RequestTimeout { get; }
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.NodeServices;
using Microsoft.AspNetCore.SpaServices.Webpack;
@@ -8,7 +7,6 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.PlatformAbstractions;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder
{
@@ -17,6 +15,8 @@ namespace Microsoft.AspNetCore.Builder
/// </summary>
public static class WebpackDevMiddleware
{
private const string WebpackDevMiddlewareScheme = "http";
private const string WebpackHotMiddlewareEndpoint = "/__webpack_hmr";
private const string DefaultConfigFile = "webpack.config.js";
/// <summary>
@@ -75,18 +75,12 @@ namespace Microsoft.AspNetCore.Builder
"/Content/Node/webpack-dev-middleware.js");
var nodeScript = new StringAsTempFile(script); // Will be cleaned up on process exit
// Ideally, this would be relative to the application's PathBase (so it could work in virtual directories)
// but it's not clear that such information exists during application startup, as opposed to within the context
// of a request.
var hmrEndpoint = "/__webpack_hmr";
// Tell Node to start the server hosting webpack-dev-middleware
var devServerOptions = new
{
webpackConfigPath = Path.Combine(nodeServicesOptions.ProjectPath, options.ConfigFile ?? DefaultConfigFile),
suppliedOptions = options,
understandsMultiplePublicPaths = true,
hotModuleReplacementEndpointUrl = hmrEndpoint
understandsMultiplePublicPaths = true
};
var devServerInfo =
nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName, "createWebpackDevServer",
@@ -100,30 +94,33 @@ namespace Microsoft.AspNetCore.Builder
}
// Proxy the corresponding requests through ASP.NET and into the Node listener
// Anything under /<publicpath> (e.g., /dist) is proxied as a normal HTTP request with a typical timeout (100s is the default from HttpClient),
// plus /__webpack_hmr is proxied with infinite timeout, because it's an EventSource (long-lived request).
foreach (var publicPath in devServerInfo.PublicPaths)
{
appBuilder.UseProxyToLocalWebpackDevMiddleware(publicPath, devServerInfo.Port, TimeSpan.FromSeconds(100));
}
appBuilder.UseProxyToLocalWebpackDevMiddleware(hmrEndpoint, devServerInfo.Port, Timeout.InfiniteTimeSpan);
}
private static void UseProxyToLocalWebpackDevMiddleware(this IApplicationBuilder appBuilder, string publicPath, int proxyToPort, TimeSpan requestTimeout)
{
// Note that this is hardcoded to make requests to "localhost" regardless of the hostname of the
// server as far as the client is concerned. This is because ConditionalProxyMiddlewareOptions is
// the one making the internal HTTP requests, and it's going to be to some port on this machine
// because aspnet-webpack hosts the dev server there. We can't use the hostname that the client
// sees, because that could be anything (e.g., some upstream load balancer) and we might not be
// able to make outbound requests to it from here.
// Also note that the webpack HMR service always uses HTTP, even if your app server uses HTTPS,
// because the HMR service has no need for HTTPS (the client doesn't see it directly - all traffic
// to it is proxied), and the HMR service couldn't use HTTPS anyway (in general it wouldn't have
// the necessary certificate).
var proxyOptions = new ConditionalProxyMiddlewareOptions(
"http", "localhost", proxyToPort.ToString(), requestTimeout);
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(publicPath, proxyOptions);
var proxyOptions = new ConditionalProxyMiddlewareOptions(WebpackDevMiddlewareScheme,
"localhost", devServerInfo.Port.ToString());
foreach (var publicPath in devServerInfo.PublicPaths)
{
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(publicPath, proxyOptions);
}
// While it would be nice to proxy the /__webpack_hmr requests too, these return an EventStream,
// and the Microsoft.AspNetCore.Proxy code doesn't handle that entirely - it throws an exception after
// a while. So, just serve a 302 for those. But note that we must use the hostname that the client
// sees, not "localhost", so that it works even when you're not running on localhost (e.g., Docker).
appBuilder.Map(WebpackHotMiddlewareEndpoint, builder =>
{
builder.Use(next => ctx =>
{
var hostname = ctx.Request.Host.Host;
ctx.Response.Redirect(
$"{WebpackDevMiddlewareScheme}://{hostname}:{devServerInfo.Port.ToString()}{WebpackHotMiddlewareEndpoint}");
return Task.FromResult(0);
});
});
}
#pragma warning disable CS0649

View File

@@ -1,6 +1,6 @@
{
"name": "aspnet-prerendering",
"version": "2.0.2",
"version": "2.0.0",
"description": "Helpers for server-side rendering of JavaScript applications in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
"main": "index.js",
"scripts": {
@@ -17,7 +17,7 @@
"url": "https://github.com/aspnet/JavaScriptServices.git"
},
"dependencies": {
"domain-task": "^2.0.2"
"domain-task": "^2.0.1"
},
"devDependencies": {
"@types/node": "^6.0.42",

View File

@@ -2,12 +2,13 @@
import * as url from 'url';
import * as path from 'path';
import * as domain from 'domain';
import { run as domainTaskRun, baseUrl as domainTaskBaseUrl } from 'domain-task/main';
import { run as domainTaskRun } from 'domain-task/main';
import { baseUrl } from 'domain-task/fetch';
const defaultTimeoutMilliseconds = 30 * 1000;
export function createServerRenderer(bootFunc: BootFunc): RenderToStringFunc {
const resultFunc = (callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any, overrideTimeoutMilliseconds: number, requestPathBase: string) => {
const resultFunc = (callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any, overrideTimeoutMilliseconds: number) => {
// Prepare a promise that will represent the completion of all domain tasks in this execution context.
// The boot code will wait for this before performing its final render.
let domainTaskCompletionPromiseResolve;
@@ -19,7 +20,6 @@ export function createServerRenderer(bootFunc: BootFunc): RenderToStringFunc {
location: url.parse(requestPathAndQuery),
origin: parsedAbsoluteRequestUrl.protocol + '//' + parsedAbsoluteRequestUrl.host,
url: requestPathAndQuery,
baseUrl: (requestPathBase || '') + '/',
absoluteUrl: absoluteRequestUrl,
domainTasks: domainTaskCompletionPromise,
data: customDataParameter
@@ -33,7 +33,7 @@ export function createServerRenderer(bootFunc: BootFunc): RenderToStringFunc {
bindPromiseContinuationsToDomain(domainTaskCompletionPromise, domain['active']);
// Make the base URL available to the 'domain-tasks/fetch' helper within this execution context
domainTaskBaseUrl(absoluteRequestUrl);
baseUrl(absoluteRequestUrl);
// Begin rendering, and apply a timeout
const bootFuncPromise = bootFunc(params);

View File

@@ -1,5 +1,5 @@
interface RenderToStringFunc {
(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any, overrideTimeoutMilliseconds: number, requestPathBase: string): void;
(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any, overrideTimeoutMilliseconds: number): void;
}
interface RenderToStringCallback {
@@ -23,7 +23,6 @@ interface BootFuncParams {
location: any; // e.g., Location object containing information '/some/path'
origin: string; // e.g., 'https://example.com:1234'
url: string; // e.g., '/some/path'
baseUrl: string; // e.g., '' or '/myVirtualDir'
absoluteUrl: string; // e.g., 'https://example.com:1234/some/path'
domainTasks: Promise<any>;
data: any; // any custom object passed through from .NET

View File

@@ -1,6 +1,6 @@
{
"name": "aspnet-webpack",
"version": "1.0.25",
"version": "1.0.24",
"description": "Helpers for using Webpack in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
"main": "index.js",
"scripts": {

View File

@@ -19,7 +19,6 @@ export interface CreateDevServerCallback {
interface CreateDevServerOptions {
webpackConfigPath: string;
suppliedOptions: DevServerOptions;
hotModuleReplacementEndpointUrl: string;
}
// These are the options configured in C# and then JSON-serialized, hence the C#-style naming
@@ -29,7 +28,7 @@ interface DevServerOptions {
ReactHotModuleReplacement: boolean;
}
function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configuration, enableHotModuleReplacement: boolean, enableReactHotModuleReplacement: boolean, hmrClientEndpoint: string, hmrServerEndpoint: string) {
function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configuration, enableHotModuleReplacement: boolean, enableReactHotModuleReplacement: boolean, hmrEndpoint: string) {
// Build the final Webpack config based on supplied options
if (enableHotModuleReplacement) {
// For this, we only support the key/value config format, not string or string[], since
@@ -45,7 +44,7 @@ function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configurati
// Augment all entry points so they support HMR (unless they already do)
Object.getOwnPropertyNames(entryPoints).forEach(entryPointName => {
const webpackHotMiddlewareEntryPoint = 'webpack-hot-middleware/client';
const webpackHotMiddlewareOptions = `?path=` + encodeURIComponent(hmrClientEndpoint);
const webpackHotMiddlewareOptions = `?path=` + encodeURIComponent(hmrEndpoint);
if (typeof entryPoints[entryPointName] === 'string') {
entryPoints[entryPointName] = [webpackHotMiddlewareEntryPoint + webpackHotMiddlewareOptions, entryPoints[entryPointName]];
} else if (firstIndexOfStringStartingWith(entryPoints[entryPointName], webpackHotMiddlewareEntryPoint) < 0) {
@@ -118,9 +117,7 @@ function attachWebpackDevMiddleware(app: any, webpackConfig: webpack.Configurati
} catch (ex) {
throw new Error('HotModuleReplacement failed because of an error while loading \'webpack-hot-middleware\'. Error was: ' + ex.stack);
}
app.use(webpackHotMiddlewareModule(compiler, {
path: hmrServerEndpoint
}));
app.use(webpackHotMiddlewareModule(compiler));
}
}
@@ -201,16 +198,8 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option
}
normalizedPublicPaths.push(removeTrailingSlash(publicPath));
// Newer versions of Microsoft.AspNetCore.SpaServices will explicitly pass an HMR endpoint URL
// (because it's relative to the app's URL space root, which the client doesn't otherwise know).
// For back-compatibility, fall back on connecting directly to the underlying HMR server (though
// that won't work if the app is hosted on HTTPS because of the mixed-content rule, and we can't
// run the HMR server itself on HTTPS because in general it has no valid cert).
const hmrClientEndpoint = options.hotModuleReplacementEndpointUrl // The URL that we'll proxy (e.g., /__asp_webpack_hmr)
|| `http://localhost:${listener.address().port}/__webpack_hmr`; // Fall back on absolute URL to bypass proxying
const hmrServerEndpoint = options.hotModuleReplacementEndpointUrl
|| '/__webpack_hmr'; // URL is relative to webpack dev server root
attachWebpackDevMiddleware(app, webpackConfig, enableHotModuleReplacement, enableReactHotModuleReplacement, hmrClientEndpoint, hmrServerEndpoint);
const hmrEndpoint = `http://localhost:${listener.address().port}/__webpack_hmr`;
attachWebpackDevMiddleware(app, webpackConfig, enableHotModuleReplacement, enableReactHotModuleReplacement, hmrEndpoint);
}
});

View File

@@ -1,6 +1,6 @@
{
"name": "domain-task",
"version": "2.0.2",
"version": "2.0.1",
"description": "Tracks outstanding operations for a logical thread of execution",
"main": "index.js",
"scripts": {

View File

@@ -1,10 +1,13 @@
import * as url from 'url';
import * as domain from 'domain';
import * as domainContext from 'domain-context';
import { baseUrl } from './main';
const isomorphicFetch = require('isomorphic-fetch');
const isNode = typeof process === 'object' && process.versions && !!process.versions.node;
// Not using a symbol, because this may need to run in a version of Node.js that doesn't support them
const domainTaskStateKey = '__DOMAIN_TASK_INTERNAL_FETCH_BASEURL__DO_NOT_REFERENCE_THIS__';
let noDomainBaseUrl: string;
function issueRequest(baseUrl: string, req: string | Request, init?: RequestInit): Promise<any> {
// Resolve relative URLs
if (baseUrl) {
@@ -67,6 +70,16 @@ export function fetch(url: string | Request, init?: RequestInit): Promise<any> {
return issueRequest(baseUrl(), url, init);
}
// Re-exporting baseUrl from this module for back-compatibility only
// Newer code that wants to access baseUrl should use the version exported from the root of this package
export { baseUrl } from './main';
export function baseUrl(url?: string): string {
if (url) {
if (domain.active) {
// There's an active domain (e.g., in Node.js), so associate the base URL with it
domainContext.set(domainTaskStateKey, url);
} else {
// There's no active domain (e.g., in browser), so there's just one shared base URL
noDomainBaseUrl = url;
}
}
return domain.active ? domainContext.get(domainTaskStateKey) : noDomainBaseUrl;
}

View File

@@ -1,3 +1,3 @@
// This file determines the top-level package exports
export { addTask, run, baseUrl } from './main';
export { addTask, run } from './main';
export { fetch } from './fetch';

View File

@@ -1,11 +1,6 @@
import * as domain from 'domain';
import * as domainContext from 'domain-context';
// Not using symbols, because this may need to run in a version of Node.js that doesn't support them
const domainTasksStateKey = '__DOMAIN_TASKS';
const domainTaskBaseUrlStateKey = '__DOMAIN_TASK_INTERNAL_FETCH_BASEURL__DO_NOT_REFERENCE_THIS__';
let noDomainBaseUrl: string;
export function addTask(task: PromiseLike<any>) {
if (task && domain.active) {
@@ -62,20 +57,6 @@ export function run<T>(codeToRun: () => T, completionCallback: (error: any) => v
return synchronousResult;
}
export function baseUrl(url?: string): string {
if (url) {
if (domain.active) {
// There's an active domain (e.g., in Node.js), so associate the base URL with it
domainContext.set(domainTaskBaseUrlStateKey, url);
} else {
// There's no active domain (e.g., in browser), so there's just one shared base URL
noDomainBaseUrl = url;
}
}
return domain.active ? domainContext.get(domainTaskBaseUrlStateKey) : noDomainBaseUrl;
}
interface DomainTasksState {
numRemainingTasks: number;
hasIssuedSuccessCallback: boolean;

View File

@@ -1,6 +1,6 @@
{
"description": "Helpers for building single-page applications on ASP.NET MVC Core",
"version": "1.1.0-*",
"version": "1.0.0-*",
"packOptions": {
"repository": {
"type": "git",
@@ -21,8 +21,8 @@
"xmlDoc": true
},
"dependencies": {
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.NodeServices": "1.1.0-*"
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.NodeServices": "1.0.0-*"
},
"frameworks": {
"net451": {},

View File

@@ -5,7 +5,7 @@ import { AppComponent } from './components/app/app.component'
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { FetchDataComponent } from './components/fetchdata/fetchdata.component';
import { CounterComponent } from 'ClientApp/app/components/counter/counter.component';
import { CounterComponent } from './components/counter/counter.component';
@NgModule({
bootstrap: [ AppComponent ],

View File

@@ -1,16 +1,17 @@
FROM microsoft/dotnet:1.1.0-sdk-projectjson
FROM microsoft/dotnet:1.0.0-preview2-onbuild
RUN apt-get update
RUN wget -qO- https://deb.nodesource.com/setup_4.x | bash -
RUN apt-get install -y build-essential nodejs
COPY . /app
WORKDIR /app
COPY project.json .
RUN ["dotnet", "restore"]
COPY . /app
RUN ["dotnet", "build"]
EXPOSE 5000/tcp
CMD ["dotnet", "run", "--server.urls", "http://*:5000"]
ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"]

View File

@@ -1,3 +1,3 @@
{
"sdk": { "version": "1.0.0-preview2-1-003177" }
"sdk": { "version": "1.0.0-preview2-003121" }
}

View File

@@ -27,7 +27,7 @@
"es6-shim": "^0.35.1",
"event-source-polyfill": "^0.0.7",
"expose-loader": "^0.7.1",
"extract-text-webpack-plugin": "^2.0.0-beta",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.9.0",
"html-loader": "^0.4.4",
"isomorphic-fetch": "^2.2.1",
@@ -39,10 +39,10 @@
"rxjs": "5.0.0-beta.12",
"style-loader": "^0.13.1",
"to-string-loader": "^1.1.5",
"ts-loader": "^1.3.0",
"typescript": "^2.1.0",
"ts-loader": "^0.8.2",
"typescript": "^2.0.3",
"url-loader": "^0.5.7",
"webpack": "^2.1.0-beta",
"webpack": "^1.13.2",
"webpack-hot-middleware": "^2.12.2",
"webpack-merge": "^0.14.1",
"zone.js": "^0.6.25"

View File

@@ -1,26 +1,26 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.AngularServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.1.0-*",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0"
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
},
"tools": {
@@ -30,7 +30,7 @@
},
"frameworks": {
"netcoreapp1.1": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"

View File

@@ -1,11 +1,5 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": [
"*"
]
},
"moduleResolution": "node",
"target": "es5",
"sourceMap": true,

View File

@@ -6,13 +6,7 @@ var merge = require('webpack-merge');
// Configuration in common to both client-side and server-side bundles
var sharedConfig = {
context: __dirname,
resolve: {
extensions: [ '.js', '.ts' ],
modules: [
'node_modules',
'.'
]
},
resolve: { extensions: [ '', '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
@@ -52,7 +46,7 @@ var clientBundleConfig = merge(sharedConfig, {
// Configuration for server-side (prerendering) bundle suitable for running in Node
var serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
resolve: { packageMains: ['main'] },
entry: { 'main-server': './ClientApp/boot-server.ts' },
plugins: [
new webpack.DllReferencePlugin({

View File

@@ -6,7 +6,7 @@ var merge = require('webpack-merge');
var extractCSS = new ExtractTextPlugin('vendor.css');
var sharedConfig = {
resolve: { extensions: [ '.js' ] },
resolve: { extensions: [ '', '.js' ] },
module: {
loaders: [
{ test: /\.json$/, loader: require.resolve('json-loader') },
@@ -68,7 +68,7 @@ var clientBundleConfig = merge(sharedConfig, {
var serverBundleConfig = merge(sharedConfig, {
target: 'node',
resolve: { mainFields: ['main'] },
resolve: { packageMains: ['main'] },
output: {
path: path.join(__dirname, 'ClientApp', 'dist'),
libraryTarget: 'commonjs2',

View File

@@ -1,16 +1,17 @@
FROM microsoft/dotnet:1.1.0-sdk-projectjson
FROM microsoft/dotnet:1.0.0-preview2-onbuild
RUN apt-get update
RUN wget -qO- https://deb.nodesource.com/setup_4.x | bash -
RUN apt-get install -y build-essential nodejs
COPY . /app
WORKDIR /app
COPY project.json .
RUN ["dotnet", "restore"]
COPY . /app
RUN ["dotnet", "build"]
EXPOSE 5000/tcp
CMD ["dotnet", "run", "--server.urls", "http://*:5000"]
ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"]

View File

@@ -1,3 +1,3 @@
{
"sdk": { "version": "1.0.0-preview2-1-003177" }
"sdk": { "version": "1.0.0-preview2-003121" }
}

View File

@@ -1,26 +1,26 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.SpaServices": "1.1.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0"
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
},
"tools": {
@@ -30,7 +30,7 @@
},
"frameworks": {
"netcoreapp1.1": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
@@ -40,10 +40,7 @@
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true,
"compile": {
"exclude": ["node_modules"]
}
"preserveCompilationContext": true
},
"runtimeOptions": {
@@ -55,12 +52,10 @@
"publishOptions": {
"include": [
"appsettings.json",
"ClientApp/dist",
"Views",
"web.config",
"wwwroot"
],
"exclude": [
"wwwroot/dist/*.map"
]
},
@@ -70,7 +65,7 @@
"node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod",
"node node_modules/webpack/bin/webpack.js --env.prod"
],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
"postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
},
"tooling": {

View File

@@ -1,16 +1,17 @@
FROM microsoft/dotnet:1.1.0-sdk-projectjson
FROM microsoft/dotnet:latest
RUN apt-get update
RUN wget -qO- https://deb.nodesource.com/setup_4.x | bash -
RUN apt-get install -y build-essential nodejs
COPY . /app
WORKDIR /app
COPY project.json .
RUN ["dotnet", "restore"]
COPY . /app
RUN ["dotnet", "build"]
EXPOSE 5000/tcp
CMD ["dotnet", "run", "--server.urls", "http://*:5000"]
ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"]

View File

@@ -1,3 +1,3 @@
{
"sdk": { "version": "1.0.0-preview2-1-003177" }
"sdk": { "version": "1.0.0-preview2-003121" }
}

View File

@@ -1,26 +1,26 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.SpaServices": "1.1.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0"
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
},
"tools": {
@@ -30,7 +30,7 @@
},
"frameworks": {
"netcoreapp1.1": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
@@ -55,6 +55,7 @@
"publishOptions": {
"include": [
"appsettings.json",
"node_modules",
"Views",
"web.config",
"wwwroot"

View File

@@ -1,16 +1,17 @@
FROM microsoft/dotnet:1.1.0-sdk-projectjson
FROM microsoft/dotnet:latest
RUN apt-get update
RUN wget -qO- https://deb.nodesource.com/setup_4.x | bash -
RUN apt-get install -y build-essential nodejs
COPY . /app
WORKDIR /app
COPY project.json .
RUN ["dotnet", "restore"]
COPY . /app
RUN ["dotnet", "build"]
EXPOSE 5000/tcp
CMD ["dotnet", "run", "--server.urls", "http://*:5000"]
ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"]

View File

@@ -1,3 +1,3 @@
{
"sdk": { "version": "1.0.0-preview2-1-003177" }
"sdk": { "version": "1.0.0-preview2-003121" }
}

View File

@@ -1,26 +1,26 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.ReactServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.1.0-*",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0"
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
},
"tools": {
@@ -30,7 +30,7 @@
},
"frameworks": {
"netcoreapp1.1": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"

View File

@@ -1,16 +1,17 @@
FROM microsoft/dotnet:1.1.0-sdk-projectjson
FROM microsoft/dotnet:latest
RUN apt-get update
RUN wget -qO- https://deb.nodesource.com/setup_4.x | bash -
RUN apt-get install -y build-essential nodejs
COPY . /app
WORKDIR /app
COPY project.json .
RUN ["dotnet", "restore"]
COPY . /app
RUN ["dotnet", "build"]
EXPOSE 5000/tcp
CMD ["dotnet", "run", "--server.urls", "http://*:5000"]
ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"]

View File

@@ -1,3 +1,3 @@
{
"sdk": { "version": "1.0.0-preview2-1-003177" }
"sdk": { "version": "1.0.0-preview2-003121" }
}

View File

@@ -1,26 +1,26 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.ReactServices": "1.0.0-*",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.1.0-*",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0"
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
},
"tools": {
@@ -30,7 +30,7 @@
},
"frameworks": {
"netcoreapp1.1": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
@@ -55,6 +55,7 @@
"publishOptions": {
"include": [
"appsettings.json",
"node_modules",
"Views",
"web.config",
"wwwroot"

View File

@@ -1,12 +1,13 @@
FROM microsoft/dotnet:1.1.0-sdk-projectjson
COPY . /app
FROM microsoft/dotnet:latest
WORKDIR /app
COPY project.json .
RUN ["dotnet", "restore"]
COPY . /app
RUN ["dotnet", "build"]
EXPOSE 5000/tcp
CMD ["dotnet", "run", "--server.urls", "http://*:5000"]
ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"]

View File

@@ -1,3 +1,3 @@
{
"sdk": { "version": "1.0.0-preview2-1-003177" }
"sdk": { "version": "1.0.0-preview2-003121" }
}

View File

@@ -1,25 +1,25 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0"
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
},
"tools": {
@@ -28,7 +28,7 @@
},
"frameworks": {
"netcoreapp1.1": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"

View File

@@ -1,6 +1,6 @@
{
"name": "generator-aspnetcore-spa",
"version": "0.7.1",
"version": "0.6.2",
"description": "Single-Page App templates for ASP.NET Core",
"author": "Microsoft",
"license": "Apache-2.0",