mirror of
https://github.com/aspnet/JavaScriptServices.git
synced 2025-12-24 10:40:23 +00:00
Design review: Change AddNodeServices to take an Action<NodeServicesOptions> like other aspects of MVC DI config
This commit is contained in:
@@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.NodeServices.HostingModels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.NodeServices
|
||||
{
|
||||
public static class Configuration
|
||||
{
|
||||
const string LogCategoryName = "Microsoft.AspNetCore.NodeServices";
|
||||
|
||||
public static void AddNodeServices(this IServiceCollection serviceCollection)
|
||||
=> AddNodeServices(serviceCollection, new NodeServicesOptions());
|
||||
|
||||
public static void AddNodeServices(this IServiceCollection serviceCollection, NodeServicesOptions options)
|
||||
{
|
||||
serviceCollection.AddSingleton(
|
||||
typeof(INodeServices),
|
||||
serviceProvider => CreateNodeServices(serviceProvider, options));
|
||||
}
|
||||
|
||||
public static INodeServices CreateNodeServices(IServiceProvider serviceProvider, NodeServicesOptions options)
|
||||
{
|
||||
return new NodeServicesImpl(() => CreateNodeInstance(serviceProvider, options));
|
||||
}
|
||||
|
||||
private static INodeInstance CreateNodeInstance(IServiceProvider serviceProvider, 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
|
||||
{
|
||||
// Otherwise we'll construct the type of INodeInstance specified by the HostingModel property
|
||||
// (which itself has a useful default value), plus obtain config information from the DI system.
|
||||
var projectPath = options.ProjectPath;
|
||||
var envVars = options.EnvironmentVariables == null
|
||||
? new Dictionary<string, string>()
|
||||
: new Dictionary<string, string>(options.EnvironmentVariables);
|
||||
|
||||
var hostEnv = serviceProvider.GetService<IHostingEnvironment>();
|
||||
if (hostEnv != null)
|
||||
{
|
||||
// In an ASP.NET environment, we can use the IHostingEnvironment data to auto-populate a few
|
||||
// things that you'd otherwise have to specify manually
|
||||
if (string.IsNullOrEmpty(projectPath))
|
||||
{
|
||||
projectPath = hostEnv.ContentRootPath;
|
||||
}
|
||||
|
||||
// Similarly, we can determine the 'is development' value from the hosting environment
|
||||
if (!envVars.ContainsKey("NODE_ENV"))
|
||||
{
|
||||
// These strings are a de-facto standard in Node
|
||||
envVars["NODE_ENV"] = hostEnv.IsDevelopment() ? "development" : "production";
|
||||
}
|
||||
}
|
||||
|
||||
// If no logger was specified explicitly, we should use the one from DI.
|
||||
// If it doesn't provide one, we'll set up a default one.
|
||||
var logger = options.NodeInstanceOutputLogger;
|
||||
if (logger == null)
|
||||
{
|
||||
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
|
||||
logger = loggerFactory != null
|
||||
? loggerFactory.CreateLogger(LogCategoryName)
|
||||
: new ConsoleLogger(LogCategoryName, null, false);
|
||||
}
|
||||
|
||||
switch (options.HostingModel)
|
||||
{
|
||||
case NodeHostingModel.Http:
|
||||
return new HttpNodeInstance(projectPath, options.WatchFileExtensions, logger,
|
||||
envVars, options.LaunchWithDebugging, options.DebuggingPort, /* port */ 0);
|
||||
case NodeHostingModel.Socket:
|
||||
var pipeName = "pni-" + Guid.NewGuid().ToString("D"); // Arbitrary non-clashing string
|
||||
return new SocketNodeInstance(projectPath, options.WatchFileExtensions, pipeName, logger,
|
||||
envVars, options.LaunchWithDebugging, options.DebuggingPort);
|
||||
default:
|
||||
throw new ArgumentException("Unknown hosting model: " + options.HostingModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.NodeServices.HostingModels;
|
||||
|
||||
namespace Microsoft.AspNetCore.NodeServices
|
||||
{
|
||||
public static class NodeServicesFactory
|
||||
{
|
||||
public static INodeServices CreateNodeServices(NodeServicesOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof (options));
|
||||
}
|
||||
|
||||
return new NodeServicesImpl(() => CreateNodeInstance(options));
|
||||
}
|
||||
|
||||
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.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.LaunchWithDebugging, options.DebuggingPort);
|
||||
default:
|
||||
throw new ArgumentException("Unknown hosting model: " + options.HostingModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,21 +2,45 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.NodeServices.HostingModels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
|
||||
namespace Microsoft.AspNetCore.NodeServices
|
||||
{
|
||||
public class NodeServicesOptions
|
||||
{
|
||||
public const NodeHostingModel DefaultNodeHostingModel = NodeHostingModel.Http;
|
||||
|
||||
private const string LogCategoryName = "Microsoft.AspNetCore.NodeServices";
|
||||
private static readonly string[] DefaultWatchFileExtensions = { ".js", ".jsx", ".ts", ".tsx", ".json", ".html" };
|
||||
|
||||
public NodeServicesOptions()
|
||||
public NodeServicesOptions(IServiceProvider serviceProvider)
|
||||
{
|
||||
if (serviceProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof (serviceProvider));
|
||||
}
|
||||
|
||||
EnvironmentVariables = new Dictionary<string, string>();
|
||||
HostingModel = DefaultNodeHostingModel;
|
||||
WatchFileExtensions = (string[])DefaultWatchFileExtensions.Clone();
|
||||
|
||||
// In an ASP.NET environment, we can use the IHostingEnvironment data to auto-populate a few
|
||||
// things that you'd otherwise have to specify manually
|
||||
var hostEnv = serviceProvider.GetService<IHostingEnvironment>();
|
||||
if (hostEnv != null)
|
||||
{
|
||||
ProjectPath = hostEnv.ContentRootPath;
|
||||
EnvironmentVariables["NODE_ENV"] = hostEnv.IsDevelopment() ? "development" : "production"; // De-facto standard values for Node
|
||||
}
|
||||
|
||||
// If the DI system gives us a logger, use it. Otherwise, set up a default one.
|
||||
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
|
||||
NodeInstanceOutputLogger = loggerFactory != null
|
||||
? loggerFactory.CreateLogger(LogCategoryName)
|
||||
: new ConsoleLogger(LogCategoryName, null, false);
|
||||
}
|
||||
public Action<System.Diagnostics.ProcessStartInfo> OnBeforeStartExternalProcess { get; set; }
|
||||
|
||||
public NodeHostingModel HostingModel { get; set; }
|
||||
public Func<INodeInstance> NodeInstanceFactory { get; set; }
|
||||
public string ProjectPath { get; set; }
|
||||
@@ -24,6 +48,6 @@ namespace Microsoft.AspNetCore.NodeServices
|
||||
public ILogger NodeInstanceOutputLogger { get; set; }
|
||||
public bool LaunchWithDebugging { get; set; }
|
||||
public IDictionary<string, string> EnvironmentVariables { get; set; }
|
||||
public int? DebuggingPort { get; set; }
|
||||
public int DebuggingPort { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.NodeServices;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for setting up NodeServices in an <see cref="IServiceCollection" />.
|
||||
/// </summary>
|
||||
public static class NodeServicesServiceCollectionExtensions
|
||||
{
|
||||
public static void AddNodeServices(this IServiceCollection serviceCollection)
|
||||
=> AddNodeServices(serviceCollection, _ => {});
|
||||
|
||||
[Obsolete("Use the AddNodeServices(Action<NodeServicesOptions> setupAction) overload instead.")]
|
||||
public static void AddNodeServices(this IServiceCollection serviceCollection, NodeServicesOptions options)
|
||||
{
|
||||
serviceCollection.AddSingleton(typeof (INodeServices), _ =>
|
||||
{
|
||||
return NodeServicesFactory.CreateNodeServices(options);
|
||||
});
|
||||
}
|
||||
|
||||
public static void AddNodeServices(this IServiceCollection serviceCollection, Action<NodeServicesOptions> setupAction)
|
||||
{
|
||||
if (setupAction == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof (setupAction));
|
||||
}
|
||||
|
||||
serviceCollection.AddSingleton(typeof(INodeServices), serviceProvider =>
|
||||
{
|
||||
// First we let NodeServicesOptions take its defaults from the IServiceProvider,
|
||||
// then we let the developer override those options
|
||||
var options = new NodeServicesOptions(serviceProvider);
|
||||
setupAction(options);
|
||||
|
||||
return NodeServicesFactory.CreateNodeServices(options);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user