Example #1
0
        public static void UseVueDevelopmentServer(this ISpaBuilder spa)
        {
            spa.UseProxyToSpaDevelopmentServer(async() => {
                var loggerFactory = spa.ApplicationBuilder.ApplicationServices.GetService <ILoggerFactory> ();
                var logger        = loggerFactory.CreateLogger("Vue");

                if (IsRunning())
                {
                    return(DevelopmentServerEndpoint);
                }
                var isWindows   = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                var processInfo = new ProcessStartInfo {
                    FileName               = isWindows ? "cmd" : "npm",
                    Arguments              = $"{(isWindows ? "/c npm " : "")}run serve",
                    WorkingDirectory       = "client-app",
                    RedirectStandardError  = true,
                    RedirectStandardInput  = true,
                    RedirectStandardOutput = true,
                    UseShellExecute        = false,
                };
                var process = Process.Start(processInfo);
                var tcs     = new TaskCompletionSource <int> ();
                _           = Task.Run(() => {
                    try {
                        string line;
                        while ((line = process.StandardOutput.ReadLine()) != null)
                        {
                            logger.LogInformation(line);
                            if (!tcs.Task.IsCompleted && line.Contains(DoneMessage))
                            {
                                tcs.SetResult(1);
                            }
                        }
                    } catch (EndOfStreamException ex) {
                        logger.LogError(ex.ToString());
                        tcs.SetException(new InvalidOperationException("'npm run serve' failed.", ex));
                    }
                });
                _ = Task.Run(() => {
                    try {
                        string line;
                        while ((line = process.StandardError.ReadLine()) != null)
                        {
                            logger.LogError(line);
                        }
                    } catch (EndOfStreamException ex) {
                        logger.LogError(ex.ToString());
                        tcs.SetException(new InvalidOperationException("'npm run serve' failed.", ex));
                    }
                });

                var timeout = Task.Delay(Timeout);
                if (await Task.WhenAny(timeout, tcs.Task) == timeout)
                {
                    throw new TimeoutException();
                }

                return(DevelopmentServerEndpoint);
            });
        }
Example #2
0
        public static void Attach(
            ISpaBuilder spaBuilder,
            string npmScriptName,
            string compiledSuccessfullyString)
        {
            var sourcePath = spaBuilder.Options.SourcePath;

            if (string.IsNullOrEmpty(sourcePath))
            {
                throw new ArgumentNullException(nameof(sourcePath));
            }
            if (string.IsNullOrEmpty(npmScriptName))
            {
                throw new ArgumentNullException(nameof(npmScriptName));
            }
            CompiledSuccessfullyString = compiledSuccessfullyString;
            var logger        = LoggerFinder.GetOrCreateLogger(spaBuilder.ApplicationBuilder, LogCategoryName);
            var targetUriTask = StartCreateVueAppServerAsync(sourcePath, npmScriptName, logger)
                                .ContinueWith(task => new UriBuilder("http", "127.0.0.1", task.Result).Uri);

            spaBuilder.UseProxyToSpaDevelopmentServer(() =>
            {
                var startupTimeout = spaBuilder.Options.StartupTimeout;
                return(targetUriTask.WithTimeout(startupTimeout,
                                                 $"在 {startupTimeout.Seconds} 秒钟的超时时间内,Vue服务器未开始侦听请求。 检查日志输出以获取错误信息"));
            });
        }
Example #3
0
 public static void UseVueDevelopmentServer(this ISpaBuilder spa, string scriptName)
 {
     spa.UseProxyToSpaDevelopmentServer(async() =>
     {
         var nodeRunner = new NodeProccessRunner(scriptName);
         return(await nodeRunner.LaunchProccess());
     });
 }
Example #4
0
 public static void UseVueDevelopmentServer(this ISpaBuilder spa)
 {
     spa.UseProxyToSpaDevelopmentServer(async() =>
     {
         if (IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Select(x => x.Port).Contains(DEV_PORT))
         {
             return(new Uri($"http://localhost:{DEV_PORT}"));
         }
         throw new InvalidOperationException($"Please serve the port {DEV_PORT}");
     });
 }
            TimeSpan.FromSeconds(5);     // This is a development-time only feature, so a very long timeout is fine

        public static void Attach(
            ISpaBuilder spaBuilder,
            string npmScriptName)
        {
            var sourcePath = spaBuilder.Options.SourcePath;

            if (string.IsNullOrEmpty(sourcePath))
            {
                throw new ArgumentException("Cannot be null or empty", nameof(sourcePath));
            }

            if (string.IsNullOrEmpty(npmScriptName))
            {
                throw new ArgumentException("Cannot be null or empty", nameof(npmScriptName));
            }

            // Start create-react-app and attach to middleware pipeline
            var appBuilder = spaBuilder.ApplicationBuilder;
            var logger     = LoggerFinder.GetOrCreateLogger(appBuilder, LogCategoryName);
            var portTask   = StartCreateVueAppServerAsync(sourcePath, npmScriptName, logger);

            // Everything we proxy is hardcoded to target http://localhost because:
            // - the requests are always from the local machine (we're not accepting remote
            //   requests that go directly to the create-react-app server)
            // - given that, there's no reason to use https, and we couldn't even if we
            //   wanted to, because in general the create-react-app server has no certificate
            var targetUriTask = portTask.ContinueWith(
                task => new UriBuilder("http", "localhost", task.Result).Uri
                );

            spaBuilder.UseProxyToSpaDevelopmentServer(
                () =>
            {
                // On each request, we create a separate startup task with its own timeout. That way, even if
                // the first request times out, subsequent requests could still work.
                var timeout = spaBuilder.Options.StartupTimeout;

                return(targetUriTask.WithTimeout(
                           timeout,
                           "The Vue development server did not start listening for requests " +
                           $"within the timeout period of {timeout.Seconds} seconds. " +
                           "Check the log output for error information."
                           ));
            }
                );
        }
Example #6
0
        public static ISpaBuilder CheckAndStartAngular(this ISpaBuilder spa, string url = "http://localhost:4200/")
        {
            try
            {
                using (HttpClient client = new HttpClient())
                {
                    var response = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result;
                    spa.UseProxyToSpaDevelopmentServer(url);
                }
            }
            catch (Exception)
            {
                spa.UseAngularCliServer(npmScript: "start");
            }

            return(spa);
        }
Example #7
0
        public static void Attach(ISpaBuilder spaBuilder)
        {
            string sourcePath = spaBuilder.Options.SourcePath;

            if (string.IsNullOrEmpty(sourcePath))
            {
                throw new ArgumentException("Cannot be null or empty", "sourcePath");
            }
            ILogger logger =
                spaBuilder.ApplicationBuilder.ApplicationServices.GetService <ILogger <AngularCliServerInfo> >();
            Task <Uri> targetUriTask = AngularCliMiddleware.StartAngularCliServerAsync(sourcePath, logger).ContinueWith <Uri>((Func <Task <AngularCliMiddleware.AngularCliServerInfo>, Uri>)(task => new UriBuilder("http", "localhost", task.Result.Port).Uri));

            spaBuilder.UseProxyToSpaDevelopmentServer((Func <Task <Uri> >)(() =>
            {
                TimeSpan startupTimeout = spaBuilder.Options.StartupTimeout;
                return(targetUriTask.WithTimeout <Uri>(startupTimeout, "The Angular CLI process did not start listening for requests " + string.Format("within the timeout period of {0} seconds. ", (object)startupTimeout.Seconds) + "Check the log output for error information."));
            }));
        }
        private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(5); // This is a development-time only feature, so a very long timeout is fine


        public static void Attach(ISpaBuilder spaBuilder, string scriptName)
        {
            var pkgManagerCommand = spaBuilder.Options.PackageManagerCommand;
            var sourcePath        = spaBuilder.Options.SourcePath;
            var devServerPort     = spaBuilder.Options.DevServerPort;

            if (string.IsNullOrEmpty(sourcePath))
            {
                throw new ArgumentException("Cannot be null or empty", nameof(sourcePath));
            }

            if (string.IsNullOrEmpty(scriptName))
            {
                throw new ArgumentException("Cannot be null or empty", nameof(scriptName));
            }

            // Start vue-cli-service serve and attach to middleware pipeline
            var appBuilder = spaBuilder.ApplicationBuilder;
            var applicationStoppingToken = appBuilder.ApplicationServices.GetRequiredService <IHostApplicationLifetime>().ApplicationStopping;
            var logger           = LoggerFinder.GetOrCreateLogger(appBuilder, LOG_CATEGORY_NAME);
            var diagnosticSource = appBuilder.ApplicationServices.GetRequiredService <DiagnosticSource>();
            var portTask         = StartCreateVueAppServerAsync(sourcePath, scriptName, pkgManagerCommand, devServerPort, logger, diagnosticSource, applicationStoppingToken);

            // Everything we proxy is hardcoded to target http://localhost because:
            // - the requests are always from the local machine (we're not accepting remote
            //   requests that go directly to the vue-cli-service server)
            // - given that, there's no reason to use https, and we couldn't even if we
            //   wanted to, because in general the vue-cli-service server has no certificate
            var targetUriTask = portTask.ContinueWith(
                task => new UriBuilder("http", "localhost", task.Result).Uri);

            spaBuilder.UseProxyToSpaDevelopmentServer(() =>
            {
                // On each request, we create a separate startup task with its own timeout. That way, even if
                // the first request times out, subsequent requests could still work.
                var timeout = spaBuilder.Options.StartupTimeout;
                return(targetUriTask.WithTimeout(timeout,
                                                 $"The vue-cli server did not start listening for requests " +
                                                 $"within the timeout period of {timeout.Seconds} seconds. " +
                                                 $"Check the log output for error information."));
            });
        }
        /// <summary>
        /// Handles requests by passing them through to an instance of the node dev server.
        /// This means you don't need to start node dev server manually.
        ///
        /// </summary>
        /// <param name="spaBuilder">The <see cref="ApplicationBuilder"/>.</param>
        /// <param name="command">The command or file name to start dev server.</param>
        /// <param name="arguments">Arguments to start dev server.</param>
        /// <param name="workingDirectory">WorkingDirectory for node dev  server</param>
        /// <param name="envVars">Environment variables for node dev  server</param>
        /// <param name="timeout">Timeout for node process waiting</param>
        /// <param name="timeoutExceedMessage">Message when timeout is exceeded</param>
        /// <param name="logInformation">Log node process output</param>
        /// <param name="logError">Log node js process error</param>
        /// <param name="unsubscribeWhenReady">Stop logging when nodejs process is ready</param>
        public static void UseAspSpaDevelopmentServer(
            this ISpaBuilder spaBuilder,
            string command,
            string arguments,
            string workingDirectory,
            Dictionary<string,string> envVars,
            TimeSpan timeout,
            string timeoutExceedMessage = "Timeout has been exceeded ",
            bool logInformation = true,
            bool logError = false,
            bool unsubscribeWhenReady = true)
        {
            if (spaBuilder == null)
            {
                throw new ArgumentNullException(nameof(spaBuilder));
            }
            var logger = GetOrCreateLogger(spaBuilder.ApplicationBuilder, LogCategoryName);
            NodeRunner runner = GetNodeRunner(spaBuilder.ApplicationBuilder);
            if (runner == null)
            {
                runner = new NodeRunner();
            }
            runner.Command = command;
            runner.Arguments = arguments;
            runner.WorkingDirectory = workingDirectory;
            runner.EnvVars = envVars;
            runner.Timeout = timeout;
            runner.TimeoutExceedMessage = timeoutExceedMessage;
            runner.Launch(logger);
            if (runner.Uri != null)
            {
                if (unsubscribeWhenReady)
                {
                    runner.UnsubscribeLog(logger);
                }
                spaBuilder.UseProxyToSpaDevelopmentServer(runner.Uri);
            }
            else
            {

            }
       }
Example #10
0
        public static void UseVueDevelopmentServer(this ISpaBuilder spaBuilder)
        {
            spaBuilder.UseProxyToSpaDevelopmentServer(async() =>
            {
                if (IsRunning())
                {
                    return(DevelopmentServerEndpoint);
                }

                _ = getRunnedTaskOutput(getProcess(), getLogger(spaBuilder), taskCompletionSource);

                _ = getRunnedTaskError(getProcess(), getLogger(spaBuilder), taskCompletionSource);

                if (await Task.WhenAny(Task.Delay(Timeout), taskCompletionSource.Task) == Task.Delay(Timeout))
                {
                    throw new TimeoutException();
                }

                return(DevelopmentServerEndpoint);
            });
        }
Example #11
0
        public static void UseVueDevelopmentServer(this ISpaBuilder spa, string url)
        {
            URI = new Uri(url);

            spa.UseProxyToSpaDevelopmentServer(async() =>
            {
                var loggerFactory = spa.ApplicationBuilder.ApplicationServices.GetService <ILoggerFactory>();
                var logger        = loggerFactory.CreateLogger("Vue");

                // if 'npm run serve' command was executed yourself, then just return the endpoint.
                if (IsRunning())
                {
                    return(URI);
                }

                // launch vue.js development server
                var isWindows   = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                var processInfo = new ProcessStartInfo
                {
                    FileName               = isWindows ? "cmd" : "npm",
                    Arguments              = $"{(isWindows ? "/c npm " : "")} run serve",
                    WorkingDirectory       = "Resources",
                    RedirectStandardError  = true,
                    RedirectStandardInput  = true,
                    RedirectStandardOutput = true,
                    UseShellExecute        = false,
                };
                var process = Process.Start(processInfo);
                var tcs     = new TaskCompletionSource <int>();

                _ = Task.Run(() =>
                {
                    try
                    {
                        string line;

                        while ((line = process.StandardOutput.ReadLine()) != null)
                        {
                            logger.LogInformation(line);

                            if (!tcs.Task.IsCompleted && line.Contains("DONE Compiled successfully in"))
                            {
                                tcs.SetResult(1);
                            }
                        }
                    }
                    catch (EndOfStreamException ex)
                    {
                        logger.LogError(ex.ToString());
                        tcs.SetException(new InvalidOperationException("'npm run serve' failed.", ex));
                    }
                });

                _ = Task.Run(() =>
                {
                    try
                    {
                        string line;

                        while ((line = process.StandardError.ReadLine()) != null)
                        {
                            logger.LogError(line);
                        }
                    }
                    catch (EndOfStreamException ex)
                    {
                        logger.LogError(ex.ToString());
                        tcs.SetException(new InvalidOperationException("'npm run' failed.", ex));
                    }
                });

                await Task.Delay(10);

                return(URI);
            });
        }
Example #12
0
        /// <summary>
        /// Adds Connection to Vite Hosted VueApplication
        /// configured per <seealso cref="SpaOptions"/> on the <paramref name="spa"/>.
        /// NOTE: (this will create devcert.pfx and vite.config.js in your Vue Application on first run)
        /// </summary>
        /// <param name="spa"></param>
        public static void UseViteDevelopmentServer(this ISpaBuilder spa)
        {
            // Default HostingPort
            if (spa.Options.DevServerPort == 0)
            {
                spa.Options.DevServerPort = 3000;
            }

            var devServerEndpoint  = new Uri($"https://localhost:{spa.Options.DevServerPort}");
            var loggerFactory      = spa.ApplicationBuilder.ApplicationServices.GetService <ILoggerFactory>();
            var webHostEnvironment = spa.ApplicationBuilder.ApplicationServices.GetService <IWebHostEnvironment>();
            var logger             = loggerFactory.CreateLogger("Vue");

            // Is this already running
            bool IsRunning = IPGlobalProperties.GetIPGlobalProperties()
                             .GetActiveTcpListeners()
                             .Select(x => x.Port)
                             .Contains(spa.Options.DevServerPort);

            if (!IsRunning)
            {
                var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

                // export dev cert
                var tempDir    = webHostEnvironment.ContentRootPath;
                var tempPfx    = Path.Combine(tempDir, spa.Options.SourcePath, "devcert.pfx");
                var tempConfig = Path.Combine(tempDir, spa.Options.SourcePath, "vite.config.js");

                if (!File.Exists(tempPfx) || !File.Exists(tempConfig))
                {
                    var pfxPassword = Guid.NewGuid().ToString("N");
                    logger.LogInformation($"Exporting dotnet dev cert to {tempPfx} for Vite");
                    logger.LogDebug($"Export password: {pfxPassword}");
                    var certExport = new ProcessStartInfo
                    {
                        FileName               = isWindows ? "cmd" : "dotnet",
                        Arguments              = $"{(isWindows ? "/c dotnet " : "")}dev-certs https -v -ep {tempPfx} -p {pfxPassword}",
                        RedirectStandardError  = true,
                        RedirectStandardInput  = true,
                        RedirectStandardOutput = true,
                        UseShellExecute        = false,
                    };
                    var exportProcess = Process.Start(certExport);
                    exportProcess.WaitForExit();
                    if (exportProcess.ExitCode == 0)
                    {
                        logger.LogInformation(exportProcess.StandardOutput.ReadToEnd());
                    }
                    else
                    {
                        logger.LogError(exportProcess.StandardError.ReadToEnd());
                    }

                    // create config
                    File.WriteAllText(tempConfig, $"export default {{\r\nhttps:true,\r\nhttpsOptions: {{\r\npfx: '{Path.GetFileName(tempPfx)}',\r\npassphrase: '{pfxPassword}'\r\n}}\r\n}}");
                    logger.LogInformation($"Creating Vite config: {tempConfig}");
                }

                // launch vue.js development server
                var processInfo = new ProcessStartInfo
                {
                    FileName               = isWindows ? "cmd" : "npm",
                    Arguments              = $"{(isWindows ? "/c npm " : "")}run dev",
                    WorkingDirectory       = spa.Options.SourcePath,
                    RedirectStandardError  = true,
                    RedirectStandardInput  = true,
                    RedirectStandardOutput = true,
                    UseShellExecute        = false,
                };
                var process = Process.Start(processInfo);
                var tcs     = new TaskCompletionSource <int>();
                _ = Task.Run(() =>
                {
                    try
                    {
                        string line;
                        while ((line = process.StandardOutput.ReadLine()?.Trim()) != null)
                        {
                            if (!String.IsNullOrEmpty(line))
                            {
                                logger.LogInformation(line);
                                if (!tcs.Task.IsCompleted && line.Contains(DoneMessage))
                                {
                                    tcs.SetResult(1);
                                }
                            }
                        }
                    }
                    catch (EndOfStreamException ex)
                    {
                        logger.LogError(ex.ToString());
                        tcs.SetException(new InvalidOperationException("'npm run dev' failed.", ex));
                    }
                });
                _ = Task.Run(() =>
                {
                    try
                    {
                        string line;
                        while ((line = process.StandardError.ReadLine()?.Trim()) != null)
                        {
                            logger.LogError(line);
                        }
                    }
                    catch (EndOfStreamException ex)
                    {
                        logger.LogError(ex.ToString());
                        tcs.SetException(new InvalidOperationException("'npm run dev' failed.", ex));
                    }
                });

                if (!tcs.Task.Wait(spa.Options.StartupTimeout))
                {
                    throw new TimeoutException();
                }
            }
            spa.UseProxyToSpaDevelopmentServer(devServerEndpoint);
        }