diff --git a/README.md b/README.md index ed2f172..85dd692 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,22 @@ Everything here is cross-platform, and works with .NET Core 1.0 RC2 or later on ## Creating new applications -If you want to build a brand-new ASP.NET Core app that uses Angular 2 / React / Knockout on the client, consider starting with the `aspnetcore-spa` generator. This lets you choose your client-side framework, and generates a starting point that includes applicable features such as Webpack dev middleware, server-side prerendering, and efficient production builds. +If you want to build a brand-new ASP.NET Core app that uses Angular 2 / React / Knockout on the client, consider starting with the `aspnetcore-spa` generator. This lets you choose your client-side framework, and generates a starting point that includes applicable features such as Webpack dev middleware, server-side prerendering, and efficient production builds. It's much easier than configuring everything to work together manually! -See: [getting started with the `aspnetcore-spa` generator](http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/). It's much easier than configuring everything to work together manually! +To do this, first install Yeoman and these generator templates: + npm install -g yo generator-aspnetcore-spa + +Then you can generate your new application starting point: + + cd some-empty-directory + yo aspnetcore-spa + +Finally, once the generator has run and restored all the dependencies, you can start up your new ASP.NET Core Single Page Application: + + dotnet run + +For a more detailed walkthrough, see [getting started with the `aspnetcore-spa` generator](http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/). ## Adding to existing applications diff --git a/src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs b/src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs index bbae3d2..6ecd43f 100644 --- a/src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs +++ b/src/Microsoft.AspNetCore.NodeServices/Configuration/Configuration.cs @@ -68,10 +68,12 @@ namespace Microsoft.AspNetCore.NodeServices switch (options.HostingModel) { case NodeHostingModel.Http: - return new HttpNodeInstance(options.ProjectPath, options.WatchFileExtensions, logger, /* port */ 0); + return new HttpNodeInstance(options.ProjectPath, options.WatchFileExtensions, logger, + 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, logger); + return new SocketNodeInstance(options.ProjectPath, options.WatchFileExtensions, pipeName, logger, + options.LaunchWithDebugging, options.DebuggingPort); default: throw new ArgumentException("Unknown hosting model: " + options.HostingModel); } diff --git a/src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs b/src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs index 98c50ec..5e6f518 100644 --- a/src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs +++ b/src/Microsoft.AspNetCore.NodeServices/Configuration/NodeServicesOptions.cs @@ -21,5 +21,7 @@ namespace Microsoft.AspNetCore.NodeServices public string ProjectPath { get; set; } public string[] WatchFileExtensions { get; set; } public ILogger NodeInstanceOutputLogger { get; set; } + public bool LaunchWithDebugging { get; set; } + public int? DebuggingPort { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs b/src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs index 53dabf9..0e828ea 100644 --- a/src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs +++ b/src/Microsoft.AspNetCore.NodeServices/HostingModels/HttpNodeInstance.cs @@ -33,15 +33,18 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels private bool _disposed; private int _portNumber; - public HttpNodeInstance(string projectPath, string[] watchFileExtensions, ILogger nodeInstanceOutputLogger, int port = 0) - : base( + public HttpNodeInstance(string projectPath, string[] watchFileExtensions, ILogger nodeInstanceOutputLogger, + bool launchWithDebugging, int? debuggingPort, int port = 0) + : base( EmbeddedResourceReader.Read( typeof(HttpNodeInstance), "/Content/Node/entrypoint-http.js"), projectPath, watchFileExtensions, MakeCommandLineOptions(port), - nodeInstanceOutputLogger) + nodeInstanceOutputLogger, + launchWithDebugging, + debuggingPort) { _client = new HttpClient(); } diff --git a/src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs b/src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs index 0664999..3c9cfd5 100644 --- a/src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs +++ b/src/Microsoft.AspNetCore.NodeServices/HostingModels/OutOfProcessNodeInstance.cs @@ -21,11 +21,22 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels { protected readonly ILogger OutputLogger; private const string ConnectionEstablishedMessage = "[Microsoft.AspNetCore.NodeServices:Listening]"; + private const string DebuggingStartedMessageFormat = @"----- +*** Node.js debugging is enabled *** +{0} + +To debug, run: + node-inspector{1} + +If you haven't yet installed node-inspector, you can do so as follows: + npm install -g node-inspector +-----"; private readonly TaskCompletionSource _connectionIsReadySource = new TaskCompletionSource(); private bool _disposed; private readonly StringAsTempFile _entryPointScript; private FileSystemWatcher _fileSystemWatcher; private readonly Process _nodeProcess; + private int? _nodeDebuggingPort; private bool _nodeProcessNeedsRestart; private readonly string[] _watchFileExtensions; @@ -34,7 +45,9 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels string projectPath, string[] watchFileExtensions, string commandLineArguments, - ILogger nodeOutputLogger) + ILogger nodeOutputLogger, + bool launchWithDebugging, + int? debuggingPort) { if (nodeOutputLogger == null) { @@ -43,8 +56,9 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels OutputLogger = nodeOutputLogger; _entryPointScript = new StringAsTempFile(entryPointScript); - - var startInfo = PrepareNodeProcessStartInfo(_entryPointScript.FileName, projectPath, commandLineArguments); + + var startInfo = PrepareNodeProcessStartInfo(_entryPointScript.FileName, projectPath, commandLineArguments, + launchWithDebugging, debuggingPort); _nodeProcess = LaunchNodeProcess(startInfo); _watchFileExtensions = watchFileExtensions; _fileSystemWatcher = BeginFileWatcher(projectPath); @@ -84,11 +98,23 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels // This method is virtual, as it provides a way to override the NODE_PATH or the path to node.exe protected virtual ProcessStartInfo PrepareNodeProcessStartInfo( - string entryPointFilename, string projectPath, string commandLineArguments) + string entryPointFilename, string projectPath, string commandLineArguments, + bool launchWithDebugging, int? debuggingPort) { + string debuggingArgs; + if (launchWithDebugging) + { + debuggingArgs = debuggingPort.HasValue ? $"--debug={debuggingPort.Value} " : "--debug "; + _nodeDebuggingPort = debuggingPort; + } + else + { + debuggingArgs = string.Empty; + } + var startInfo = new ProcessStartInfo("node") { - Arguments = "\"" + entryPointFilename + "\" " + (commandLineArguments ?? string.Empty), + Arguments = debuggingArgs + "\"" + entryPointFilename + "\" " + (commandLineArguments ?? string.Empty), UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, @@ -100,7 +126,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels var existingNodePath = Environment.GetEnvironmentVariable("NODE_PATH") ?? string.Empty; if (existingNodePath != string.Empty) { - existingNodePath += ":"; + existingNodePath += Path.PathSeparator; } var nodePathValue = existingNodePath + Path.Combine(projectPath, "node_modules"); @@ -201,7 +227,12 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels { if (evt.Data != null) { - if (!initializationIsCompleted) + if (IsDebuggerListeningMessage(evt.Data)) + { + var debugPortArg = _nodeDebuggingPort.HasValue ? $" --debug-port={_nodeDebuggingPort.Value}" : string.Empty; + OutputLogger.LogWarning(string.Format(DebuggingStartedMessageFormat, evt.Data, debugPortArg)); + } + else if (!initializationIsCompleted) { _connectionIsReadySource.SetException( new InvalidOperationException("The Node.js process failed to initialize: " + evt.Data)); @@ -218,6 +249,11 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels _nodeProcess.BeginErrorReadLine(); } + private static bool IsDebuggerListeningMessage(string message) + { + return message.StartsWith("Debugger listening ", StringComparison.OrdinalIgnoreCase); + } + private FileSystemWatcher BeginFileWatcher(string rootDir) { if (_watchFileExtensions == null || _watchFileExtensions.Length == 0) diff --git a/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs b/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs index f5bbce1..5f3a6ec 100644 --- a/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs +++ b/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs @@ -37,14 +37,18 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels private string _socketAddress; private VirtualConnectionClient _virtualConnectionClient; - public SocketNodeInstance(string projectPath, string[] watchFileExtensions, string socketAddress, ILogger nodeInstanceOutputLogger) : base( + public SocketNodeInstance(string projectPath, string[] watchFileExtensions, string socketAddress, + ILogger nodeInstanceOutputLogger, bool launchWithDebugging, int? debuggingPort) + : base( EmbeddedResourceReader.Read( typeof(SocketNodeInstance), "/Content/Node/entrypoint-socket.js"), projectPath, watchFileExtensions, MakeNewCommandLineOptions(socketAddress), - nodeInstanceOutputLogger) + nodeInstanceOutputLogger, + launchWithDebugging, + debuggingPort) { _socketAddress = socketAddress; } diff --git a/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs b/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs index 959ee46..a9398d7 100644 --- a/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs +++ b/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddleware.cs @@ -15,7 +15,6 @@ namespace Microsoft.AspNetCore.Builder public static class WebpackDevMiddleware { private const string WebpackDevMiddlewareScheme = "http"; - private const string WebpackDevMiddlewareHostname = "localhost"; private const string WebpackHotMiddlewareEndpoint = "/__webpack_hmr"; private const string DefaultConfigFile = "webpack.config.js"; @@ -64,19 +63,27 @@ namespace Microsoft.AspNetCore.Builder JsonConvert.SerializeObject(devServerOptions)).Result; // Proxy the corresponding requests through ASP.NET and into the Node listener + // 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. var proxyOptions = new ConditionalProxyMiddlewareOptions(WebpackDevMiddlewareScheme, - WebpackDevMiddlewareHostname, devServerInfo.Port.ToString()); + "localhost", devServerInfo.Port.ToString()); appBuilder.UseMiddleware(devServerInfo.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. + // 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 => async ctx => { + var hostname = ctx.Request.Host.Host; ctx.Response.Redirect( - $"{WebpackDevMiddlewareScheme}://{WebpackDevMiddlewareHostname}:{devServerInfo.Port.ToString()}{WebpackHotMiddlewareEndpoint}"); + $"{WebpackDevMiddlewareScheme}://{hostname}:{devServerInfo.Port.ToString()}{WebpackHotMiddlewareEndpoint}"); await Task.Yield(); }); }); diff --git a/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddlewareOptions.cs b/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddlewareOptions.cs index 08a6dbd..fcdde44 100644 --- a/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddlewareOptions.cs +++ b/src/Microsoft.AspNetCore.SpaServices/Webpack/WebpackDevMiddlewareOptions.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack public class WebpackDevMiddlewareOptions { public bool HotModuleReplacement { get; set; } + public int HotModuleReplacementServerPort { get; set; } public bool ReactHotModuleReplacement { get; set; } public string ConfigFile { get; set; } } diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json index 6ff72aa..8980b92 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/package.json @@ -1,6 +1,6 @@ { "name": "aspnet-webpack", - "version": "1.0.6", + "version": "1.0.9", "description": "Helpers for using Webpack in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.", "main": "index.js", "scripts": { diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/LoadViaWebpack.ts b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/LoadViaWebpack.ts index a6f6fa7..c41d7e8 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/LoadViaWebpack.ts +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/LoadViaWebpack.ts @@ -35,6 +35,12 @@ export function loadViaWebpack(webpackConfigPath: string, modulePath: string, }) } +function setExtension(filePath: string, newExtension: string) { + const oldExtensionIfAny = path.extname(filePath); + const basenameWithoutExtension = path.basename(filePath, oldExtensionIfAny); + return path.join(path.dirname(filePath), basenameWithoutExtension) + newExtension; +} + function loadViaWebpackNoCache(webpackConfigPath: string, modulePath: string) { return new Promise((resolve, reject) => { // Load the Webpack config and make alterations needed for loading the output into Node @@ -94,8 +100,13 @@ function loadViaWebpackNoCache(webpackConfigPath: string, modulePath: string) + stats.toString({ chunks: false })); } + // The dynamically-built module will only appear in node-inspector if it has some nonempty + // file path. The following value is arbitrary (since there's no real compiled file on disk) + // but is sufficient to enable debugging. + const fakeModulePath = setExtension(modulePath, '.js'); + const fileContent = compiler.outputFileSystem.readFileSync(outputVirtualPath, 'utf8'); - const moduleInstance = requireFromString(fileContent); + const moduleInstance = requireFromString(fileContent, fakeModulePath); resolve(moduleInstance); } catch(ex) { reject(ex); diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts index e33433f..f34eefd 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/WebpackDevMiddleware.ts @@ -16,6 +16,7 @@ interface CreateDevServerOptions { // These are the options configured in C# and then JSON-serialized, hence the C#-style naming interface DevServerOptions { HotModuleReplacement: boolean; + HotModuleReplacementServerPort: number; ReactHotModuleReplacement: boolean; } @@ -35,9 +36,11 @@ export function createWebpackDevServer(callback: CreateDevServerCallback, option return; } + // The default value, 0, means 'choose randomly' + const suggestedHMRPortOrZero = options.suppliedOptions.HotModuleReplacementServerPort || 0; + const app = connect(); - const defaultPort = 0; // 0 means 'choose randomly'. Could allow an explicit value to be supplied instead. - const listener = app.listen(defaultPort, () => { + const listener = app.listen(suggestedHMRPortOrZero, () => { // Build the final Webpack config based on supplied options if (enableHotModuleReplacement) { // TODO: Stop assuming there's an entry point called 'main' diff --git a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/typings/require-from-string.d.ts b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/typings/require-from-string.d.ts index 80e4645..ba41884 100644 --- a/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/typings/require-from-string.d.ts +++ b/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/typings/require-from-string.d.ts @@ -1,3 +1,3 @@ export namespace requirefromstring { - export function requireFromString(fileContent: string): T; + export function requireFromString(fileContent: string, filename?: string): T; } diff --git a/templates/Angular2Spa/ClientApp/boot-client.ts b/templates/Angular2Spa/ClientApp/boot-client.ts index be3ca22..d19ff24 100644 --- a/templates/Angular2Spa/ClientApp/boot-client.ts +++ b/templates/Angular2Spa/ClientApp/boot-client.ts @@ -1,3 +1,4 @@ +import 'es6-shim'; require('zone.js'); import 'bootstrap'; import 'reflect-metadata'; diff --git a/templates/Angular2Spa/ClientApp/routes.ts b/templates/Angular2Spa/ClientApp/routes.ts index d693c44..c0a45b7 100644 --- a/templates/Angular2Spa/ClientApp/routes.ts +++ b/templates/Angular2Spa/ClientApp/routes.ts @@ -4,7 +4,7 @@ import { FetchData } from './components/fetch-data/fetch-data'; import { Counter } from './components/counter/counter'; export const routes: RouterConfig = [ - { path: '', redirectTo: 'home' }, + { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'home', component: Home }, { path: 'counter', component: Counter }, { path: 'fetch-data', component: FetchData }, diff --git a/templates/Angular2Spa/Dockerfile b/templates/Angular2Spa/Dockerfile index 63d7c45..b828f96 100644 --- a/templates/Angular2Spa/Dockerfile +++ b/templates/Angular2Spa/Dockerfile @@ -1,11 +1,16 @@ -FROM microsoft/aspnet:1.0.0-rc1-update1 +FROM microsoft/dotnet:latest -RUN printf "deb http://ftp.us.debian.org/debian jessie main\n" >> /etc/apt/sources.list -RUN apt-get -qq update && apt-get install -qqy sqlite3 libsqlite3-dev && rm -rf /var/lib/apt/lists/* +RUN apt-get update +RUN apt-get install -y build-essential nodejs nodejs-legacy + +WORKDIR /app + +COPY project.json . +RUN ["dotnet", "restore"] COPY . /app -WORKDIR /app -RUN ["dnu", "restore"] +RUN ["dotnet", "build"] EXPOSE 5000/tcp -ENTRYPOINT ["dnx", "-p", "project.json", "web"] + +ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"] diff --git a/templates/Angular2Spa/Program.cs b/templates/Angular2Spa/Program.cs new file mode 100644 index 0000000..b2e5e4b --- /dev/null +++ b/templates/Angular2Spa/Program.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; + +namespace WebApplicationBasic +{ + public class Program + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder() + .AddCommandLine(args) + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .Build(); + + var host = new WebHostBuilder() + .UseConfiguration(config) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/templates/Angular2Spa/Startup.cs b/templates/Angular2Spa/Startup.cs index 0c5cc48..e5d73ed 100755 --- a/templates/Angular2Spa/Startup.cs +++ b/templates/Angular2Spa/Startup.cs @@ -1,42 +1,57 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.SpaServices.Webpack; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Serialization; namespace WebApplicationBasic { public class Startup { + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddEnvironmentVariables(); + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc().AddJsonOptions(options => - { - options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - }); + // Add framework services. + services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env) + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { - app.UseDeveloperExceptionPage(); + loggerFactory.AddConsole(Configuration.GetSection("Logging")); + loggerFactory.AddDebug(); - if (env.IsDevelopment()) { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { HotModuleReplacement = true }); } + else + { + app.UseExceptionHandler("/Home/Error"); + } app.UseStaticFiles(); - loggerFactory.AddConsole(); + app.UseMvc(routes => { routes.MapRoute( @@ -48,17 +63,5 @@ namespace WebApplicationBasic defaults: new { controller = "Home", action = "Index" }); }); } - - public static void Main(string[] args) - { - var host = new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseKestrel() - .UseStartup() - .Build(); - - host.Run(); - } } } diff --git a/templates/Angular2Spa/appsettings.json b/templates/Angular2Spa/appsettings.json index e5472e5..723c096 100755 --- a/templates/Angular2Spa/appsettings.json +++ b/templates/Angular2Spa/appsettings.json @@ -2,7 +2,7 @@ "Logging": { "IncludeScopes": false, "LogLevel": { - "Default": "Verbose", + "Default": "Debug", "System": "Information", "Microsoft": "Information" } diff --git a/templates/Angular2Spa/package.json b/templates/Angular2Spa/package.json index 047a6ea..3797004 100644 --- a/templates/Angular2Spa/package.json +++ b/templates/Angular2Spa/package.json @@ -2,6 +2,7 @@ "name": "WebApplicationBasic", "version": "0.0.0", "devDependencies": { + "aspnet-webpack": "^1.0.6", "bootstrap": "^3.3.6", "css-loader": "^0.23.1", "expose-loader": "^0.7.1", @@ -18,18 +19,18 @@ "webpack-hot-middleware": "^2.10.0" }, "dependencies": { - "@angular/common": "2.0.0-rc.3", - "@angular/compiler": "2.0.0-rc.3", - "@angular/core": "2.0.0-rc.3", - "@angular/http": "2.0.0-rc.3", - "@angular/platform-browser": "2.0.0-rc.3", - "@angular/platform-browser-dynamic": "2.0.0-rc.3", - "@angular/platform-server": "2.0.0-rc.3", - "@angular/router": "3.0.0-alpha.8", - "angular2-universal": "^0.104.1", + "@angular/common": "2.0.0-rc.4", + "@angular/compiler": "2.0.0-rc.4", + "@angular/core": "2.0.0-rc.4", + "@angular/http": "2.0.0-rc.4", + "@angular/platform-browser": "2.0.0-rc.4", + "@angular/platform-browser-dynamic": "2.0.0-rc.4", + "@angular/platform-server": "2.0.0-rc.4", + "@angular/router": "3.0.0-beta.2", + "angular2-universal": "^0.104.5", "aspnet-prerendering": "^1.0.2", - "aspnet-webpack": "^1.0.1", "css": "^2.2.1", + "es6-shim": "^0.35.1", "isomorphic-fetch": "^2.2.1", "preboot": "^2.0.10", "rxjs": "5.0.0-beta.6", diff --git a/templates/Angular2Spa/project.json b/templates/Angular2Spa/project.json index 1ce5f41..845fe68 100755 --- a/templates/Angular2Spa/project.json +++ b/templates/Angular2Spa/project.json @@ -4,7 +4,6 @@ "version": "1.0.0", "type": "platform" }, - "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", "Microsoft.AspNetCore.AngularServices": "1.0.0-*", "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.0", @@ -17,46 +16,16 @@ "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.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "type": "build" - }, - "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { - "version": "1.0.0-preview2-final", - "type": "build" - } + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0" }, "tools": { - "Microsoft.AspNetCore.Razor.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.AspNetCore.Server.IISIntegration.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.EntityFrameworkCore.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, - "Microsoft.Extensions.SecretManager.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, + "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", "Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final" }, @@ -64,14 +33,12 @@ "netcoreapp1.0": { "imports": [ "dotnet5.6", - "dnxcore50", "portable-net45+win8" ] } }, "buildOptions": { - "debugType": "portable", "emitEntryPoint": true, "preserveCompilationContext": true }, diff --git a/templates/Angular2Spa/webpack.config.vendor.js b/templates/Angular2Spa/webpack.config.vendor.js index 0fc256a..cd2bbe0 100644 --- a/templates/Angular2Spa/webpack.config.vendor.js +++ b/templates/Angular2Spa/webpack.config.vendor.js @@ -18,6 +18,7 @@ module.exports = { vendor: [ 'bootstrap', 'bootstrap/dist/css/bootstrap.css', + 'es6-shim', 'style-loader', 'jquery', '@angular/common', diff --git a/templates/KnockoutSpa/Dockerfile b/templates/KnockoutSpa/Dockerfile index 63d7c45..b828f96 100644 --- a/templates/KnockoutSpa/Dockerfile +++ b/templates/KnockoutSpa/Dockerfile @@ -1,11 +1,16 @@ -FROM microsoft/aspnet:1.0.0-rc1-update1 +FROM microsoft/dotnet:latest -RUN printf "deb http://ftp.us.debian.org/debian jessie main\n" >> /etc/apt/sources.list -RUN apt-get -qq update && apt-get install -qqy sqlite3 libsqlite3-dev && rm -rf /var/lib/apt/lists/* +RUN apt-get update +RUN apt-get install -y build-essential nodejs nodejs-legacy + +WORKDIR /app + +COPY project.json . +RUN ["dotnet", "restore"] COPY . /app -WORKDIR /app -RUN ["dnu", "restore"] +RUN ["dotnet", "build"] EXPOSE 5000/tcp -ENTRYPOINT ["dnx", "-p", "project.json", "web"] + +ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"] diff --git a/templates/KnockoutSpa/Program.cs b/templates/KnockoutSpa/Program.cs new file mode 100644 index 0000000..b2e5e4b --- /dev/null +++ b/templates/KnockoutSpa/Program.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; + +namespace WebApplicationBasic +{ + public class Program + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder() + .AddCommandLine(args) + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .Build(); + + var host = new WebHostBuilder() + .UseConfiguration(config) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/templates/KnockoutSpa/Startup.cs b/templates/KnockoutSpa/Startup.cs index 0c5cc48..e5d73ed 100755 --- a/templates/KnockoutSpa/Startup.cs +++ b/templates/KnockoutSpa/Startup.cs @@ -1,42 +1,57 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.SpaServices.Webpack; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Serialization; namespace WebApplicationBasic { public class Startup { + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddEnvironmentVariables(); + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc().AddJsonOptions(options => - { - options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - }); + // Add framework services. + services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env) + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { - app.UseDeveloperExceptionPage(); + loggerFactory.AddConsole(Configuration.GetSection("Logging")); + loggerFactory.AddDebug(); - if (env.IsDevelopment()) { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { HotModuleReplacement = true }); } + else + { + app.UseExceptionHandler("/Home/Error"); + } app.UseStaticFiles(); - loggerFactory.AddConsole(); + app.UseMvc(routes => { routes.MapRoute( @@ -48,17 +63,5 @@ namespace WebApplicationBasic defaults: new { controller = "Home", action = "Index" }); }); } - - public static void Main(string[] args) - { - var host = new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseKestrel() - .UseStartup() - .Build(); - - host.Run(); - } } } diff --git a/templates/KnockoutSpa/appsettings.json b/templates/KnockoutSpa/appsettings.json index e5472e5..723c096 100755 --- a/templates/KnockoutSpa/appsettings.json +++ b/templates/KnockoutSpa/appsettings.json @@ -2,7 +2,7 @@ "Logging": { "IncludeScopes": false, "LogLevel": { - "Default": "Verbose", + "Default": "Debug", "System": "Information", "Microsoft": "Information" } diff --git a/templates/KnockoutSpa/package.json b/templates/KnockoutSpa/package.json index c00f895..9de9738 100644 --- a/templates/KnockoutSpa/package.json +++ b/templates/KnockoutSpa/package.json @@ -2,7 +2,7 @@ "name": "WebApplicationBasic", "version": "0.0.0", "devDependencies": { - "aspnet-webpack": "^1.0.0", + "aspnet-webpack": "^1.0.6", "bootstrap": "^3.3.6", "bundle-loader": "^0.5.4", "crossroads": "^0.12.2", diff --git a/templates/KnockoutSpa/project.json b/templates/KnockoutSpa/project.json index 66ff147..d3e2777 100755 --- a/templates/KnockoutSpa/project.json +++ b/templates/KnockoutSpa/project.json @@ -4,7 +4,6 @@ "version": "1.0.0", "type": "platform" }, - "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", "Microsoft.AspNetCore.SpaServices": "1.0.0-*", "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.0", @@ -17,46 +16,16 @@ "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.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "type": "build" - }, - "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { - "version": "1.0.0-preview2-final", - "type": "build" - } + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0" }, "tools": { - "Microsoft.AspNetCore.Razor.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.AspNetCore.Server.IISIntegration.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.EntityFrameworkCore.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, - "Microsoft.Extensions.SecretManager.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, + "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", "Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final" }, @@ -64,14 +33,12 @@ "netcoreapp1.0": { "imports": [ "dotnet5.6", - "dnxcore50", "portable-net45+win8" ] } }, "buildOptions": { - "debugType": "portable", "emitEntryPoint": true, "preserveCompilationContext": true }, diff --git a/templates/ReactReduxSpa/Dockerfile b/templates/ReactReduxSpa/Dockerfile index 63d7c45..b828f96 100644 --- a/templates/ReactReduxSpa/Dockerfile +++ b/templates/ReactReduxSpa/Dockerfile @@ -1,11 +1,16 @@ -FROM microsoft/aspnet:1.0.0-rc1-update1 +FROM microsoft/dotnet:latest -RUN printf "deb http://ftp.us.debian.org/debian jessie main\n" >> /etc/apt/sources.list -RUN apt-get -qq update && apt-get install -qqy sqlite3 libsqlite3-dev && rm -rf /var/lib/apt/lists/* +RUN apt-get update +RUN apt-get install -y build-essential nodejs nodejs-legacy + +WORKDIR /app + +COPY project.json . +RUN ["dotnet", "restore"] COPY . /app -WORKDIR /app -RUN ["dnu", "restore"] +RUN ["dotnet", "build"] EXPOSE 5000/tcp -ENTRYPOINT ["dnx", "-p", "project.json", "web"] + +ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"] diff --git a/templates/ReactReduxSpa/Program.cs b/templates/ReactReduxSpa/Program.cs new file mode 100644 index 0000000..b2e5e4b --- /dev/null +++ b/templates/ReactReduxSpa/Program.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; + +namespace WebApplicationBasic +{ + public class Program + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder() + .AddCommandLine(args) + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .Build(); + + var host = new WebHostBuilder() + .UseConfiguration(config) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/templates/ReactReduxSpa/Startup.cs b/templates/ReactReduxSpa/Startup.cs index 6f4babb..750d79c 100755 --- a/templates/ReactReduxSpa/Startup.cs +++ b/templates/ReactReduxSpa/Startup.cs @@ -1,43 +1,58 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.SpaServices.Webpack; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Serialization; namespace WebApplicationBasic { public class Startup { + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddEnvironmentVariables(); + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc().AddJsonOptions(options => - { - options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - }); + // Add framework services. + services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env) + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { - app.UseDeveloperExceptionPage(); + loggerFactory.AddConsole(Configuration.GetSection("Logging")); + loggerFactory.AddDebug(); - if (env.IsDevelopment()) { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { HotModuleReplacement = true, ReactHotModuleReplacement = true }); } + else + { + app.UseExceptionHandler("/Home/Error"); + } app.UseStaticFiles(); - loggerFactory.AddConsole(); + app.UseMvc(routes => { routes.MapRoute( @@ -49,17 +64,5 @@ namespace WebApplicationBasic defaults: new { controller = "Home", action = "Index" }); }); } - - public static void Main(string[] args) - { - var host = new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseKestrel() - .UseStartup() - .Build(); - - host.Run(); - } } } diff --git a/templates/ReactReduxSpa/appsettings.json b/templates/ReactReduxSpa/appsettings.json index e5472e5..723c096 100755 --- a/templates/ReactReduxSpa/appsettings.json +++ b/templates/ReactReduxSpa/appsettings.json @@ -2,7 +2,7 @@ "Logging": { "IncludeScopes": false, "LogLevel": { - "Default": "Verbose", + "Default": "Debug", "System": "Information", "Microsoft": "Information" } diff --git a/templates/ReactReduxSpa/package.json b/templates/ReactReduxSpa/package.json index 4070c8a..a1d53df 100644 --- a/templates/ReactReduxSpa/package.json +++ b/templates/ReactReduxSpa/package.json @@ -2,6 +2,7 @@ "name": "WebApplicationBasic", "version": "0.0.0", "devDependencies": { + "aspnet-webpack": "^1.0.6", "aspnet-webpack-react": "^1.0.1", "babel-loader": "^6.2.3", "babel-preset-es2015": "^6.5.0", @@ -21,7 +22,6 @@ }, "dependencies": { "aspnet-prerendering": "^1.0.2", - "aspnet-webpack": "^1.0.2", "babel-core": "^6.5.2", "domain-task": "^2.0.0", "react": "^15.0.1", diff --git a/templates/ReactReduxSpa/project.json b/templates/ReactReduxSpa/project.json index f768eca..0794a38 100755 --- a/templates/ReactReduxSpa/project.json +++ b/templates/ReactReduxSpa/project.json @@ -4,7 +4,6 @@ "version": "1.0.0", "type": "platform" }, - "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", "Microsoft.AspNetCore.ReactServices": "1.0.0-*", "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.0", @@ -17,46 +16,16 @@ "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.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "type": "build" - }, - "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { - "version": "1.0.0-preview2-final", - "type": "build" - } + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0" }, "tools": { - "Microsoft.AspNetCore.Razor.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.AspNetCore.Server.IISIntegration.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.EntityFrameworkCore.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, - "Microsoft.Extensions.SecretManager.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, + "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", "Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final" }, @@ -64,14 +33,12 @@ "netcoreapp1.0": { "imports": [ "dotnet5.6", - "dnxcore50", "portable-net45+win8" ] } }, "buildOptions": { - "debugType": "portable", "emitEntryPoint": true, "preserveCompilationContext": true }, diff --git a/templates/ReactSpa/Dockerfile b/templates/ReactSpa/Dockerfile index 63d7c45..b828f96 100644 --- a/templates/ReactSpa/Dockerfile +++ b/templates/ReactSpa/Dockerfile @@ -1,11 +1,16 @@ -FROM microsoft/aspnet:1.0.0-rc1-update1 +FROM microsoft/dotnet:latest -RUN printf "deb http://ftp.us.debian.org/debian jessie main\n" >> /etc/apt/sources.list -RUN apt-get -qq update && apt-get install -qqy sqlite3 libsqlite3-dev && rm -rf /var/lib/apt/lists/* +RUN apt-get update +RUN apt-get install -y build-essential nodejs nodejs-legacy + +WORKDIR /app + +COPY project.json . +RUN ["dotnet", "restore"] COPY . /app -WORKDIR /app -RUN ["dnu", "restore"] +RUN ["dotnet", "build"] EXPOSE 5000/tcp -ENTRYPOINT ["dnx", "-p", "project.json", "web"] + +ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"] diff --git a/templates/ReactSpa/Program.cs b/templates/ReactSpa/Program.cs new file mode 100644 index 0000000..b2e5e4b --- /dev/null +++ b/templates/ReactSpa/Program.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; + +namespace WebApplicationBasic +{ + public class Program + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder() + .AddCommandLine(args) + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .Build(); + + var host = new WebHostBuilder() + .UseConfiguration(config) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/templates/ReactSpa/Startup.cs b/templates/ReactSpa/Startup.cs index 6f4babb..750d79c 100755 --- a/templates/ReactSpa/Startup.cs +++ b/templates/ReactSpa/Startup.cs @@ -1,43 +1,58 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.SpaServices.Webpack; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Serialization; namespace WebApplicationBasic { public class Startup { + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddEnvironmentVariables(); + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc().AddJsonOptions(options => - { - options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - }); + // Add framework services. + services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env) + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { - app.UseDeveloperExceptionPage(); + loggerFactory.AddConsole(Configuration.GetSection("Logging")); + loggerFactory.AddDebug(); - if (env.IsDevelopment()) { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { HotModuleReplacement = true, ReactHotModuleReplacement = true }); } + else + { + app.UseExceptionHandler("/Home/Error"); + } app.UseStaticFiles(); - loggerFactory.AddConsole(); + app.UseMvc(routes => { routes.MapRoute( @@ -49,17 +64,5 @@ namespace WebApplicationBasic defaults: new { controller = "Home", action = "Index" }); }); } - - public static void Main(string[] args) - { - var host = new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseKestrel() - .UseStartup() - .Build(); - - host.Run(); - } } } diff --git a/templates/ReactSpa/appsettings.json b/templates/ReactSpa/appsettings.json index e5472e5..723c096 100755 --- a/templates/ReactSpa/appsettings.json +++ b/templates/ReactSpa/appsettings.json @@ -2,7 +2,7 @@ "Logging": { "IncludeScopes": false, "LogLevel": { - "Default": "Verbose", + "Default": "Debug", "System": "Information", "Microsoft": "Information" } diff --git a/templates/ReactSpa/package.json b/templates/ReactSpa/package.json index 2b6d0b0..9776cdb 100644 --- a/templates/ReactSpa/package.json +++ b/templates/ReactSpa/package.json @@ -2,7 +2,7 @@ "name": "WebApplicationBasic", "version": "0.0.0", "devDependencies": { - "aspnet-webpack": "^1.0.2", + "aspnet-webpack": "^1.0.6", "aspnet-webpack-react": "^1.0.0", "babel-loader": "^6.2.3", "babel-preset-es2015": "^6.5.0", diff --git a/templates/ReactSpa/project.json b/templates/ReactSpa/project.json index f768eca..0794a38 100755 --- a/templates/ReactSpa/project.json +++ b/templates/ReactSpa/project.json @@ -4,7 +4,6 @@ "version": "1.0.0", "type": "platform" }, - "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", "Microsoft.AspNetCore.ReactServices": "1.0.0-*", "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.0", @@ -17,46 +16,16 @@ "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.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "type": "build" - }, - "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { - "version": "1.0.0-preview2-final", - "type": "build" - } + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0" }, "tools": { - "Microsoft.AspNetCore.Razor.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.AspNetCore.Server.IISIntegration.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.EntityFrameworkCore.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, - "Microsoft.Extensions.SecretManager.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, + "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", "Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final" }, @@ -64,14 +33,12 @@ "netcoreapp1.0": { "imports": [ "dotnet5.6", - "dnxcore50", "portable-net45+win8" ] } }, "buildOptions": { - "debugType": "portable", "emitEntryPoint": true, "preserveCompilationContext": true }, diff --git a/templates/WebApplicationBasic/Dockerfile b/templates/WebApplicationBasic/Dockerfile index 63d7c45..134c714 100644 --- a/templates/WebApplicationBasic/Dockerfile +++ b/templates/WebApplicationBasic/Dockerfile @@ -1,11 +1,13 @@ -FROM microsoft/aspnet:1.0.0-rc1-update1 +FROM microsoft/dotnet:latest -RUN printf "deb http://ftp.us.debian.org/debian jessie main\n" >> /etc/apt/sources.list -RUN apt-get -qq update && apt-get install -qqy sqlite3 libsqlite3-dev && rm -rf /var/lib/apt/lists/* +WORKDIR /app + +COPY project.json . +RUN ["dotnet", "restore"] COPY . /app -WORKDIR /app -RUN ["dnu", "restore"] +RUN ["dotnet", "build"] EXPOSE 5000/tcp -ENTRYPOINT ["dnx", "-p", "project.json", "web"] + +ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"] diff --git a/templates/WebApplicationBasic/Program.cs b/templates/WebApplicationBasic/Program.cs new file mode 100644 index 0000000..b2e5e4b --- /dev/null +++ b/templates/WebApplicationBasic/Program.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; + +namespace WebApplicationBasic +{ + public class Program + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder() + .AddCommandLine(args) + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .Build(); + + var host = new WebHostBuilder() + .UseConfiguration(config) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/templates/WebApplicationBasic/Startup.cs b/templates/WebApplicationBasic/Startup.cs index 4ddc86c..fe5473d 100755 --- a/templates/WebApplicationBasic/Startup.cs +++ b/templates/WebApplicationBasic/Startup.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -13,19 +12,42 @@ namespace WebApplicationBasic { public class Startup { + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddEnvironmentVariables(); + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + // Add framework services. services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env) + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { - app.UseDeveloperExceptionPage(); + loggerFactory.AddConsole(Configuration.GetSection("Logging")); + loggerFactory.AddDebug(); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Home/Error"); + } app.UseStaticFiles(); - loggerFactory.AddConsole(); + app.UseMvc(routes => { routes.MapRoute( @@ -33,17 +55,5 @@ namespace WebApplicationBasic template: "{controller=Home}/{action=Index}/{id?}"); }); } - - public static void Main(string[] args) - { - var host = new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseKestrel() - .UseStartup() - .Build(); - - host.Run(); - } } } diff --git a/templates/WebApplicationBasic/appsettings.json b/templates/WebApplicationBasic/appsettings.json index e5472e5..723c096 100755 --- a/templates/WebApplicationBasic/appsettings.json +++ b/templates/WebApplicationBasic/appsettings.json @@ -2,7 +2,7 @@ "Logging": { "IncludeScopes": false, "LogLevel": { - "Default": "Verbose", + "Default": "Debug", "System": "Information", "Microsoft": "Information" } diff --git a/templates/WebApplicationBasic/project.json b/templates/WebApplicationBasic/project.json index a28b4b3..4464a43 100755 --- a/templates/WebApplicationBasic/project.json +++ b/templates/WebApplicationBasic/project.json @@ -4,7 +4,6 @@ "version": "1.0.0", "type": "platform" }, - "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Razor.Tools": { @@ -16,60 +15,28 @@ "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.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "type": "build" - }, - "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { - "version": "1.0.0-preview2-final", - "type": "build" - } + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0" }, "tools": { - "Microsoft.AspNetCore.Razor.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.AspNetCore.Server.IISIntegration.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.EntityFrameworkCore.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - }, - "Microsoft.Extensions.SecretManager.Tools": { - "version": "1.0.0-preview2-final", - "imports": "portable-net45+win8+dnxcore50" - }, - "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { - "version": "1.0.0-preview2-final", - "imports": [ - "portable-net45+win8+dnxcore50", - "portable-net45+win8" - ] - } + "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final" }, "frameworks": { "netcoreapp1.0": { "imports": [ "dotnet5.6", - "dnxcore50", "portable-net45+win8" ] } }, "buildOptions": { - "debugType": "portable", "emitEntryPoint": true, "preserveCompilationContext": true }, diff --git a/templates/yeoman/src/generator/package.json b/templates/yeoman/src/generator/package.json index ad60454..839ed75 100644 --- a/templates/yeoman/src/generator/package.json +++ b/templates/yeoman/src/generator/package.json @@ -1,6 +1,6 @@ { "name": "generator-aspnetcore-spa", - "version": "0.2.2", + "version": "0.2.3", "description": "Single-Page App templates for ASP.NET Core", "author": "Microsoft", "license": "Apache-2.0",