这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions MLS.Agent.Tests/AgentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using MLS.Agent.CommandLine;
Expand Down Expand Up @@ -41,7 +43,14 @@ public AgentService(StartupOptions options = null, IDirectoryAccessor directoryA

public void Dispose() => _disposables.Dispose();

private TestServer CreateTestServer() => new TestServer(CreateWebHostBuilder());
private TestServer CreateTestServer()
{
//We need to set the feature collection to be not null,
//so that the ServerFeatures(like the urls to use) can be configured and used
var featureCollection = new FeatureCollection();
featureCollection.Set<IServerAddressesFeature>(new ServerAddressesFeature());
return new TestServer(CreateWebHostBuilder(), featureCollection);
}

private IWebHostBuilder CreateWebHostBuilder()
{
Expand All @@ -60,7 +69,8 @@ private IWebHostBuilder CreateWebHostBuilder()
});
})
.UseTestEnvironment()
.UseStartup<Startup>();
.UseStartup<Startup>()
.ConfigureUrlUsingPort(_options.Port);

return builder;
}
Expand Down
16 changes: 16 additions & 0 deletions MLS.Agent.Tests/CommandLine/CommandLineParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,22 @@ public async Task AiKey_defaults_to_null()
_start_options.ApplicationInsightsKey.Should().BeNull();
}

[Fact]
public async Task Parses_the_port()
{
await _parser.InvokeAsync("--port 6000", _console);
_start_options.Port.Should().Be(6000);
}

[Fact]
public void Negative_port_fails_the_parse()
{
_parser.Parse("--port -8090")
.Errors
.Should()
.Contain(e => e.Message == "Invalid argument for --port option");
}

[Fact]
public void Parse_application_insights_key_without_parameter_fails_the_parse()
{
Expand Down
47 changes: 47 additions & 0 deletions MLS.Agent.Tests/WebHostBuilderExtensionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using FluentAssertions;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using Xunit;
namespace MLS.Agent.Tests
{
public class WebHostBuilderExtensionTests
{
[Fact]
public void If_launched_for_development_4242_is_used()
{
var uri = WebHostBuilderExtensions.GetBrowserLaunchUri(true, null);
uri.ToString().Should().Be("http://localhost:4242/");
}

[Fact]
public void If_not_launched_for_development_and_port_is_specified_it_is_used()
{
var uri = WebHostBuilderExtensions.GetBrowserLaunchUri(false, 6000);
uri.ToString().Should().Be("https://localhost:6000/");
}

[Fact]
public void If_not_launched_for_development_and_port_is_not_specified_a_free_port_is_returned()
{
var uri = WebHostBuilderExtensions.GetBrowserLaunchUri(false, null);
uri.AbsoluteUri.Should().Match("https://localhost:*/");
CheckIfPortIsAvailable(uri.Port).Should().BeTrue();
}

private static bool CheckIfPortIsAvailable(int port)
{
// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form. We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

return tcpConnInfoArray.FirstOrDefault(tcpi => tcpi.LocalEndPoint.Port == port) == null;
}
}
}
36 changes: 28 additions & 8 deletions MLS.Agent/CommandLine/CommandLineParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.CommandLine.Builder;
using System.CommandLine.Invocation;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Clockwise;
using Microsoft.AspNetCore.Hosting;
Expand Down Expand Up @@ -53,7 +54,7 @@ public delegate Task<int> Jupyter(
IConsole console,
StartServer startServer = null,
InvocationContext context = null);

public static Parser Create(
StartServer startServer = null,
Demo demo = null,
Expand Down Expand Up @@ -91,8 +92,8 @@ public static Parser Create(
pack = pack ??
PackCommand.Do;

install = install??
InstallCommand.Do;
install = install ??
InstallCommand.Do;
services = services ??
new ServiceCollection();

Expand Down Expand Up @@ -181,6 +182,25 @@ RootCommand StartInTryMode()
"Enable verbose logging to the console",
new Argument<bool>()));

var portArgument = new Argument<ushort>();

portArgument.AddValidator(symbolResult =>{

if(symbolResult.Tokens
.Select(t => t.Value)
.Where(value => !ushort.TryParse(value, out ushort result)).Count() >0)
{
return "Invalid argument for --port option";
}

return null;
});

command.AddOption(new Option(
"--port",
"Specify the port for dotnet try to listen on",
portArgument));

command.Handler = CommandHandler.Create<InvocationContext, StartupOptions>((context, options) =>
{
services.AddSingleton(_ => PackageRegistry.CreateForTryMode(
Expand Down Expand Up @@ -245,7 +265,7 @@ Command StartInHostedMode()
Command Demo()
{
var demoCommand = new Command(
"demo",
"demo",
"Learn how to create Try .NET content with an interactive demo")
{
new Option("--output", "Where should the demo project be written to?")
Expand Down Expand Up @@ -278,15 +298,15 @@ Command GitHub()

return github;
}

Command Jupyter()
{
var jupyterCommand = new Command("jupyter", "Starts dotnet try as a Jupyter kernel");
jupyterCommand.IsHidden = true;
var connectionFileArgument = new Argument<FileInfo>
{
Name = "ConnectionFile"
}.ExistingOnly();
{
Name = "ConnectionFile"
}.ExistingOnly();
jupyterCommand.Argument = connectionFileArgument;

jupyterCommand.Handler = CommandHandler.Create<JupyterOptions, IConsole, InvocationContext>((options, console, context) =>
Expand Down
5 changes: 4 additions & 1 deletion MLS.Agent/CommandLine/StartupOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public StartupOptions(
bool enablePreviewFeatures = false,
string package = null,
string packageVersion = null,
ParseResult parseResult = null)
ParseResult parseResult = null,
ushort? port = null)
{
_parseResult = parseResult;
LogPath = logPath;
Expand All @@ -59,6 +60,7 @@ public StartupOptions(
EnablePreviewFeatures = enablePreviewFeatures;
Package = package;
PackageVersion = packageVersion;
Port = port;
}

public bool EnablePreviewFeatures { get; }
Expand Down Expand Up @@ -98,5 +100,6 @@ public StartupMode Mode
public string Package { get; }

public string PackageVersion { get; }
public ushort? Port { get; }
}
}
2 changes: 2 additions & 0 deletions MLS.Agent/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public static IWebHost ConstructWebHost(StartupOptions options)
Log.Trace("Received Key: {key}", options.Key);
}


var webHost = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
Expand All @@ -139,6 +140,7 @@ public static IWebHost ConstructWebHost(StartupOptions options)
})
.UseEnvironment(options.EnvironmentName)
.UseStartup<Startup>()
.ConfigureUrlUsingPort(options.Port)
.Build();

return webHost;
Expand Down
13 changes: 4 additions & 9 deletions MLS.Agent/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Clockwise;
using Microsoft.AspNetCore.Blazor.Server;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.DotNet.Try.Markdown;
Expand Down Expand Up @@ -182,8 +183,9 @@ public void Configure(

if (StartupOptions.Mode == StartupMode.Try)
{
var uri = new Uri(app.ServerFeatures.Get<IServerAddressesFeature>().Addresses.First());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can there be more than one?

Copy link
Contributor Author

@akshita31 akshita31 Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are setting up in the Program.cs to use a single url, there will be only one here - https://github.com/dotnet/try/pull/246/files#diff-adcfc4b0634e7250308be781cbe69f63R146

Clock.Current
.Schedule(_ => LaunchBrowser(browserLauncher,directoryAccessor), TimeSpan.FromSeconds(1));
.Schedule(_ => LaunchBrowser(browserLauncher,directoryAccessor, uri), TimeSpan.FromSeconds(1));
}
}
}
Expand All @@ -204,15 +206,8 @@ private static void ConfigureForOrchestratorProxy(IApplicationBuilder app)
});
}

private void LaunchBrowser(IBrowserLauncher browserLauncher, IDirectoryAccessor directoryAccessor)
private void LaunchBrowser(IBrowserLauncher browserLauncher, IDirectoryAccessor directoryAccessor, Uri uri)
{
var processName = Process.GetCurrentProcess().ProcessName;

var uri = processName == "dotnet" ||
processName == "dotnet.exe"
? new Uri("http://localhost:4242")
: new Uri("http://localhost:5000");

if (StartupOptions.Uri != null &&
!StartupOptions.Uri.IsAbsoluteUri)
{
Expand Down
51 changes: 51 additions & 0 deletions MLS.Agent/WebHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Net;
using System.Net.Sockets;
using Microsoft.AspNetCore.Hosting;
using MLS.Agent.CommandLine;

namespace MLS.Agent
{
public static class WebHostBuilderExtensions
{
public static IWebHostBuilder ConfigureUrlUsingPort(this IWebHostBuilder builder, int? port)
{
var uri = GetBrowserLaunchUri(IsLaunchedForDevelopment(), port);
return builder.UseUrls(uri.ToString());
}

public static Uri GetBrowserLaunchUri(bool isLaunchedForDevelopment, int? port)
{
if (isLaunchedForDevelopment)
{
return new Uri("http://localhost:4242");
}
else if (port.HasValue)
{
return new Uri($"https://localhost:{port}");
}
else
{
return new Uri($"https://localhost:{GetFreePort()}");
}
}

private static bool IsLaunchedForDevelopment()
{
var processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
return processName == "dotnet" || processName == "dotnet.exe";
}

private static int GetFreePort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
}
}